diff -Nru libindi-1.0.0/ChangeLog libindi-1.1.0/ChangeLog --- libindi-1.0.0/ChangeLog 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/ChangeLog 2015-09-06 13:17:35.000000000 +0000 @@ -1,3 +1,29 @@ +From 1.0.0 to 1.1.0 + + + INDI::Weather for support of weather devices. + + INDI::GPS for support of GPS devices. + + WunderGround weather driver. + + Meade DSI I & II support. + + FocusLynx focuser support. + + PerfectStar focuser support. + + World Coordinate System (WCS) support in generated FITS. + + Updated Losmany driver. + + New Celestron driver. + + New IEQPro driver. + + Support for custom parking in dome drivers. + + Support Open Loop dome controllers. + + Various QHY CCD & Filter Wheel fixes and QHY OSX support. + + SBIG External Guide CCD fixes. + + Custom parking support for Celestron/Astrophysics/AstroElectronics/IEQPro + + Updated ASI ZWO drivers. + + Updated Apogee library. Improved NET support in INDI Apogee driver. + + Standarizing mount slew and track rates. + + Video4Linux 2 fixes and improvements: (16bpp pixel formats(Y16 and BYR2), pwc flashled, colorSpace/linearization, stacking), Simutaneous record/stream/exp. Stream rate divisor. Rec. file patterns. + + EQMod fixes: Keep tracking after joystick motion is stopped. Park initialization always set encoders. + + Improved support for drivers on ARM architecture. + + Improved logging capability. + + Deprecated: LX200Legacy and indimain library. + From 0.9.9 to 1.0.0 + 3rdparty: Support for QHY CCDs and CFWs (BETA). @@ -217,4 +243,4 @@ + INDI scripting tools + Various bug fixing -INDI Library v1.0 conforms to INDI wire protocol v1.6 +INDI Library v1.1 conforms to INDI wire protocol v1.7 diff -Nru libindi-1.0.0/CMakeLists.txt libindi-1.1.0/CMakeLists.txt --- libindi-1.0.0/CMakeLists.txt 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/CMakeLists.txt 2015-09-06 13:17:35.000000000 +0000 @@ -8,7 +8,7 @@ ################## INDI version ################################ set(INDI_SOVERSION "1") set(CMAKE_INDI_VERSION_MAJOR 1) -set(CMAKE_INDI_VERSION_MINOR 0) +set(CMAKE_INDI_VERSION_MINOR 1) set(CMAKE_INDI_VERSION_RELEASE 0) set(CMAKE_INDI_VERSION_STRING "${CMAKE_INDI_VERSION_MAJOR}.${CMAKE_INDI_VERSION_MINOR}.${CMAKE_INDI_VERSION_RELEASE}") @@ -40,6 +40,7 @@ FIND_LIBRARY(M_LIB m) FIND_PACKAGE(ZLIB REQUIRED) FIND_PACKAGE(USB-1 REQUIRED) +find_package(CURL REQUIRED) FIND_PACKAGE(CFITSIO REQUIRED) FIND_PACKAGE(Nova REQUIRED) FIND_PACKAGE(Threads REQUIRED) @@ -88,9 +89,8 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(libwebcam_SRCS - ${CMAKE_SOURCE_DIR}/libs/webcam/PPort.cpp - ${CMAKE_SOURCE_DIR}/libs/webcam/port.cpp ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_base.cpp + ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_colorspace.c ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_c2.c ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_misc.c ${CMAKE_SOURCE_DIR}/libs/webcam/jpegutils.c @@ -101,8 +101,6 @@ ) endif() - - set (indimain_SRCS ${CMAKE_SOURCE_DIR}/indidriver.c ${CMAKE_SOURCE_DIR}/indidrivermain.c @@ -129,6 +127,8 @@ ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterinterface.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indidomeinterface.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indidome.cpp + ${CMAKE_SOURCE_DIR}/libs/indibase/indigps.cpp + ${CMAKE_SOURCE_DIR}/libs/indibase/indiweather.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indilogger.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indicontroller.cpp ) @@ -137,6 +137,14 @@ ${CMAKE_SOURCE_DIR}/libs/lx/Lx.cpp ) +IF (APPLE) +set(hidapi_SRCS ${CMAKE_SOURCE_DIR}/libs/indibase/hid_mac.c) +ELSEIF (WIN32) +set(hidapi_SRCS ${CMAKE_SOURCE_DIR}/libs/indibase/hid_win.c) +ELSE () +set(hidapi_SRCS ${CMAKE_SOURCE_DIR}/libs/indibase/hid_libusb.c) +ENDIF() + ###################################### ########### INDI SERVER ############## ###################################### @@ -159,28 +167,17 @@ install(TARGETS indi LIBRARY DESTINATION ${LIB_DESTINATION}) set_target_properties(indi PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION}) -################################################### -############ INDI Main Shared Library ############# -# To link with main() for 3rd party legacy drivers# -################################################### -add_library(indimain SHARED ${indimain_SRCS} ${libindicom_SRCS} ${liblilxml_SRCS}) - -target_link_libraries(indimain ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES}) - -install(TARGETS indimain LIBRARY DESTINATION ${LIB_DESTINATION}) -set_target_properties(indimain PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION}) - ################################################## ########## INDI Default Driver Library ########### # To link with main() and indibase classes ###### ################################################## if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") -add_library(indidriver SHARED ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS} ${libwebcam_SRCS}) +add_library(indidriver SHARED ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS} ${libwebcam_SRCS} ${hidapi_SRCS}) target_link_libraries(indidriver ${LIBUSB_1_LIBRARIES} ${NOVA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CFITSIO_LIBRARIES} ${M_LIB} ${ZLIB_LIBRARY} ${JPEG_LIBRARY}) add_library(indidriverstatic STATIC ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS} ${libwebcam_SRCS}) target_link_libraries(indidriverstatic ${LIBUSB_1_LIBRARIES} ${NOVA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CFITSIO_LIBRARIES} ${M_LIB} ${ZLIB_LIBRARY} ${JPEG_LIBRARY}) else() -add_library(indidriver SHARED ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS}) +add_library(indidriver SHARED ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS} ${hidapi_SRCS}) target_link_libraries(indidriver ${LIBUSB_1_LIBRARIES} ${NOVA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CFITSIO_LIBRARIES} ${M_LIB} ${ZLIB_LIBRARY}) add_library(indidriverstatic STATIC ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS}) target_link_libraries(indidriverstatic ${LIBUSB_1_LIBRARIES} ${NOVA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CFITSIO_LIBRARIES} ${M_LIB} ${ZLIB_LIBRARY}) @@ -233,12 +230,12 @@ ########### LX200 Basic ############# set(lx200basic_SRCS ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c + ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200basic.cpp ) add_executable(indi_lx200basic ${lx200basic_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) -target_link_libraries(indi_lx200basic ${NOVA_LIBRARIES} ${NOVA_LIBRARIES}) +target_link_libraries(indi_lx200basic indidriver) install(TARGETS indi_lx200basic RUNTIME DESTINATION bin ) @@ -246,14 +243,17 @@ ########### LX200 Generic ########### set(lx200generic_SRCS - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c + ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200autostar.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200_16.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200gps.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200generic.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200classic.cpp - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200apdriver.c + ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200apdriver.cpp + ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200gemini.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200ap.cpp + ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200fs2.cpp + ) add_executable(indi_lx200generic ${lx200generic_SRCS}) @@ -268,31 +268,15 @@ exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200_16)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200gps)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200ap)\n +exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200gemini)\n +exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200fs2)\n ") set_target_properties(indi_lx200generic PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_lx200generic_symlink.cmake) ################################################################################# -########### LX200 Generic Legacy ########### -set(lx200genericlegacy_SRCS - ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200genericlegacy.cpp - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200fs2.cpp) - -add_executable(indi_lx200genericlegacy ${lx200genericlegacy_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) - -target_link_libraries(indi_lx200genericlegacy ${NOVA_LIBRARIES} ${M_LIB} ) - -install(TARGETS indi_lx200genericlegacy RUNTIME DESTINATION bin ) - -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_lx200genericlegacy_symlink.cmake -"exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200genericlegacy \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200fs2)\n") -set_target_properties(indi_lx200genericlegacy PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_lx200genericlegacy_symlink.cmake) -################################################################################# - ########### Celestron GPS ############ set(celestrongps_SRCS - ${CMAKE_SOURCE_DIR}/drivers/telescope/celestronprotocol.c + ${CMAKE_SOURCE_DIR}/drivers/telescope/celestrondriver.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/celestrongps.cpp ) add_executable(indi_celestron_gps ${celestrongps_SRCS}) @@ -318,7 +302,6 @@ ########### Sky Commander ############# set(skycommander_SRCS ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/skycommander.c ) add_executable(indi_skycommander ${skycommander_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) @@ -332,7 +315,6 @@ ########### Intelliscope ############### set(intelliscope_SRCS ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/intelliscope.c ) add_executable(indi_intelliscope ${intelliscope_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) @@ -362,30 +344,17 @@ install(TARGETS indi_magellan1 RUNTIME DESTINATION bin ) -########### IEQ45 ############# -###Handheld 8406 version -set(ieq45_8406_SRCS - ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45driver8406.c - ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45.cpp ) - -add_executable(indi_ieq45_8406 ${ieq45_8406_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) - -target_link_libraries(indi_ieq45_8406 ${NOVA_LIBRARIES}) - -install(TARGETS indi_ieq45_8406 RUNTIME DESTINATION bin ) - -###Handheld 8407 version -set(ieq45_8407_SRCS +########### IEQ Pro / CEM60 ############# +set(ieq_SRCS ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45driver8407.c - ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45.cpp ) + ${CMAKE_SOURCE_DIR}/drivers/telescope/ieqprodriver.cpp + ${CMAKE_SOURCE_DIR}/drivers/telescope/ieqpro.cpp ) -add_executable(indi_ieq45_8407 ${ieq45_8407_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) +add_executable(indi_ieq_telescope ${ieq_SRCS}) -target_link_libraries(indi_ieq45_8407 ${NOVA_LIBRARIES}) +target_link_libraries(indi_ieq_telescope indidriver) -install(TARGETS indi_ieq45_8407 RUNTIME DESTINATION bin ) +install(TARGETS indi_ieq_telescope RUNTIME DESTINATION bin ) ########### Telescope Simulator ############## set(telescopesimulator_SRCS @@ -468,6 +437,28 @@ target_link_libraries(indi_steeldrive_focus indidriver) install(TARGETS indi_steeldrive_focus RUNTIME DESTINATION bin ) +################ FocusLynx Focuser ################ + +set(focuslynx_SRCS + ${CMAKE_SOURCE_DIR}/drivers/focuser/focuslynx.cpp + ) + +add_executable(indi_lynx_focus ${focuslynx_SRCS}) +target_link_libraries(indi_lynx_focus indidriver) +install(TARGETS indi_lynx_focus RUNTIME DESTINATION bin ) + +################ PerfectStar Focuser ################ + +set(perfectstar_SRCS + ${CMAKE_SOURCE_DIR}/drivers/focuser/perfectstar.cpp + ) + +add_executable(indi_perfectstar_focus ${perfectstar_SRCS}) +target_link_libraries(indi_perfectstar_focus indidriver) +install(TARGETS indi_perfectstar_focus RUNTIME DESTINATION bin ) +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +install(FILES ${CMAKE_SOURCE_DIR}/drivers/focuser/99-perfectstar.rules DESTINATION ${UDEVRULES_INSTALL_DIR}) +endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ################ Optec TCF-S ################ @@ -560,69 +551,10 @@ ################################################################################# -### Meade Lunar Planetary Imager ######## -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") -if (CFITSIO_FOUND) - -ADD_DEFINITIONS(-DHAVE_LINUX_VIDEODEV2_H) - -set(meade_lpi_SRCS - ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp - ${CMAKE_SOURCE_DIR}/drivers/video/indi_lpi.cpp - ) - -add_executable(indi_meade_lpi ${meade_lpi_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) - -target_link_libraries(indi_meade_lpi z ${JPEG_LIBRARY} ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - -install(TARGETS indi_meade_lpi RUNTIME DESTINATION bin ) - -endif (CFITSIO_FOUND) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - -################################################################################# - -########### V4L Philips ############## +########### INDI::CCD V4L Driver ############### if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (CFITSIO_FOUND) -set(v4lphilips_SRCS - ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp - ${CMAKE_SOURCE_DIR}/drivers/video/v4lphilips.cpp - ${CMAKE_SOURCE_DIR}/drivers/video/indi_philips.cpp -) - -add_executable(indi_v4l_philips ${v4lphilips_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) - -target_link_libraries(indi_v4l_philips ${JPEG_LIBRARY} ${M_LIB} ${ZLIB_LIBRARY} ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - -install(TARGETS indi_v4l_philips RUNTIME DESTINATION bin ) - -endif (CFITSIO_FOUND) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - -################################################################################# - -########### Old Generic V4L Driver ############### -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") -if (CFITSIO_FOUND) - -set(v4ldriver_SRCS - ${indimain_SRCS} - ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp - ${CMAKE_SOURCE_DIR}/drivers/video/indi_v4l.cpp - ) - -add_executable(indi_v4l_legacy ${v4ldriver_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) - -target_link_libraries(indi_v4l_legacy ${JPEG_LIBRARY} ${M_LIB} ${ZLIB_LIBRARY} ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - -install(TARGETS indi_v4l_legacy RUNTIME DESTINATION bin ) - -########### New INDI::CCD V4L Driver ############### - set(v4l2driverccd_SRCS ${lx_SRCS} ${CMAKE_SOURCE_DIR}/drivers/video/v4l2driver.cpp @@ -688,6 +620,38 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +########### GPS Simulator Driver ############### + +set(gpssimulator_SRCS + ${CMAKE_SOURCE_DIR}/drivers/auxiliary/gps_simulator.cpp + ) + +add_executable(indi_simulator_gps ${gpssimulator_SRCS}) + +target_link_libraries(indi_simulator_gps indidriver) +install(TARGETS indi_simulator_gps RUNTIME DESTINATION bin ) + +##################################### +############ AUX GROUP ############## +##################################### + +########### WunderGround Driver ############### + +set(WunderGround_SRCS + ${CMAKE_SOURCE_DIR}/drivers/weather/gason.cpp + ${CMAKE_SOURCE_DIR}/drivers/weather/wunderground.cpp + ) + +add_executable(indi_wunderground_weather ${WunderGround_SRCS}) + +target_link_libraries(indi_wunderground_weather indidriver ${CURL_LIBRARIES}) +install(TARGETS indi_wunderground_weather RUNTIME DESTINATION bin ) + +##################################### +############ INDI TOOLS ############# +##################################### + + ########### getINDI ############## set(getindi_SRCS ${CMAKE_SOURCE_DIR}/eventloop.c @@ -739,15 +703,19 @@ install( FILES drivers.xml ${CMAKE_SOURCE_DIR}/drivers/focuser/indi_tcfs_sk.xml DESTINATION ${DATA_INSTALL_DIR}) install( FILES indiapi.h indidevapi.h base64.h eventloop.h indidriver.h ${CMAKE_SOURCE_DIR}/libs/lilxml.h ${CMAKE_SOURCE_DIR}/libs/indibase/indibase.h -${CMAKE_SOURCE_DIR}/libs/indibase/basedevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/defaultdevice.h +${CMAKE_SOURCE_DIR}/libs/indibase/indibasetypes.h ${CMAKE_SOURCE_DIR}/libs/indibase/basedevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/defaultdevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiccd.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterwheel.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifocuserinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifocuser.h ${CMAKE_SOURCE_DIR}/libs/indibase/inditelescope.h ${CMAKE_SOURCE_DIR}/libs/indibase/baseclient.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiguiderinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiproperty.h -${CMAKE_SOURCE_DIR}/libs/indibase/indidomeinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indidome.h -${CMAKE_SOURCE_DIR}/libs/indicom.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiusbdevice.h -${CMAKE_SOURCE_DIR}/libs/indibase/indilogger.h ${CMAKE_SOURCE_DIR}/libs/indibase/indicontroller.h +${CMAKE_SOURCE_DIR}/libs/indibase/indidomeinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indidome.h ${CMAKE_SOURCE_DIR}/libs/indibase/indigps.h +${CMAKE_SOURCE_DIR}/libs/indibase/indiweather.h ${CMAKE_SOURCE_DIR}/libs/indicom.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiusbdevice.h +${CMAKE_SOURCE_DIR}/libs/indibase/indilogger.h ${CMAKE_SOURCE_DIR}/libs/indibase/indicontroller.h ${CMAKE_SOURCE_DIR}/libs/indibase/hidapi.h ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt.h ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_types.h +${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_record/v4l2_record.h ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_record/ser_recorder.h +${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_decode/v4l2_decode.h ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_decode/v4l2_builtin_decoder.h +${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_types.h ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_colorspace.h +${CMAKE_SOURCE_DIR}/libs/webcam/jpegutils.h DESTINATION ${INCLUDE_INSTALL_DIR}/libindi COMPONENT Devel) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libindi.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libindi.pc @ONLY) diff -Nru libindi-1.0.0/cmake_modules/FindASI.cmake libindi-1.1.0/cmake_modules/FindASI.cmake --- libindi-1.0.0/cmake_modules/FindASI.cmake 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/cmake_modules/FindASI.cmake 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,50 @@ +# - 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(ASI_LIBRARIES NAMES ASICamera2 + PATHS + ${_obLinkDir} + ${GNUWIN32_DIR}/lib + ) + + 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 -Nru libindi-1.0.0/cmake_modules/FindFISHCAMP.cmake libindi-1.1.0/cmake_modules/FindFISHCAMP.cmake --- libindi-1.0.0/cmake_modules/FindFISHCAMP.cmake 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/cmake_modules/FindFISHCAMP.cmake 2015-09-06 13:17:35.000000000 +0000 @@ -19,14 +19,14 @@ else (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR) - find_library(FISHCAMP_LIBRARIES NAMES fishcamp + find_library(FISHCAMP_LIBRARIES NAMES fishcamp PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) find_path(FISHCAMP_INCLUDE_DIR fishcamp.h - PATH_SUFFIXES fishcamp + PATH_SUFFIXES libfishcamp ${_obIncDir} ${GNUWIN32_DIR}/include ) diff -Nru libindi-1.0.0/cmake_modules/FindINDI.cmake libindi-1.1.0/cmake_modules/FindINDI.cmake --- libindi-1.0.0/cmake_modules/FindINDI.cmake 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/cmake_modules/FindINDI.cmake 2015-09-06 13:17:35.000000000 +0000 @@ -4,26 +4,25 @@ # INDI_FOUND - system has INDI # INDI_INCLUDE_DIR - the INDI include directory # INDI_LIBRARIES - Link these to use INDI -# INDI_MAIN_LIBRARIES - Link to these to build INDI drivers with main() # INDI_DRIVER_LIBRARIES - Link to these to build INDI drivers with indibase support # INDI_CLIENT_LIBRARIES - Link to these to build INDI clients # INDI_DATA_DIR - INDI shared data dir. -# Copyright (c) 2011, Jasem Mutlaq +# Copyright (c) 2015, Jasem Mutlaq # Copyright (c) 2012, Pino Toscano # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. -if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES AND INDI_CLIENT_LIBRARIES) +if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_CLIENT_LIBRARIES) # in cache already set(INDI_FOUND TRUE) message(STATUS "Found INDI: ${INDI_LIBRARIES}") -else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES AND INDI_CLIENT_LIBRARIES) +else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_CLIENT_LIBRARIES) find_package(PkgConfig) @@ -50,11 +49,7 @@ find_library(INDI_DRIVER_LIBRARIES NAMES indidriver HINTS ${PC_INDI_LIBRARY_DIRS} ) - - find_library(INDI_MAIN_LIBRARIES NAMES indimain - HINTS ${PC_INDI_LIBRARY_DIRS} - ) - + find_library(INDI_CLIENT_LIBRARIES NAMES indiclient HINTS ${PC_INDI_LIBRARY_DIRS} ) @@ -69,10 +64,10 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(INDI - REQUIRED_VARS INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES + REQUIRED_VARS INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_CLIENT_LIBRARIES VERSION_VAR INDI_VERSION ) - mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES) + mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_CLIENT_LIBRARIES) -endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES AND INDI_CLIENT_LIBRARIES) +endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_CLIENT_LIBRARIES) diff -Nru libindi-1.0.0/cmake_modules/FindSBIG.cmake libindi-1.1.0/cmake_modules/FindSBIG.cmake --- libindi-1.0.0/cmake_modules/FindSBIG.cmake 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/cmake_modules/FindSBIG.cmake 2015-09-06 13:17:35.000000000 +0000 @@ -1,22 +1,26 @@ -# - Try to find SBIG (Santa Barbara Instruments Group Library for CCDs & Filter Wheels). +# - 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 -# Copyright (c) 2006, Jasem Mutlaq -# Based on FindLibfacile by Carsten Niehaus, -# # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. -if (SBIG_LIBRARIES) +if (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) # in cache already set(SBIG_FOUND TRUE) - message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") + message(STATUS "Found libsbig: ${SBIG_LIBRARIES}") + +else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) -else (SBIG_LIBRARIES) + find_path(SBIG_INCLUDE_DIR sbigudrv.h + PATH_SUFFIXES libsbig + ${_obIncDir} + ${GNUWIN32_DIR}/include + ) find_library(SBIG_LIBRARIES NAMES sbigudrv PATHS @@ -24,13 +28,12 @@ ${GNUWIN32_DIR}/lib ) - set(CMAKE_REQUIRED_LIBRARIES ${SBIG_LIBRARIES}) - - if(SBIG_LIBRARIES) + if(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) set(SBIG_FOUND TRUE) - else (SBIG_LIBRARIES) + else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) set(SBIG_FOUND FALSE) - endif(SBIG_LIBRARIES) + endif(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) + if (SBIG_FOUND) if (NOT SBIG_FIND_QUIETLY) @@ -38,10 +41,10 @@ endif (NOT SBIG_FIND_QUIETLY) else (SBIG_FOUND) if (SBIG_FIND_REQUIRED) - message(FATAL_ERROR "SBIG not found. Please install SBIG library. http://indi.sf.net") + 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_LIBRARIES) + mark_as_advanced(SBIG_INCLUDE_DIR SBIG_LIBRARIES) -endif (SBIG_LIBRARIES) +endif (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES) diff -Nru libindi-1.0.0/.cproject libindi-1.1.0/.cproject --- libindi-1.0.0/.cproject 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/.cproject 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru libindi-1.0.0/debian/changelog libindi-1.1.0/debian/changelog --- libindi-1.0.0/debian/changelog 2015-12-08 17:25:43.000000000 +0000 +++ libindi-1.1.0/debian/changelog 2016-02-18 13:00:41.000000000 +0000 @@ -1,21 +1,22 @@ -libindi (1.0.0-3ubuntu3) xenial; urgency=medium +libindi (1.1.0-1ubuntu1) xenial; urgency=medium - * Rebuild against new gsl SONAME change. + * Mark symbols as optional, when built with -O3. - -- Michael Terry Tue, 08 Dec 2015 12:25:43 -0500 + -- Matthias Klose Thu, 18 Feb 2016 14:00:02 +0100 -libindi (1.0.0-3ubuntu2) xenial; urgency=medium +libindi (1.1.0-1) unstable; urgency=medium - * Rebuild against new gsl. Update references to libgsl0-dev to libgsl- - dev. + * New upstream release (1.1.0). - -- Iain Lane Tue, 10 Nov 2015 15:06:07 +0000 + -- Maximiliano Curia Mon, 18 Jan 2016 16:06:38 +0100 -libindi (1.0.0-3ubuntu1) wily; urgency=medium +libindi (1.0.0-4) unstable; urgency=medium - * Update symbols from 1.0.0-3 build logs. + [ Bas Couwenberg ] + * Update build dependencies for GSL 2, change libgsl0-dev to libgsl-dev. + (Closes: #806834) - -- Logan Rosen Mon, 31 Aug 2015 14:23:54 -0400 + -- Maximiliano Curia Wed, 02 Dec 2015 11:09:08 +0100 libindi (1.0.0-3) unstable; urgency=medium diff -Nru libindi-1.0.0/debian/control libindi-1.1.0/debian/control --- libindi-1.0.0/debian/control 2015-11-10 15:02:13.000000000 +0000 +++ libindi-1.1.0/debian/control 2016-01-18 15:06:38.000000000 +0000 @@ -1,13 +1,14 @@ Source: libindi Section: misc Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Krap Maintainers +Maintainer: Debian Krap Maintainers Uploaders: Pino Toscano , Maximiliano Curia -Build-Depends: cmake (>= 2.4.7), +Build-Depends: cmake (>= 2.6~), debhelper (>= 9), libcfitsio-dev, + libcurl4-gnutls-dev, libgsl-dev, + libgsl0-dev, libjpeg-dev, libnova-dev (>= 0.14.0), libusb-1.0-0-dev, @@ -22,7 +23,9 @@ Package: libindi1 Section: libs Architecture: any -Depends: libindi-data (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: libindi-data (>= ${source:Version}), + ${misc:Depends}, + ${shlibs:Depends} Suggests: indi-bin (>= ${source:Version}) Pre-Depends: ${misc:Pre-Depends} Multi-Arch: same @@ -38,7 +41,9 @@ Package: libindidriver1 Section: libs Architecture: any -Depends: libindi-data (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: libindi-data (>= ${source:Version}), + ${misc:Depends}, + ${shlibs:Depends} Pre-Depends: ${misc:Pre-Depends} Multi-Arch: same Description: Instrument-Neutral Device Interface library -- driver library @@ -50,25 +55,12 @@ . This package contains the driver shared library. -Package: libindimain1 -Section: libs -Architecture: any -Depends: libindi-data (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} -Pre-Depends: ${misc:Pre-Depends} -Multi-Arch: same -Description: Instrument-Neutral Device Interface library -- main library - INDI (Instrument-Neutral Device Interface) is a distributed XML-based - control protocol designed to operate astronomical instrumentation. - INDI is small, flexible, easy to parse, scalable, and stateless. - It supports common DCS functions such as remote control, data acquisition, - monitoring, and a lot more. - . - This package contains the main shared library. - Package: libindialignmentdriver1 Section: libs Architecture: any -Depends: libindi-plugins (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: libindi-plugins (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} Pre-Depends: ${misc:Pre-Depends} Multi-Arch: same Description: Instrument-Neutral Device Interface library -- alignment driver lib @@ -100,9 +92,8 @@ Architecture: any Depends: libcfitsio3-dev, libindi1 (= ${binary:Version}), - libindidriver1 (= ${binary:Version}), - libindimain1 (= ${binary:Version}), libindialignmentdriver1 (= ${binary:Version}), + libindidriver1 (= ${binary:Version}), libusb-1.0-0-dev, ${misc:Depends} Description: Instrument-Neutral Device Interface library -- development files @@ -129,7 +120,9 @@ Package: indi-bin Architecture: any -Depends: libindi-data (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} +Depends: libindi-data (>= ${source:Version}), + ${misc:Depends}, + ${shlibs:Depends} Description: INDI server, drivers and tools INDI (Instrument-Neutral Device Interface) is a distributed XML-based control protocol designed to operate astronomical instrumentation. diff -Nru libindi-1.0.0/debian/libindi1.symbols libindi-1.1.0/debian/libindi1.symbols --- libindi-1.0.0/debian/libindi1.symbols 2015-08-31 18:22:15.000000000 +0000 +++ libindi-1.1.0/debian/libindi1.symbols 2016-01-18 15:06:38.000000000 +0000 @@ -1,4 +1,4 @@ -# SymbolsHelper-Confirmed: 1.0.0 amd64 +# SymbolsHelper-Confirmed: 1.1.0 amd64 libindi.so.1 libindi1 #MINVER# IDLog@Base 1.0.0 IUFindBLOB@Base 1.0.0 @@ -32,6 +32,8 @@ from64tobits@Base 1.0.0 fs_sexa@Base 1.0.0 getSexComponents@Base 1.0.0 + get_local_hour_angle@Base 1.1.0 + get_local_sideral_time@Base 1.1.0 lilxmlMalloc@Base 1.0.0 nXMLAtt@Base 1.0.0 nXMLEle@Base 1.0.0 @@ -48,6 +50,10 @@ permStr@Base 1.0.0 prXMLEle@Base 1.0.0 pstateStr@Base 1.0.0 + range24@Base 1.1.0 + range360@Base 1.1.0 + rangeDec@Base 1.1.0 + rangeHA@Base 1.1.0 readXMLEle@Base 1.0.0 readXMLFile@Base 1.0.0 rmXMLAtt@Base 1.0.0 diff -Nru libindi-1.0.0/debian/libindialignmentdriver1.symbols libindi-1.1.0/debian/libindialignmentdriver1.symbols --- libindi-1.0.0/debian/libindialignmentdriver1.symbols 2015-08-31 18:22:56.000000000 +0000 +++ libindi-1.1.0/debian/libindialignmentdriver1.symbols 2016-02-18 13:00:00.000000000 +0000 @@ -1,4 +1,4 @@ -# SymbolsHelper-Confirmed: 1.0.0 amd64 arm64 armel armhf hppa i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc ppc64 ppc64el s390x x32 +# SymbolsHelper-Confirmed: 1.1.0 amd64 libindiAlignmentDriver.so.1 libindialignmentdriver1 #MINVER# _ZN4INDI18AlignmentSubsystem10ConvexHull10CheckEulerEiii@Base 1.0.0 _ZN4INDI18AlignmentSubsystem10ConvexHull10CleanEdgesEv@Base 1.0.0 @@ -82,13 +82,13 @@ _ZN4INDI18AlignmentSubsystem20MathPluginManagementD1Ev@Base 1.0.0 _ZN4INDI18AlignmentSubsystem20MathPluginManagementD2Ev@Base 1.0.0 _ZN4INDI18AlignmentSubsystem24TelescopeDirectionVector13RotateAroundYEd@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers14InitPropertiesEPNS_9TelescopeE@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers20SaveConfigPropertiesEP8_IO_FILE@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers21ProcessBlobPropertiesEPNS_9TelescopeEPKcPiS6_PPcS8_S8_i@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers21ProcessTextPropertiesEPNS_9TelescopeEPKcPPcS7_i@Base 1.0.0 _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers22MyDatabaseLoadCallbackEPv@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers23ProcessNumberPropertiesEPNS_9TelescopeEPKcPdPPci@Base 1.0.0 - _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers23ProcessSwitchPropertiesEPNS_9TelescopeEPKcP7ISStatePPci@Base 1.0.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers23InitAlignmentPropertiesEPNS_9TelescopeE@Base 1.1.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers29SaveAlignmentConfigPropertiesEP8_IO_FILE@Base 1.1.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers30ProcessAlignmentBLOBPropertiesEPNS_9TelescopeEPKcPiS6_PPcS8_S8_i@Base 1.1.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers30ProcessAlignmentTextPropertiesEPNS_9TelescopeEPKcPPcS7_i@Base 1.1.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers32ProcessAlignmentNumberPropertiesEPNS_9TelescopeEPKcPdPPci@Base 1.1.0 + _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDrivers32ProcessAlignmentSwitchPropertiesEPNS_9TelescopeEPKcP7ISStatePPci@Base 1.1.0 _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDriversC1Ev@Base 1.0.0 _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDriversC2Ev@Base 1.0.0 _ZN4INDI18AlignmentSubsystem28AlignmentSubsystemForDriversD0Ev@Base 1.0.0 @@ -110,31 +110,26 @@ _ZN4INDI18AlignmentSubsystem40TelescopeDirectionVectorSupportFunctionsD2Ev@Base 1.0.0 _ZNK4INDI18AlignmentSubsystem16InMemoryDatabase26CheckForDuplicateSyncPointERKNS0_22AlignmentDatabaseEntryEd@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE13_M_insert_auxIIRKS2_EEEvN9__gnu_cxx17__normal_iteratorIPS2_S4_EEDpOT_@Base 1.0.0 - (optional=gccinternal|arch=!amd64 !arm64 !armhf !i386 !powerpc !ppc64el)_ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE13_M_insert_auxIIS2_EEEvN9__gnu_cxx17__normal_iteratorIPS2_S4_EEDpOT_@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE13_M_insert_auxIJRKS2_EEEvN9__gnu_cxx17__normal_iteratorIPS2_S4_EEDpOT_@Base 1.0.0 - (optional=gccinternal|arch=!amd64 !arm64 !armhf !i386 !powerpc !ppc64el)_ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE13_M_insert_auxIJS2_EEEvN9__gnu_cxx17__normal_iteratorIPS2_S4_EEDpOT_@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE19_M_emplace_back_auxIIRKS2_EEEvDpOT_@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE19_M_emplace_back_auxIJRKS2_EEEvDpOT_@Base 1.0.0 - (optional=gccinternal|arch=!amd64 !arm64 !armhf !i386 !powerpc !ppc64el)_ZNSt6vectorIN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryESaIS2_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS2_S4_EERS7_@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem24TelescopeDirectionVectorESaIS2_EE19_M_emplace_back_auxIIRKS2_EEEvDpOT_@Base 1.0.0 _ZNSt6vectorIN4INDI18AlignmentSubsystem24TelescopeDirectionVectorESaIS2_EE19_M_emplace_back_auxIJRKS2_EEEvDpOT_@Base 1.0.0 (optional=templinst)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIIRKS5_EEEvDpOT_@Base 1.0.0 - (optional=templinst|arch=arm64 armel armhf hppa mips mipsel powerpc ppc64 ppc64el)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIIS5_EEEvDpOT_@Base 1.0.0 + (optional=templinst|arch=armel armhf hppa mips mipsel powerpc ppc64 ppc64el)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIIS5_EEEvDpOT_@Base 1.0.0 (optional=templinst)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIJRKS5_EEEvDpOT_@Base 1.0.0 - (optional=templinst|arch=arm64 armel armhf hppa mips mipsel powerpc ppc64 ppc64el)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIJS5_EEEvDpOT_@Base 1.0.0 + (optional=templinst|arch=armel armhf hppa mips mipsel powerpc ppc64 ppc64el)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIJS5_EEEvDpOT_@Base 1.0.0 (optional=templinst)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED1Ev@Base 1.0.0 (optional=templinst)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev@Base 1.0.0 -#MISSING: 1.0.0# (optional=gccinternal|arch=!armel !armhf !hppa !i386 !kfreebsd-amd64 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x !x32)_ZNSt6vectorISsSaISsEED1Ev@Base 1.0.0 -#MISSING: 1.0.0# (optional=gccinternal|arch=!armel !armhf !hppa !i386 !kfreebsd-amd64 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x !x32)_ZNSt6vectorISsSaISsEED2Ev@Base 1.0.0 (optional=templinst|arch=!hppa !x32)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE22_M_emplace_hint_uniqueIIRKSt21piecewise_construct_tSt5tupleIIOdEESI_IIEEEEESt17_Rb_tree_iteratorIS7_ESt23_Rb_tree_const_iteratorIS7_EDpOT_@Base 1.0.0 (optional=templinst|arch=!hppa !x32)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE22_M_emplace_hint_uniqueIJRKSt21piecewise_construct_tSt5tupleIJOdEESI_IJEEEEESt17_Rb_tree_iteratorIS7_ESt23_Rb_tree_const_iteratorIS7_EDpOT_@Base 1.0.0 - (arch=!ppc64el)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 - (optional=templinst|arch=!armel !armhf !i386 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS7_ERS1_@Base 1.0.0 + (optional=O3)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 + (optional=templinst|arch=!armel !armhf !i386 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !s390x)_ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS7_ERS1_@Base 1.0.0 _ZNSt8_Rb_treeIdSt4pairIKdPKN4INDI18AlignmentSubsystem22AlignmentDatabaseEntryEESt10_Select1stIS7_ESt4lessIdESaIS7_EE8_M_eraseEPSt13_Rb_tree_nodeIS7_E@Base 1.0.0 (optional=templinst)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE22_M_emplace_hint_uniqueIIRKSt21piecewise_construct_tSt5tupleIIRS1_EESD_IIEEEEESt17_Rb_tree_iteratorIS2_ESt23_Rb_tree_const_iteratorIS2_EDpOT_@Base 1.0.0 (optional=templinst)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE22_M_emplace_hint_uniqueIJRKSt21piecewise_construct_tSt5tupleIJRS1_EESD_IJEEEEESt17_Rb_tree_iteratorIS2_ESt23_Rb_tree_const_iteratorIS2_EDpOT_@Base 1.0.0 - (arch=!ppc64el)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 - (optional=templinst|arch=!armel !armhf !i386 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS2_ERS1_@Base 1.0.0 + (optional=O3)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 + (optional=templinst|arch=!armel !armhf !i386 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !s390x)_ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS2_ERS1_@Base 1.0.0 _ZNSt8_Rb_treeIiSt4pairIKiiESt10_Select1stIS2_ESt4lessIiESaIS2_EE8_M_eraseEPSt13_Rb_tree_nodeIS2_E@Base 1.0.0 _ZTIN4INDI18AlignmentSubsystem10ConvexHullE@Base 1.0.0 _ZTIN4INDI18AlignmentSubsystem10MathPluginE@Base 1.0.0 @@ -164,8 +159,6 @@ _ZTVN4INDI18AlignmentSubsystem20MathPluginManagementE@Base 1.0.0 _ZTVN4INDI18AlignmentSubsystem28AlignmentSubsystemForDriversE@Base 1.0.0 _ZTVN4INDI18AlignmentSubsystem31MapPropertiesToInMemoryDatabaseE@Base 1.0.0 -#MISSING: 1.0.0# (optional=gccinternal|arch=!armel !armhf !hppa !i386 !kfreebsd-amd64 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x !x32)_ZTVN4INDI18AlignmentSubsystem32AlignmentSubsystemForMathPluginsE@Base 1.0.0 -#MISSING: 1.0.0# (optional=gccinternal|arch=!armel !armhf !hppa !i386 !kfreebsd-amd64 !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !ppc64el !s390x !x32)_ZTVN4INDI18AlignmentSubsystem40TelescopeDirectionVectorSupportFunctionsE@Base 1.0.0 (c++)"non-virtual thunk to INDI::AlignmentSubsystem::AlignmentSubsystemForDrivers::~AlignmentSubsystemForDrivers()@Base" 1.0.0 (c++)"non-virtual thunk to INDI::AlignmentSubsystem::BasicMathPlugin::~BasicMathPlugin()@Base" 1.0.0 (c++)"non-virtual thunk to INDI::AlignmentSubsystem::BuiltInMathPlugin::~BuiltInMathPlugin()@Base" 1.0.0 diff -Nru libindi-1.0.0/debian/libindidriver1.symbols libindi-1.1.0/debian/libindidriver1.symbols --- libindi-1.0.0/debian/libindidriver1.symbols 2015-08-31 18:22:56.000000000 +0000 +++ libindi-1.1.0/debian/libindidriver1.symbols 2016-02-18 12:58:51.000000000 +0000 @@ -1,4 +1,4 @@ -# SymbolsHelper-Confirmed: 1.0.0 amd64 arm64 armel armhf hppa i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc ppc64 ppc64el s390x sh4 x32 +# SymbolsHelper-Confirmed: 1.1.0 amd64 libindidriver.so.1 libindidriver1 #MINVER# ALIGNMENT_TAB@Base 1.0.0 COMMUNICATION_TAB@Base 1.0.0 @@ -79,6 +79,7 @@ RAPIDGUIDE_TAB@Base 1.0.0 (arch=!kfreebsd-any)RGB2YUV@Base 1.0.0 SITE_TAB@Base 1.0.0 + WCS_TAB@Base 1.1.0 _Z9timerfuncPv@Base 1.0.0 (arch=!kfreebsd-any)_ZN11V4L2_Decode10getDecoderEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN11V4L2_Decode10setDecoderEP12V4L2_Decoder@Base 1.0.0 @@ -127,10 +128,14 @@ (arch=!kfreebsd-any)_ZN13V4L2_RecorderD0Ev@Base 1.0.0 (arch=!kfreebsd-any)_ZN13V4L2_RecorderD1Ev@Base 1.0.0 (arch=!kfreebsd-any)_ZN13V4L2_RecorderD2Ev@Base 1.0.0 + _ZN20V4L2_Builtin_Decoder10getLinearYEv@Base 1.1.0 + _ZN20V4L2_Builtin_Decoder11makeLinearYEv@Base 1.1.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder11usesoftcropEb@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder12allocBuffersEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder12getRGBBufferEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder14getColorBufferEv@Base 1.0.0 + _ZN20V4L2_Builtin_Decoder15setQuantizationEb@Base 1.1.0 + _ZN20V4L2_Builtin_Decoder16setLinearizationEb@Base 1.1.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder17issupportedformatEj@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder19getsupportedformatsEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder22init_supported_formatsEv@Base 1.0.0 @@ -138,10 +143,12 @@ (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder4getVEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder4getYEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder4initEv@Base 1.0.0 + _ZN20V4L2_Builtin_Decoder5makeYEv@Base 1.1.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder6decodeEPhP11v4l2_buffer@Base 1.0.0 + _ZN20V4L2_Builtin_Decoder6getBppEv@Base 1.1.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder7setcropE9v4l2_crop@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder9resetcropEv@Base 1.0.0 - (arch=!kfreebsd-any)_ZN20V4L2_Builtin_Decoder9setformatE11v4l2_format@Base 1.0.0 + _ZN20V4L2_Builtin_Decoder9setformatE11v4l2_formatb@Base 1.1.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_DecoderC1Ev@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_DecoderC2Ev@Base 1.0.0 (arch=!kfreebsd-any)_ZN20V4L2_Builtin_DecoderD0Ev@Base 1.0.0 @@ -149,7 +156,7 @@ (arch=!kfreebsd-any)_ZN20V4L2_Builtin_DecoderD2Ev@Base 1.0.0 (arch=!sh4)_ZN4INDI10BaseDevice10addMessageENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE@Base 1.0.0 (arch=sh4)_ZN4INDI10BaseDevice10addMessageESs@Base 1.0.0 - _ZN4INDI10BaseDevice11getPropertyEPKc9INDI_TYPE@Base 1.0.0 + _ZN4INDI10BaseDevice11getPropertyEPKc18INDI_PROPERTY_TYPE@Base 1.1.0 _ZN4INDI10BaseDevice11isConnectedEv@Base 1.0.0 (arch=!sh4)_ZN4INDI10BaseDevice11lastMessageB5cxx11Ev@Base 1.0.0 (arch=sh4)_ZN4INDI10BaseDevice11lastMessageEv@Base 1.0.0 @@ -161,11 +168,11 @@ _ZN4INDI10BaseDevice13getDriverExecEv@Base 1.0.0 _ZN4INDI10BaseDevice13getDriverNameEv@Base 1.0.0 _ZN4INDI10BaseDevice13setDeviceNameEPKc@Base 1.0.0 - _ZN4INDI10BaseDevice14getRawPropertyEPKc9INDI_TYPE@Base 1.0.0 + _ZN4INDI10BaseDevice14getRawPropertyEPKc18INDI_PROPERTY_TYPE@Base 1.1.0 _ZN4INDI10BaseDevice14removePropertyEPKcPc@Base 1.0.0 _ZN4INDI10BaseDevice16getDriverVersionEv@Base 1.0.0 _ZN4INDI10BaseDevice16getPropertyStateEPKc@Base 1.0.0 - _ZN4INDI10BaseDevice16registerPropertyEPv9INDI_TYPE@Base 1.0.0 + _ZN4INDI10BaseDevice16registerPropertyEPv18INDI_PROPERTY_TYPE@Base 1.1.0 _ZN4INDI10BaseDevice18getDriverInterfaceEv@Base 1.0.0 _ZN4INDI10BaseDevice21getPropertyPermissionEPKc@Base 1.0.0 _ZN4INDI10BaseDevice7getBLOBEPKc@Base 1.0.0 @@ -266,19 +273,32 @@ _ZN4INDI13DefaultDeviceD0Ev@Base 1.0.0 _ZN4INDI13DefaultDeviceD1Ev@Base 1.0.0 _ZN4INDI13DefaultDeviceD2Ev@Base 1.0.0 - _ZN4INDI13DomeInterface11MoveAbsDomeEd@Base 1.0.0 - _ZN4INDI13DomeInterface11MoveRelDomeENS0_13DomeDirectionEd@Base 1.0.0 - _ZN4INDI13DomeInterface12SetDomeSpeedEd@Base 1.0.0 + _ZN4INDI13DomeInterface12GetAxis1ParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface12LoadParkDataEv@Base 1.1.0 + _ZN4INDI13DomeInterface12SetAxis1ParkEd@Base 1.1.0 + _ZN4INDI13DomeInterface13WriteParkDataEv@Base 1.1.0 + _ZN4INDI13DomeInterface14ControlShutterENS0_16ShutterOperationE@Base 1.1.0 + _ZN4INDI13DomeInterface14SetCurrentParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface14SetDefaultParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface15SetParkDataTypeENS0_12DomeParkDataE@Base 1.1.0 _ZN4INDI13DomeInterface17SetDomeCapabilityEPNS0_14DomeCapabilityE@Base 1.0.0 _ZN4INDI13DomeInterface17processDomeNumberEPKcS2_PdPPci@Base 1.0.0 _ZN4INDI13DomeInterface17processDomeSwitchEPKcS2_P7ISStatePPci@Base 1.0.0 - _ZN4INDI13DomeInterface18ControlDomeShutterENS0_16ShutterOperationE@Base 1.0.0 _ZN4INDI13DomeInterface18initDomePropertiesEPKcS2_@Base 1.0.0 + _ZN4INDI13DomeInterface19GetAxis1ParkDefaultEv@Base 1.1.0 + _ZN4INDI13DomeInterface19SetAxis1ParkDefaultEd@Base 1.1.0 _ZN4INDI13DomeInterface22GetShutterStatusStringENS0_13ShutterStatusE@Base 1.0.0 - _ZN4INDI13DomeInterface8HomeDomeEv@Base 1.0.0 - _ZN4INDI13DomeInterface8MoveDomeENS0_13DomeDirectionEdi@Base 1.0.0 - _ZN4INDI13DomeInterface8ParkDomeEv@Base 1.0.0 - _ZN4INDI13DomeInterface9AbortDomeEv@Base 1.0.0 + _ZN4INDI13DomeInterface4HomeEv@Base 1.1.0 + _ZN4INDI13DomeInterface4MoveENS0_13DomeDirectionENS0_17DomeMotionCommandE@Base 1.1.0 + _ZN4INDI13DomeInterface4ParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface5AbortEv@Base 1.1.0 + _ZN4INDI13DomeInterface6UnParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface7MoveAbsEd@Base 1.1.0 + _ZN4INDI13DomeInterface7MoveRelEd@Base 1.1.0 + _ZN4INDI13DomeInterface8InitParkEv@Base 1.1.0 + _ZN4INDI13DomeInterface8SetSpeedEd@Base 1.1.0 + _ZN4INDI13DomeInterface8isParkedEv@Base 1.1.0 + _ZN4INDI13DomeInterface9SetParkedEb@Base 1.1.0 _ZN4INDI13DomeInterfaceC1Ev@Base 1.0.0 _ZN4INDI13DomeInterfaceC2Ev@Base 1.0.0 _ZN4INDI13DomeInterfaceD0Ev@Base 1.0.0 @@ -292,15 +312,16 @@ _ZN4INDI15FilterInterfaceC2Ev@Base 1.0.0 _ZN4INDI15FilterInterfaceD1Ev@Base 1.0.0 _ZN4INDI15FilterInterfaceD2Ev@Base 1.0.0 + _ZN4INDI15GuiderInterface13GuideCompleteE12INDI_EQ_AXIS@Base 1.1.0 _ZN4INDI15GuiderInterface20initGuiderPropertiesEPKcS2_@Base 1.0.0 _ZN4INDI15GuiderInterface23processGuiderPropertiesEPKcPdPPci@Base 1.0.0 _ZN4INDI15GuiderInterfaceC1Ev@Base 1.0.0 _ZN4INDI15GuiderInterfaceC2Ev@Base 1.0.0 _ZN4INDI15GuiderInterfaceD1Ev@Base 1.0.0 _ZN4INDI15GuiderInterfaceD2Ev@Base 1.0.0 - _ZN4INDI16FocuserInterface11MoveFocuserENS0_14FocusDirectionEii@Base 1.0.0 + _ZN4INDI16FocuserInterface11MoveFocuserENS0_14FocusDirectionEit@Base 1.1.0 _ZN4INDI16FocuserInterface12AbortFocuserEv@Base 1.0.0 - _ZN4INDI16FocuserInterface14MoveAbsFocuserEi@Base 1.0.0 + _ZN4INDI16FocuserInterface14MoveAbsFocuserEj@Base 1.1.0 _ZN4INDI16FocuserInterface14MoveRelFocuserENS0_14FocusDirectionEj@Base 1.0.0 _ZN4INDI16FocuserInterface15SetFocuserSpeedEi@Base 1.0.0 _ZN4INDI16FocuserInterface20SetFocuserCapabilityEPNS0_17FocuserCapabilityE@Base 1.0.0 @@ -321,6 +342,7 @@ _ZN4INDI3CCD12UpdateCCDBinEii@Base 1.0.0 _ZN4INDI3CCD12getFileIndexEPKcS2_S2_@Base 1.0.0 _ZN4INDI3CCD13AbortExposureEv@Base 1.0.0 + _ZN4INDI3CCD13GuideCompleteE12INDI_EQ_AXIS@Base 1.1.0 _ZN4INDI3CCD13ISSnoopDeviceEP8_xml_ele@Base 1.0.0 _ZN4INDI3CCD13StartExposureEf@Base 1.0.0 _ZN4INDI3CCD14SetTemperatureEd@Base 1.0.0 @@ -351,6 +373,16 @@ _ZN4INDI3CCDD0Ev@Base 1.0.0 _ZN4INDI3CCDD1Ev@Base 1.0.0 _ZN4INDI3CCDD2Ev@Base 1.0.0 + _ZN4INDI3GPS11ISNewSwitchEPKcS2_P7ISStatePPci@Base 1.1.0 + _ZN4INDI3GPS14initPropertiesEv@Base 1.1.0 + _ZN4INDI3GPS16updatePropertiesEv@Base 1.1.0 + _ZN4INDI3GPS8TimerHitEv@Base 1.1.0 + _ZN4INDI3GPS9updateGPSEv@Base 1.1.0 + _ZN4INDI3GPSC1Ev@Base 1.1.0 + _ZN4INDI3GPSC2Ev@Base 1.1.0 + _ZN4INDI3GPSD0Ev@Base 1.1.0 + _ZN4INDI3GPSD1Ev@Base 1.1.0 + _ZN4INDI3GPSD2Ev@Base 1.1.0 _ZN4INDI4Dome11GetTargetAzERdS1_S1_S1_@Base 1.0.0 _ZN4INDI4Dome11ISNewNumberEPKcS2_PdPPci@Base 1.0.0 _ZN4INDI4Dome11ISNewSwitchEPKcS2_P7ISStatePPci@Base 1.0.0 @@ -401,6 +433,7 @@ (arch=sh4)_ZN4INDI6Logger5printEPKcjRKSsiS2_z@Base 1.0.0 (arch=!sh4)_ZN4INDI6Logger8logFile_B5cxx11E@Base 1.0.0 (arch=sh4)_ZN4INDI6Logger8logFile_E@Base 1.0.0 + _ZN4INDI6Logger8nDevicesE@Base 1.1.0 (arch=!sh4)_ZN4INDI6Logger9configureERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS0_11loggerConf_Eii@Base 1.0.0 (arch=sh4)_ZN4INDI6Logger9configureERKSsNS0_11loggerConf_Eii@Base 1.0.0 _ZN4INDI6LoggerC1Ev@Base 1.0.0 @@ -422,6 +455,26 @@ _ZN4INDI7FocuserD0Ev@Base 1.0.0 _ZN4INDI7FocuserD1Ev@Base 1.0.0 _ZN4INDI7FocuserD2Ev@Base 1.0.0 + _ZN4INDI7Weather11ISNewNumberEPKcS2_PdPPci@Base 1.1.0 + _ZN4INDI7Weather11ISNewSwitchEPKcS2_P7ISStatePPci@Base 1.1.0 + _ZN4INDI7Weather12addParameterENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEdddd@Base 1.1.0 + _ZN4INDI7Weather13ISSnoopDeviceEP8_xml_ele@Base 1.1.0 + _ZN4INDI7Weather13updateWeatherEv@Base 1.1.0 + _ZN4INDI7Weather14initPropertiesEv@Base 1.1.0 + _ZN4INDI7Weather14syncParametersEv@Base 1.1.0 + _ZN4INDI7Weather14updateLocationEddd@Base 1.1.0 + _ZN4INDI7Weather15saveConfigItemsEP8_IO_FILE@Base 1.1.0 + _ZN4INDI7Weather16updatePropertiesEv@Base 1.1.0 + _ZN4INDI7Weather18updateWeatherStateEv@Base 1.1.0 + _ZN4INDI7Weather19processLocationInfoEddd@Base 1.1.0 + _ZN4INDI7Weather20createParameterRangeENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE@Base 1.1.0 + _ZN4INDI7Weather20setCriticalParameterENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE@Base 1.1.0 + _ZN4INDI7Weather8TimerHitEv@Base 1.1.0 + _ZN4INDI7WeatherC1Ev@Base 1.1.0 + _ZN4INDI7WeatherC2Ev@Base 1.1.0 + _ZN4INDI7WeatherD0Ev@Base 1.1.0 + _ZN4INDI7WeatherD1Ev@Base 1.1.0 + _ZN4INDI7WeatherD2Ev@Base 1.1.0 _ZN4INDI8Property10setDynamicEb@Base 1.0.0 _ZN4INDI8Property11setPropertyEPv@Base 1.0.0 _ZN4INDI8Property12getGroupNameEv@Base 1.0.0 @@ -432,7 +485,7 @@ _ZN4INDI8Property7getBLOBEv@Base 1.0.0 _ZN4INDI8Property7getNameEv@Base 1.0.0 _ZN4INDI8Property7getTextEv@Base 1.0.0 - _ZN4INDI8Property7setTypeE9INDI_TYPE@Base 1.0.0 + _ZN4INDI8Property7setTypeE18INDI_PROPERTY_TYPE@Base 1.1.0 _ZN4INDI8Property8getLabelEv@Base 1.0.0 _ZN4INDI8Property8getLightEv@Base 1.0.0 _ZN4INDI8Property8getStateEv@Base 1.0.0 @@ -446,22 +499,48 @@ _ZN4INDI9Telescope10updateTimeEP7ln_dated@Base 1.0.0 _ZN4INDI9Telescope11ISNewNumberEPKcS2_PdPPci@Base 1.0.0 _ZN4INDI9Telescope11ISNewSwitchEPKcS2_P7ISStatePPci@Base 1.0.0 + _ZN4INDI9Telescope11SetSlewRateEi@Base 1.1.0 + _ZN4INDI9Telescope11processNSWEEdd@Base 1.1.0 + _ZN4INDI9Telescope12GetAxis1ParkEv@Base 1.1.0 + _ZN4INDI9Telescope12GetAxis2ParkEv@Base 1.1.0 + _ZN4INDI9Telescope12LoadParkDataEv@Base 1.1.0 + _ZN4INDI9Telescope12SetAxis1ParkEd@Base 1.1.0 + _ZN4INDI9Telescope12SetAxis2ParkEd@Base 1.1.0 + _ZN4INDI9Telescope12buttonHelperEPKc7ISStatePv@Base 1.1.0 _ZN4INDI9Telescope13ISSnoopDeviceEP8_xml_ele@Base 1.0.0 + _ZN4INDI9Telescope13WriteParkDataEv@Base 1.1.0 + _ZN4INDI9Telescope13processButtonEPKc7ISState@Base 1.1.0 + _ZN4INDI9Telescope14SetCurrentParkEv@Base 1.1.0 + _ZN4INDI9Telescope14SetDefaultParkEv@Base 1.1.0 _ZN4INDI9Telescope14initPropertiesEv@Base 1.0.0 + _ZN4INDI9Telescope14joystickHelperEPKcddPv@Base 1.1.0 _ZN4INDI9Telescope14updateLocationEddd@Base 1.0.0 _ZN4INDI9Telescope15ISGetPropertiesEPKc@Base 1.0.0 + _ZN4INDI9Telescope15SetParkDataTypeENS0_17TelescopeParkDataE@Base 1.1.0 + _ZN4INDI9Telescope15processJoystickEPKcdd@Base 1.1.0 + _ZN4INDI9Telescope15processTimeInfoEPKcS2_@Base 1.1.0 _ZN4INDI9Telescope15saveConfigItemsEP8_IO_FILE@Base 1.0.0 _ZN4INDI9Telescope16updatePropertiesEv@Base 1.0.0 + _ZN4INDI9Telescope18processSlewPresetsEdd@Base 1.1.0 + _ZN4INDI9Telescope19GetAxis1ParkDefaultEv@Base 1.1.0 + _ZN4INDI9Telescope19GetAxis2ParkDefaultEv@Base 1.1.0 + _ZN4INDI9Telescope19SetAxis1ParkDefaultEd@Base 1.1.0 + _ZN4INDI9Telescope19SetAxis2ParkDefaultEd@Base 1.1.0 + _ZN4INDI9Telescope19processLocationInfoEddd@Base 1.1.0 _ZN4INDI9Telescope22SetTelescopeCapabilityEPNS0_19TelescopeCapabilityE@Base 1.0.0 _ZN4INDI9Telescope4ParkEv@Base 1.0.0 _ZN4INDI9Telescope4SyncEdd@Base 1.0.0 - _ZN4INDI9Telescope6MoveNSENS0_17TelescopeMotionNSENS0_22TelescopeMotionCommandE@Base 1.0.0 - _ZN4INDI9Telescope6MoveWEENS0_17TelescopeMotionWEENS0_22TelescopeMotionCommandE@Base 1.0.0 - _ZN4INDI9Telescope7ConnectEPKc@Base 1.0.0 + _ZN4INDI9Telescope6MoveNSE11INDI_DIR_NSNS0_22TelescopeMotionCommandE@Base 1.1.0 + _ZN4INDI9Telescope6MoveWEE11INDI_DIR_WENS0_22TelescopeMotionCommandE@Base 1.1.0 + _ZN4INDI9Telescope6UnParkEv@Base 1.1.0 + _ZN4INDI9Telescope7ConnectEPKct@Base 1.1.0 _ZN4INDI9Telescope7ConnectEv@Base 1.0.0 + _ZN4INDI9Telescope8InitParkEv@Base 1.1.0 _ZN4INDI9Telescope8NewRaDecEdd@Base 1.0.0 _ZN4INDI9Telescope8TimerHitEv@Base 1.0.0 + _ZN4INDI9Telescope8isParkedEv@Base 1.1.0 _ZN4INDI9Telescope9ISNewTextEPKcS2_PPcS4_i@Base 1.0.0 + _ZN4INDI9Telescope9SetParkedEb@Base 1.1.0 _ZN4INDI9TelescopeC1Ev@Base 1.0.0 _ZN4INDI9TelescopeC2Ev@Base 1.0.0 _ZN4INDI9TelescopeD0Ev@Base 1.0.0 @@ -481,22 +560,6 @@ _ZN4INDI9USBDeviceD0Ev@Base 1.0.0 _ZN4INDI9USBDeviceD1Ev@Base 1.0.0 _ZN4INDI9USBDeviceD2Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort11registerBitEPKvi@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort13unregisterBitEPKvi@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort5resetEv@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort6commitEv@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort6setBitEPKvib@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPort7setPortEi@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortC1Ei@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortC1Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortC2Ei@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortC2Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortD1Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN5PPortD2Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN6port_tC1Ei@Base 1.0.0 - (arch=!kfreebsd-any)_ZN6port_tC2Ei@Base 1.0.0 - (arch=!kfreebsd-any)_ZN6port_tD1Ev@Base 1.0.0 - (arch=!kfreebsd-any)_ZN6port_tD2Ev@Base 1.0.0 _ZN7CCDChip12setFrameTypeENS_9CCD_FRAMEE@Base 1.0.0 _ZN7CCDChip12setPixelSizeEff@Base 1.0.0 _ZN7CCDChip13setInterlacedEb@Base 1.0.0 @@ -521,6 +584,7 @@ (arch=!kfreebsd-any)_ZN9V4L2_Base10errno_exitEPKcPc@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base10findMinMaxEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base10getControlEjPdPc@Base 1.0.0 + _ZN9V4L2_Base10getLinearYEv@Base 1.1.0 (arch=!kfreebsd-any)_ZN9V4L2_Base10init_userpEj@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base10query_ctrlEjRdS0_S0_S0_Pc@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base10read_frameEPc@Base 1.0.0 @@ -557,9 +621,11 @@ (arch=!kfreebsd-any)_ZN9V4L2_Base16setcaptureformatEjPc@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base17getcaptureformatsEP22_ISwitchVectorProperty@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base18enumerate_ext_ctrlEv@Base 1.0.0 + _ZN9V4L2_Base18setColorProcessingEbbb@Base 1.1.0 (arch=!kfreebsd-any)_ZN9V4L2_Base4getUEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base4getVEv@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base4getYEv@Base 1.0.0 + _ZN9V4L2_Base6getBppEv@Base 1.1.0 (arch=!kfreebsd-any)_ZN9V4L2_Base6xioctlEiiPv@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base7setSizeEii@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_Base8doDecodeEb@Base 1.0.0 @@ -578,7 +644,6 @@ (arch=!kfreebsd-any)_ZN9V4L2_BaseD1Ev@Base 1.0.0 (arch=!kfreebsd-any)_ZN9V4L2_BaseD2Ev@Base 1.0.0 _ZNK4INDI13DefaultDevice22getInterfaceDescriptorEv@Base 1.0.0 - (arch=!kfreebsd-any)_ZNK5PPort13isRegisterBitEPKvi@Base 1.0.0 _ZNK7CCDChip8getNAxisEv@Base 1.0.0 _ZNKSt5ctypeIcE8do_widenEc@Base 1.0.0 _ZNSt14_Function_base13_Base_managerIPFvPKc7ISStatePvEE10_M_managerERSt9_Any_dataRKS8_St18_Manager_operation@Base 1.0.0 @@ -592,8 +657,8 @@ (optional=templinst|arch=sh4)_ZNSt17_Function_handlerIFvPKcdPvEPFvS1_iS2_EE9_M_invokeERKSt9_Any_dataS1_dS2_@Base 1.0.0 (optional=templinst|arch=!sh4)_ZNSt17_Function_handlerIFvPKcddPvEPS3_E9_M_invokeERKSt9_Any_dataOS1_OdSA_OS2_@Base 1.0.0 (optional=templinst|arch=sh4)_ZNSt17_Function_handlerIFvPKcddPvEPS3_E9_M_invokeERKSt9_Any_dataS1_ddS2_@Base 1.0.0 - (optional=templinst|arch=!ppc64el !sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12emplace_backIIS5_EEEvDpOT_@Base 1.0.0 - (optional=templinst|arch=!ppc64el !sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12emplace_backIJS5_EEEvDpOT_@Base 1.0.0 + (optional=templinst|arch=!sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12emplace_backIIS5_EEEvDpOT_@Base 1.0.0 + (optional=templinst|arch=!sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12emplace_backIJS5_EEEvDpOT_@Base 1.0.0 (optional=templinst|arch=!sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIIRKS5_EEEvDpOT_@Base 1.0.0 (optional=templinst|arch=!sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIIS5_EEEvDpOT_@Base 1.0.0 (optional=templinst|arch=!sh4)_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_emplace_back_auxIJRKS5_EEEvDpOT_@Base 1.0.0 @@ -606,7 +671,7 @@ (arch=!kfreebsd-any)_ZNSt6vectorIP13V4L2_RecorderSaIS1_EE19_M_emplace_back_auxIJS1_EEEvDpOT_@Base 1.0.0 _ZNSt6vectorIPN4INDI8PropertyESaIS2_EE19_M_emplace_back_auxIIRKS2_EEEvDpOT_@Base 1.0.0 _ZNSt6vectorIPN4INDI8PropertyESaIS2_EE19_M_emplace_back_auxIJRKS2_EEEvDpOT_@Base 1.0.0 - (optional=templinst|arch=!ppc64el !sh4)_ZNSt6vectorIPN4INDI8PropertyESaIS2_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS2_S4_EE@Base 1.0.0 + (optional=templinst|arch=!sh4)_ZNSt6vectorIPN4INDI8PropertyESaIS2_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS2_S4_EE@Base 1.0.0 (optional=templinst|arch=sh4)_ZNSt6vectorISsSaISsEE12emplace_backIISsEEEvDpOT_@Base 1.0.0 (optional=templinst|arch=sh4)_ZNSt6vectorISsSaISsEE12emplace_backIJSsEEEvDpOT_@Base 1.0.0 (optional=templinst|arch=sh4)_ZNSt6vectorISsSaISsEE19_M_emplace_back_auxIIRKSsEEEvDpOT_@Base 1.0.0 @@ -620,7 +685,7 @@ (arch=!kfreebsd-any)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE16_M_insert_uniqueIS0_IjS4_EEES0_ISt17_Rb_tree_iteratorIS5_EbEOT_@Base 1.0.0 (optional=templinst|arch=!amd64 !arm64 !hppa !kfreebsd-amd64 !kfreebsd-i386 !ppc64el !sh4 !x32)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE22_M_emplace_hint_uniqueIIRKSt21piecewise_construct_tSt5tupleIIRS1_EESG_IIEEEEESt17_Rb_tree_iteratorIS5_ESt23_Rb_tree_const_iteratorIS5_EDpOT_@Base 1.0.0 (optional=templinst|arch=!amd64 !arm64 !hppa !kfreebsd-amd64 !kfreebsd-i386 !ppc64el !sh4 !x32)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE22_M_emplace_hint_uniqueIJRKSt21piecewise_construct_tSt5tupleIJRS1_EESG_IJEEEEESt17_Rb_tree_iteratorIS5_ESt23_Rb_tree_const_iteratorIS5_EDpOT_@Base 1.0.0 - (arch=!kfreebsd-amd64 !kfreebsd-any !kfreebsd-i386 !ppc64el)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 + (optional=O3|arch=!kfreebsd-any)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE24_M_get_insert_unique_posERS1_@Base 1.0.0 (arch=!armel !armhf !i386 !kfreebsd-amd64 !kfreebsd-any !kfreebsd-i386 !mips !mipsel !powerpc !ppc64 !s390x)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS5_ERS1_@Base 1.0.0 (arch=!kfreebsd-any)_ZNSt8_Rb_treeIjSt4pairIKjPN20V4L2_Builtin_Decoder6formatEESt10_Select1stIS5_ESt4lessIjESaIS5_EE8_M_eraseEPSt13_Rb_tree_nodeIS5_E@Base 1.0.0 (arch=!kfreebsd-any)_ZTI12SER_Recorder@Base 1.0.0 @@ -640,8 +705,10 @@ _ZTIN4INDI15GuiderInterfaceE@Base 1.0.0 _ZTIN4INDI16FocuserInterfaceE@Base 1.0.0 _ZTIN4INDI3CCDE@Base 1.0.0 + _ZTIN4INDI3GPSE@Base 1.1.0 _ZTIN4INDI4DomeE@Base 1.0.0 _ZTIN4INDI7FocuserE@Base 1.0.0 + _ZTIN4INDI7WeatherE@Base 1.1.0 _ZTIN4INDI9TelescopeE@Base 1.0.0 _ZTIN4INDI9USBDeviceE@Base 1.0.0 _ZTIPFvPKc7ISStatePvE@Base 1.0.0 @@ -664,8 +731,10 @@ _ZTSN4INDI15GuiderInterfaceE@Base 1.0.0 _ZTSN4INDI16FocuserInterfaceE@Base 1.0.0 _ZTSN4INDI3CCDE@Base 1.0.0 + _ZTSN4INDI3GPSE@Base 1.1.0 _ZTSN4INDI4DomeE@Base 1.0.0 _ZTSN4INDI7FocuserE@Base 1.0.0 + _ZTSN4INDI7WeatherE@Base 1.1.0 _ZTSN4INDI9TelescopeE@Base 1.0.0 _ZTSN4INDI9USBDeviceE@Base 1.0.0 _ZTSPFvPKc7ISStatePvE@Base 1.0.0 @@ -684,8 +753,10 @@ _ZTVN4INDI15GuiderInterfaceE@Base 1.0.0 _ZTVN4INDI16FocuserInterfaceE@Base 1.0.0 _ZTVN4INDI3CCDE@Base 1.0.0 + _ZTVN4INDI3GPSE@Base 1.1.0 _ZTVN4INDI4DomeE@Base 1.0.0 _ZTVN4INDI7FocuserE@Base 1.0.0 + _ZTVN4INDI7WeatherE@Base 1.1.0 _ZTVN4INDI9TelescopeE@Base 1.0.0 _ZTVN4INDI9USBDeviceE@Base 1.0.0 addCallback@Base 1.0.0 @@ -740,9 +811,45 @@ findXMLEle@Base 1.0.0 from64tobits@Base 1.0.0 fs_sexa@Base 1.0.0 + getColorSpaceName@Base 1.1.0 + getQuantization@Base 1.1.0 + getQuantizationName@Base 1.1.0 getSexComponents@Base 1.0.0 + getYCbCrEncoding@Base 1.1.0 + getYCbCrEncodingName@Base 1.1.0 + get_local_hour_angle@Base 1.1.0 + get_local_sideral_time@Base 1.1.0 + get_usb_code_for_current_locale@Base 1.1.0 + hid_close@Base 1.1.0 + hid_enumerate@Base 1.1.0 + hid_error@Base 1.1.0 + hid_exit@Base 1.1.0 + hid_free_enumeration@Base 1.1.0 + hid_get_feature_report@Base 1.1.0 + hid_get_indexed_string@Base 1.1.0 + hid_get_manufacturer_string@Base 1.1.0 + hid_get_product_string@Base 1.1.0 + hid_get_serial_number_string@Base 1.1.0 + hid_init@Base 1.1.0 + hid_open@Base 1.1.0 + hid_open_path@Base 1.1.0 + hid_read@Base 1.1.0 + hid_read_timeout@Base 1.1.0 + hid_send_feature_report@Base 1.1.0 + hid_set_nonblocking@Base 1.1.0 + hid_write@Base 1.1.0 + initColorSpace@Base 1.1.0 isPropDefined@Base 1.0.0 lilxmlMalloc@Base 1.0.0 + linearize@Base 1.1.0 + lutrangecbcr10@Base 1.1.0 + lutrangecbcr12@Base 1.1.0 + lutrangecbcr16@Base 1.1.0 + lutrangecbcr8@Base 1.1.0 + lutrangey10@Base 1.1.0 + lutrangey12@Base 1.1.0 + lutrangey16@Base 1.1.0 + lutrangey8@Base 1.1.0 main@Base 1.0.0 me@Base 1.0.0 (arch=!kfreebsd-any)mjpegtoyuv420p@Base 1.0.0 @@ -752,6 +859,7 @@ newLilXML@Base 1.0.0 nextXMLAtt@Base 1.0.0 nextXMLEle@Base 1.0.0 + (c++)"non-virtual thunk to INDI::CCD::GuideComplete(INDI_EQ_AXIS)@Base" 1.1.0 (c++)"non-virtual thunk to INDI::CCD::GuideEast(float)@Base" 1.0.0 (c++)"non-virtual thunk to INDI::CCD::GuideNorth(float)@Base" 1.0.0 (c++)"non-virtual thunk to INDI::CCD::GuideSouth(float)@Base" 1.0.0 @@ -772,6 +880,11 @@ permStr@Base 1.0.0 prXMLEle@Base 1.0.0 pstateStr@Base 1.0.0 + range24@Base 1.1.0 + range360@Base 1.1.0 + rangeDec@Base 1.1.0 + rangeHA@Base 1.1.0 + rangeY8@Base 1.1.0 readXMLEle@Base 1.0.0 readXMLFile@Base 1.0.0 rmCallback@Base 1.0.0 diff -Nru libindi-1.0.0/debian/libindimain1.install libindi-1.1.0/debian/libindimain1.install --- libindi-1.0.0/debian/libindimain1.install 2015-08-31 18:22:15.000000000 +0000 +++ libindi-1.1.0/debian/libindimain1.install 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -usr/lib/*/libindimain.so.1 -usr/lib/*/libindimain.so.1.* diff -Nru libindi-1.0.0/debian/libindimain1.symbols libindi-1.1.0/debian/libindimain1.symbols --- libindi-1.0.0/debian/libindimain1.symbols 2015-08-31 18:22:15.000000000 +0000 +++ libindi-1.1.0/debian/libindimain1.symbols 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -# SymbolsHelper-Confirmed: 1.0.0 amd64 -libindimain.so.1 libindimain1 #MINVER# - IDDefBLOB@Base 1.0.0 - IDDefLight@Base 1.0.0 - IDDefNumber@Base 1.0.0 - IDDefSwitch@Base 1.0.0 - IDDefText@Base 1.0.0 - IDDelete@Base 1.0.0 - IDLog@Base 1.0.0 - IDMessage@Base 1.0.0 - IDSetBLOB@Base 1.0.0 - IDSetLight@Base 1.0.0 - IDSetNumber@Base 1.0.0 - IDSetSwitch@Base 1.0.0 - IDSetText@Base 1.0.0 - IDSnoopBLOBs@Base 1.0.0 - IDSnoopDevice@Base 1.0.0 - IEAddCallback@Base 1.0.0 - IEAddTimer@Base 1.0.0 - IEAddWorkProc@Base 1.0.0 - IEDeferLoop0@Base 1.0.0 - IEDeferLoop@Base 1.0.0 - IERmCallback@Base 1.0.0 - IERmTimer@Base 1.0.0 - IERmWorkProc@Base 1.0.0 - IUFillBLOB@Base 1.0.0 - IUFillBLOBVector@Base 1.0.0 - IUFillLight@Base 1.0.0 - IUFillLightVector@Base 1.0.0 - IUFillNumber@Base 1.0.0 - IUFillNumberVector@Base 1.0.0 - IUFillSwitch@Base 1.0.0 - IUFillSwitchVector@Base 1.0.0 - IUFillText@Base 1.0.0 - IUFillTextVector@Base 1.0.0 - IUFindBLOB@Base 1.0.0 - IUFindIndex@Base 1.0.0 - IUFindLight@Base 1.0.0 - IUFindNumber@Base 1.0.0 - IUFindOnSwitch@Base 1.0.0 - IUFindOnSwitchIndex@Base 1.0.0 - IUFindSwitch@Base 1.0.0 - IUFindText@Base 1.0.0 - IUGetConfigFP@Base 1.0.0 - IUReadConfig@Base 1.0.0 - IUResetSwitch@Base 1.0.0 - IUSaveBLOB@Base 1.0.0 - IUSaveConfigBLOB@Base 1.0.0 - IUSaveConfigNumber@Base 1.0.0 - IUSaveConfigSwitch@Base 1.0.0 - IUSaveConfigTag@Base 1.0.0 - IUSaveConfigText@Base 1.0.0 - IUSaveDefaultConfig@Base 1.0.0 - IUSaveText@Base 1.0.0 - IUSnoopBLOB@Base 1.0.0 - IUSnoopLight@Base 1.0.0 - IUSnoopNumber@Base 1.0.0 - IUSnoopSwitch@Base 1.0.0 - IUSnoopText@Base 1.0.0 - IUUpdateBLOB@Base 1.0.0 - IUUpdateMinMax@Base 1.0.0 - IUUpdateNumber@Base 1.0.0 - IUUpdateSwitch@Base 1.0.0 - IUUpdateText@Base 1.0.0 - addCallback@Base 1.0.0 - addTimer@Base 1.0.0 - addWorkProc@Base 1.0.0 - addXMLAtt@Base 1.0.0 - addXMLEle@Base 1.0.0 - appXMLEle@Base 1.0.0 - clientMsgCB@Base 1.0.0 - clixml@Base 1.0.0 - cloneXMLEle@Base 1.0.0 - crackDN@Base 1.0.0 - crackIPState@Base 1.0.0 - crackIPerm@Base 1.0.0 - crackISRule@Base 1.0.0 - crackISState@Base 1.0.0 - deferLoop0@Base 1.0.0 - deferLoop@Base 1.0.0 - delLilXML@Base 1.0.0 - delXMLEle@Base 1.0.0 - dispatch@Base 1.0.0 - editXMLAtt@Base 1.0.0 - editXMLEle@Base 1.0.0 - entityXML@Base 1.0.0 - escapeXML@Base 1.0.0 - eventLoop@Base 1.0.0 - extractISOTime@Base 1.0.0 - f_scansexa@Base 1.0.0 - findXMLAtt@Base 1.0.0 - findXMLAttValu@Base 1.0.0 - findXMLEle@Base 1.0.0 - from64tobits@Base 1.0.0 - fs_sexa@Base 1.0.0 - getSexComponents@Base 1.0.0 - isPropDefined@Base 1.0.0 - lilxmlMalloc@Base 1.0.0 - main@Base 1.0.0 - me@Base 1.0.0 - nXMLAtt@Base 1.0.0 - nXMLEle@Base 1.0.0 - nameXMLAtt@Base 1.0.0 - newLilXML@Base 1.0.0 - nextXMLAtt@Base 1.0.0 - nextXMLEle@Base 1.0.0 - nroCheck@Base 1.0.0 - numberFormat@Base 1.0.0 - parentXMLAtt@Base 1.0.0 - parentXMLEle@Base 1.0.0 - parseXML@Base 1.0.0 - pcdataXMLEle@Base 1.0.0 - pcdatalenXMLEle@Base 1.0.0 - permStr@Base 1.0.0 - prXMLEle@Base 1.0.0 - pstateStr@Base 1.0.0 - readXMLEle@Base 1.0.0 - readXMLFile@Base 1.0.0 - rmCallback@Base 1.0.0 - rmTimer@Base 1.0.0 - rmWorkProc@Base 1.0.0 - rmXMLAtt@Base 1.0.0 - roCheck@Base 1.0.0 - ruleStr@Base 1.0.0 - sprXMLEle@Base 1.0.0 - sprlXMLEle@Base 1.0.0 - sstateStr@Base 1.0.0 - stdout_mutex@Base 1.0.0 - tagXMLEle@Base 1.0.0 - timestamp@Base 1.0.0 - to64frombits@Base 1.0.0 - tty_connect@Base 1.0.0 - tty_debug@Base 1.0.0 - tty_disconnect@Base 1.0.0 - tty_error_msg@Base 1.0.0 - tty_read@Base 1.0.0 - tty_read_section@Base 1.0.0 - tty_set_debug@Base 1.0.0 - tty_timeout@Base 1.0.0 - tty_write@Base 1.0.0 - tty_write_string@Base 1.0.0 - valuXMLAtt@Base 1.0.0 - verbose@Base 1.0.0 - xmlv1@Base 1.0.0 diff -Nru libindi-1.0.0/debian/not-installed libindi-1.1.0/debian/not-installed --- libindi-1.0.0/debian/not-installed 2015-08-31 18:22:15.000000000 +0000 +++ libindi-1.1.0/debian/not-installed 2016-01-18 15:06:38.000000000 +0000 @@ -1 +1,2 @@ lib/udev/rules.d/99-gpusb.rules +lib/udev/rules.d/99-perfectstar.rules diff -Nru libindi-1.0.0/debian/patches/freebsd_support libindi-1.1.0/debian/patches/freebsd_support --- libindi-1.0.0/debian/patches/freebsd_support 2015-08-31 18:22:15.000000000 +0000 +++ libindi-1.1.0/debian/patches/freebsd_support 2016-01-18 15:06:38.000000000 +0000 @@ -1,7 +1,7 @@ -Index: libindi-1.0.0/cmake_modules/FindUSB-1.cmake +Index: libindi/cmake_modules/FindUSB-1.cmake =================================================================== ---- libindi-1.0.0.orig/cmake_modules/FindUSB-1.cmake 2015-07-08 17:51:51.000000000 +0200 -+++ libindi-1.0.0/cmake_modules/FindUSB-1.cmake 2015-07-08 17:53:21.000000000 +0200 +--- libindi.orig/cmake_modules/FindUSB-1.cmake 2016-01-18 15:14:27.504507896 +0100 ++++ libindi/cmake_modules/FindUSB-1.cmake 2016-01-18 15:14:27.460509736 +0100 @@ -46,16 +46,16 @@ # in cache already set(LIBUSB_FOUND TRUE) @@ -47,10 +47,10 @@ int main() { libusb_error_name(0); return 0; }" ERROR_NAME_COMPILE) if (NOT ERROR_NAME_COMPILE) add_definitions("-DNO_ERROR_NAME") -Index: libindi-1.0.0/libs/indibase/indiusbdevice.h +Index: libindi/libs/indibase/indiusbdevice.h =================================================================== ---- libindi-1.0.0.orig/libs/indibase/indiusbdevice.h 2015-07-08 17:51:51.000000000 +0200 -+++ libindi-1.0.0/libs/indibase/indiusbdevice.h 2015-07-08 17:54:25.000000000 +0200 +--- libindi.orig/libs/indibase/indiusbdevice.h 2016-01-18 15:14:27.504507896 +0100 ++++ libindi/libs/indibase/indiusbdevice.h 2016-01-18 15:14:27.492508398 +0100 @@ -1,6 +1,6 @@ /******************************************************************************* Copyright(c) 2011 Gerry Rozema. All rights reserved. @@ -68,11 +68,11 @@ #endif #include "indibase.h" -Index: libindi-1.0.0/CMakeLists.txt +Index: libindi/CMakeLists.txt =================================================================== ---- libindi-1.0.0.orig/CMakeLists.txt 2015-07-08 17:51:51.000000000 +0200 -+++ libindi-1.0.0/CMakeLists.txt 2015-07-08 17:51:51.000000000 +0200 -@@ -77,6 +77,7 @@ +--- libindi.orig/CMakeLists.txt 2016-01-18 15:14:27.504507896 +0100 ++++ libindi/CMakeLists.txt 2016-01-18 15:14:27.500508063 +0100 +@@ -78,6 +78,7 @@ include_directories(${CFITSIO_INCLUDE_DIR}) endif (CFITSIO_FOUND) diff -Nru libindi-1.0.0/Doxyfile libindi-1.1.0/Doxyfile --- libindi-1.0.0/Doxyfile 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/Doxyfile 2015-09-06 13:17:35.000000000 +0000 @@ -820,7 +820,6 @@ EXCLUDE = /home/jasem/Projects/indi/trunk/libindi/drivers \ /home/jasem/Projects/indi/trunk/libindi/tools \ - /home/jasem/Projects/indi/trunk/libindi/libs/webcam \ /home/jasem/Projects/indi/trunk/libindi/libs/base64.c \ /home/jasem/Projects/indi/trunk/libindi/libs/fq.c \ /home/jasem/Projects/indi/trunk/libindi/indidrivermain.c \ diff -Nru libindi-1.0.0/drivers/agent/agent_imager.cpp libindi-1.1.0/drivers/agent/agent_imager.cpp --- libindi-1.0.0/drivers/agent/agent_imager.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/agent/agent_imager.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -425,6 +425,11 @@ void Imager::removeProperty(INDI::Property *property) { } +void Imager::removeDevice(INDI::BaseDevice *dp) +{ + +} + void Imager::newBLOB(IBLOB *bp) { if (ProgressNP.s == IPS_BUSY) { char name[128]; diff -Nru libindi-1.0.0/drivers/agent/agent_imager.h libindi-1.1.0/drivers/agent/agent_imager.h --- libindi-1.0.0/drivers/agent/agent_imager.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/agent/agent_imager.h 2015-09-06 13:17:35.000000000 +0000 @@ -120,6 +120,7 @@ virtual void newDevice(INDI::BaseDevice *dp); virtual void newProperty(INDI::Property *property); virtual void removeProperty(INDI::Property *property); + virtual void removeDevice(INDI::BaseDevice *dp); virtual void newBLOB(IBLOB *bp); virtual void newSwitch(ISwitchVectorProperty *svp); virtual void newNumber(INumberVectorProperty *nvp); @@ -130,4 +131,4 @@ virtual void serverDisconnected(int exit_code); }; -#endif \ No newline at end of file +#endif diff -Nru libindi-1.0.0/drivers/auxiliary/gps_simulator.cpp libindi-1.1.0/drivers/auxiliary/gps_simulator.cpp --- libindi-1.0.0/drivers/auxiliary/gps_simulator.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/gps_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,138 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + Simple GPS Simulator + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#include +#include +#include + +#include "gps_simulator.h" + +// We declare an auto pointer to GPSSimulator. +std::auto_ptr gpsSimulator(0); + +void ISInit() +{ + static int isInit =0; + + if (isInit == 1) + return; + + isInit = 1; + if(gpsSimulator.get() == 0) gpsSimulator.reset(new GPSSimulator()); + +} + +void ISGetProperties(const char *dev) +{ + ISInit(); + gpsSimulator->ISGetProperties(dev); +} + +void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) +{ + ISInit(); + gpsSimulator->ISNewSwitch(dev, name, states, names, num); +} + +void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) +{ + ISInit(); + gpsSimulator->ISNewText(dev, name, texts, names, num); +} + +void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) +{ + ISInit(); + gpsSimulator->ISNewNumber(dev, name, values, names, num); +} + +void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + INDI_UNUSED(dev); + INDI_UNUSED(name); + INDI_UNUSED(sizes); + INDI_UNUSED(blobsizes); + INDI_UNUSED(blobs); + INDI_UNUSED(formats); + INDI_UNUSED(names); + INDI_UNUSED(n); +} +void ISSnoopDevice (XMLEle *root) +{ + INDI_UNUSED(root); +} + + +GPSSimulator::GPSSimulator() +{ + setVersion(1,0); +} + +GPSSimulator::~GPSSimulator() +{ + +} + +const char * GPSSimulator::getDefaultName() +{ + return (char *)"GPS Simulator"; +} + +bool GPSSimulator::Connect() +{ + return true; +} + +bool GPSSimulator::Disconnect() +{ + return true; +} + +IPState GPSSimulator::updateGPS() +{ + static char ts[32]; + struct tm *utc, *local; + + time_t raw_time; + time(&raw_time); + + utc = gmtime(&raw_time); + strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", utc); + IUSaveText(&TimeT[0], ts); + + local= localtime(&raw_time); + snprintf(ts, sizeof(ts), "%4.2f", (local->tm_gmtoff/3600.0)); + IUSaveText(&TimeT[1], ts); + + TimeTP.s = IPS_OK; + + LocationN[LOCATION_LATITUDE].value = 29.1; + LocationN[LOCATION_LONGITUDE].value = 48.5; + LocationN[LOCATION_ELEVATION].value = 12; + + LocationNP.s = IPS_OK; + + return IPS_OK; +} + diff -Nru libindi-1.0.0/drivers/auxiliary/gps_simulator.h libindi-1.1.0/drivers/auxiliary/gps_simulator.h --- libindi-1.0.0/drivers/auxiliary/gps_simulator.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/gps_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,47 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + Simple GPS Simulator + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#ifndef GPSSIMULATOR_H +#define GPSSIMULATOR_H + +#include "indigps.h" + +class GPSSimulator : public INDI::GPS +{ + public: + GPSSimulator(); + virtual ~GPSSimulator(); + + protected: + + // Generic indi device entries + bool Connect(); + bool Disconnect(); + const char *getDefaultName(); + + IPState updateGPS(); + +}; + +#endif // GPSSIMULATOR_H diff -Nru libindi-1.0.0/drivers/auxiliary/gpusb.cpp libindi-1.1.0/drivers/auxiliary/gpusb.cpp --- libindi-1.0.0/drivers/auxiliary/gpusb.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/gpusb.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -315,7 +315,7 @@ } -bool GPUSB::GuideNorth(float ms) +IPState GPUSB::GuideNorth(float ms) { RemoveTimer(NStimerID); @@ -333,7 +333,7 @@ usleep(ms*1000); driver->stopPulse(GPUSB_NORTH); - return true; + return IPS_OK; } NSPulseRequest=ms/1000.0; @@ -343,13 +343,11 @@ NStimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } -bool GPUSB::GuideSouth(float ms) +IPState GPUSB::GuideSouth(float ms) { - - RemoveTimer(NStimerID); driver->startPulse(GPUSB_SOUTH); @@ -364,7 +362,7 @@ usleep(ms*1000); driver->stopPulse(GPUSB_SOUTH); - return true; + return IPS_OK; } NSPulseRequest=ms/1000.0; @@ -374,14 +372,11 @@ NStimerID = SetTimer(ms-50); - return true; - + return IPS_BUSY; } -bool GPUSB::GuideEast(float ms) +IPState GPUSB::GuideEast(float ms) { - - RemoveTimer(WEtimerID); driver->startPulse(GPUSB_EAST); @@ -396,7 +391,7 @@ usleep(ms*1000); driver->stopPulse(GPUSB_EAST); - return true; + return IPS_OK; } WEPulseRequest=ms/1000.0; @@ -405,10 +400,10 @@ WEtimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } -bool GPUSB::GuideWest(float ms) +IPState GPUSB::GuideWest(float ms) { RemoveTimer(WEtimerID); @@ -425,7 +420,7 @@ usleep(ms*1000); driver->stopPulse(GPUSB_WEST); - return true; + return IPS_OK; } WEPulseRequest=ms/1000.0; @@ -435,6 +430,6 @@ WEtimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } diff -Nru libindi-1.0.0/drivers/auxiliary/gpusb.h libindi-1.1.0/drivers/auxiliary/gpusb.h --- libindi-1.0.0/drivers/auxiliary/gpusb.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/gpusb.h 2015-09-06 13:17:35.000000000 +0000 @@ -64,10 +64,10 @@ void TimerHit(); - virtual bool GuideNorth(float ms); - virtual bool GuideSouth(float ms); - virtual bool GuideEast(float ms); - virtual bool GuideWest(float ms); + virtual IPState GuideNorth(float ms); + virtual IPState GuideSouth(float ms); + virtual IPState GuideEast(float ms); + virtual IPState GuideWest(float ms); private: diff -Nru libindi-1.0.0/drivers/auxiliary/joystickdriver.cpp libindi-1.1.0/drivers/auxiliary/joystickdriver.cpp --- libindi-1.0.0/drivers/auxiliary/joystickdriver.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/joystickdriver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -108,6 +108,7 @@ void* JoyStickDriver::loop(void *obj) { while (reinterpret_cast(obj)->active) reinterpret_cast(obj)->readEv(); + return obj; } void JoyStickDriver::readEv() diff -Nru libindi-1.0.0/drivers/auxiliary/STAR2000.cpp libindi-1.1.0/drivers/auxiliary/STAR2000.cpp --- libindi-1.0.0/drivers/auxiliary/STAR2000.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/STAR2000.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -218,6 +218,7 @@ bool STAR2000::saveConfigItems(FILE *fp) { IUSaveConfigText(fp, &PortTP); + return(true); } float STAR2000::CalcWEPulseTimeLeft() @@ -342,7 +343,7 @@ } -bool STAR2000::GuideNorth(float ms) +IPState STAR2000::GuideNorth(float ms) { RemoveTimer(NStimerID); @@ -360,7 +361,7 @@ StopPulse(NORTH); - return true; + return IPS_OK; } NSPulseRequest=ms/1000.0; @@ -369,10 +370,10 @@ NStimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } -bool STAR2000::GuideSouth(float ms) +IPState STAR2000::GuideSouth(float ms) { RemoveTimer(NStimerID); @@ -388,7 +389,7 @@ StopPulse(SOUTH); - return true; + return IPS_OK; } NSPulseRequest=ms/1000.0; @@ -397,11 +398,11 @@ NStimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } -bool STAR2000::GuideEast(float ms) +IPState STAR2000::GuideEast(float ms) { RemoveTimer(WEtimerID); @@ -417,7 +418,7 @@ StopPulse(EAST); - return true; + return IPS_OK; } WEPulseRequest=ms/1000.0; @@ -426,10 +427,10 @@ WEtimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } -bool STAR2000::GuideWest(float ms) +IPState STAR2000::GuideWest(float ms) { RemoveTimer(WEtimerID); @@ -445,7 +446,7 @@ StopPulse(WEST); - return true; + return IPS_OK; } WEPulseRequest=ms/1000.0; @@ -454,5 +455,5 @@ WEtimerID = SetTimer(ms-50); - return true; + return IPS_BUSY; } diff -Nru libindi-1.0.0/drivers/auxiliary/STAR2000.h libindi-1.1.0/drivers/auxiliary/STAR2000.h --- libindi-1.0.0/drivers/auxiliary/STAR2000.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/auxiliary/STAR2000.h 2015-09-06 13:17:35.000000000 +0000 @@ -65,10 +65,10 @@ void TimerHit(); - virtual bool GuideNorth(float ms); - virtual bool GuideSouth(float ms); - virtual bool GuideEast(float ms); - virtual bool GuideWest(float ms); + virtual IPState GuideNorth(float ms); + virtual IPState GuideSouth(float ms); + virtual IPState GuideEast(float ms); + virtual IPState GuideWest(float ms); /* STAR2000 box RS232 port */ diff -Nru libindi-1.0.0/drivers/ccd/ccd_simulator.cpp libindi-1.1.0/drivers/ccd/ccd_simulator.cpp --- libindi-1.0.0/drivers/ccd/ccd_simulator.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/ccd/ccd_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -116,7 +116,6 @@ raPE=RA; decPE=Dec; - // sxvh9 bias=1500; maxnoise=20; maxval=65000; @@ -124,14 +123,14 @@ minpix =65000; limitingmag=11.5; saturationmag=2; - focallength=1280; // focal length of the telescope in millimeters - guider_focallength=1280; + FocalLength=1280; // focal length of the telescope in millimeters OAGoffset=0; // An oag is offset this much from center of scope position (arcminutes); skyglow=40; seeing=3.5; // fwhm of our stars ImageScalex=1.0; // preset with a valid non-zero ImageScaley=1.0; + rotationCW = 0; time(&RunStart); // Our PEPeriod is 8 minutes @@ -171,6 +170,7 @@ OAGoffset=SimulatorSettingsN[10].value; // An oag is offset this much from center of scope position (arcminutes); polarError=SimulatorSettingsN[11].value; polarDrift=SimulatorSettingsN[12].value; + rotationCW=SimulatorSettingsN[13].value; nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8; nbuf += 512; @@ -219,7 +219,8 @@ IUFillNumber(&SimulatorSettingsN[10],"SIM_OAGOFFSET","Oag Offset (arcminutes)","%4.1f",0,6000,0,0); IUFillNumber(&SimulatorSettingsN[11],"SIM_POLAR","PAE (arcminutes)","%4.1f",-600,600,0,0); /* PAE = Polar Alignment Error */ IUFillNumber(&SimulatorSettingsN[12],"SIM_POLARDRIFT","PAE Drift (minutes)","%4.1f",0,6000,0,0); - IUFillNumberVector(SimulatorSettingsNV,SimulatorSettingsN,13,getDeviceName(),"SIMULATOR_SETTINGS","Simulator Settings","Simulator Config",IP_RW,60,IPS_IDLE); + IUFillNumber(&SimulatorSettingsN[13],"SIM_ROTATION","Rotation CW (degrees)","%4.1f",-360,360,0,0); + IUFillNumberVector(SimulatorSettingsNV,SimulatorSettingsN,14,getDeviceName(),"SIMULATOR_SETTINGS","Simulator Settings","Simulator Config",IP_RW,60,IPS_IDLE); IUFillSwitch(&TimeFactorS[0],"1X","Actual Time",ISS_ON); IUFillSwitch(&TimeFactorS[1],"10X","10x",ISS_OFF); @@ -229,12 +230,6 @@ IUFillNumber(&FWHMN[0],"SIM_FWHM","FWHM (arcseconds)","%4.2f",0,60,0,7.5); IUFillNumberVector(&FWHMNP,FWHMN,1,ActiveDeviceT[1].text, "FWHM","FWHM",OPTIONS_TAB,IP_RO,60,IPS_IDLE); - IUFillNumber(&ScopeParametersN[0],"TELESCOPE_APERTURE","Aperture (mm)","%g",50,4000,0,0.0); - IUFillNumber(&ScopeParametersN[1],"TELESCOPE_FOCAL_LENGTH","Focal Length (mm)","%g",100,10000,0,0.0 ); - IUFillNumber(&ScopeParametersN[2],"GUIDER_APERTURE","Guider Aperture (mm)","%g",50,4000,0,0.0); - IUFillNumber(&ScopeParametersN[3],"GUIDER_FOCAL_LENGTH","Guider Focal Length (mm)","%g",100,10000,0,0.0 ); - IUFillNumberVector(&ScopeParametersNP,ScopeParametersN,4,ActiveDeviceT[0].text,"TELESCOPE_INFO","Scope Properties",OPTIONS_TAB,IP_RW,60,IPS_OK); - IUFillSwitch(&CoolerS[0], "COOLER_ON", "ON", ISS_OFF); IUFillSwitch(&CoolerS[1], "COOLER_OFF", "OFF", ISS_ON); IUFillSwitchVector(&CoolerSP, CoolerS, 2, getDeviceName(), "CCD_COOLER", "Cooler", MAIN_CONTROL_TAB, IP_WO, ISR_1OFMANY, 0, IPS_IDLE); @@ -244,7 +239,6 @@ IUFillNumberVector(&EqPENP,EqPEN,2,ActiveDeviceT[0].text,"EQUATORIAL_PE","EQ PE","Main Control",IP_RW,60,IPS_IDLE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_PE"); - IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[1].text,"FWHM"); initFilterProperties(getDeviceName(), FILTER_TAB); @@ -513,15 +507,11 @@ ptr=(unsigned short int *) targetChip->getFrameBuffer(); if (targetChip->getXRes() == 500) - { - targetFocalLength = guider_focallength; ExposureTime = GuideExposureRequest; - } else - { - targetFocalLength = focallength; ExposureTime = ExposureRequest; - } + + targetFocalLength = FocalLength; if(ShowStarField) { @@ -568,38 +558,42 @@ // the standard co-ordinates on each star for drawing // a ccd frame; double pa,pb,pc,pd,pe,pf; - // Since this is a simple ccd, correctly aligned - // for now we cheat - // no offset or rotation for and y axis means - pb=0.0; - nwidth = targetChip->getXRes() / targetChip->getBinX(); - pc=nwidth/2; - pd=0.0; + // Pixels per radian + double pprx, ppry; + // Scale in arcsecs per pixel + double Scalex; + double Scaley; + + // Pixels per radian + pprx = targetFocalLength/targetChip->getPixelSizeX()*1000/targetChip->getBinX(); + ppry = targetFocalLength/targetChip->getPixelSizeY()*1000/targetChip->getBinY(); - nheight = targetChip->getYRes() / targetChip->getBinY(); - pf=nheight/2; - // and we do a simple scale for x and y locations + // we do a simple scale for x and y locations // based on the focal length and pixel size // focal length in mm, pixels in microns - pa=targetFocalLength/targetChip->getPixelSizeX()*1000/targetChip->getBinX(); - pe=targetFocalLength/targetChip->getPixelSizeY()*1000/targetChip->getBinY(); + // JM: 2015-03-17: Using a simpler formula, Scalex and Scaley are in arcsecs/pixel + Scalex=(targetChip->getPixelSizeX() / targetFocalLength) * 206.3 * targetChip->getBinX(); + Scaley=(targetChip->getPixelSizeY() / targetFocalLength) * 206.3 * targetChip->getBinY(); + + double theta = rotationCW + 180; + if (theta > 360) + theta -=360; + else if (theta < -360) + theta += 360; + + // JM: 2015-03-17: Next we do a rotation assuming CW for angle theta + pa=pprx*cos(theta*M_PI/180.0); + pb=ppry*sin(theta*M_PI/180.0); - //IDLog("Focal length is %6.4f Pixels are %4.2f %4.2f pa %6.4f pe %6.4f\n",targetFocalLength, - // targetChip->getPixelSizeX(), targetChip->getPixelSizeY(),pa,pe); + pd=pprx*-sin(theta*M_PI/180.0); + pe=ppry*cos(theta*M_PI/180.0); - // these numbers are now pixels per radian - float Scalex; - float Scaley; - Scalex=pa*0.0174532925; // pixels per degree - Scalex=Scalex/3600.0; // pixels per arcsecond - Scalex=1.0/Scalex; // arcseconds per pixel - - Scaley=pe*0.0174532925; // pixels per degree - Scaley=Scaley/3600.0; // pixels per arcsecond - Scaley=1.0/Scaley; // arcseconds per pixel - //qq=qq/3600; // arcseconds per pixel + nwidth = targetChip->getXRes() / targetChip->getBinX(); + pc=nwidth/2; + + nheight = targetChip->getYRes() / targetChip->getBinY(); + pf=nheight/2; - //IDLog("Pixel scale is %4.2f x %4.2f\n",Scalex,Scaley); ImageScalex=Scalex; ImageScaley=Scaley; @@ -976,7 +970,7 @@ return drew; } -bool CCDSim::GuideNorth(float v) +IPState CCDSim::GuideNorth(float v) { float c; @@ -984,9 +978,10 @@ c=c/3600; decPE=decPE+c; - return true; + return IPS_OK; } -bool CCDSim::GuideSouth(float v) + +IPState CCDSim::GuideSouth(float v) { float c; @@ -994,10 +989,10 @@ c=c/3600; decPE=decPE-c; - return true; + return IPS_OK; } -bool CCDSim::GuideEast(float v) +IPState CCDSim::GuideEast(float v) { float c; @@ -1006,9 +1001,10 @@ c=c/(cos(decPE*0.0174532925)); raPE=raPE+c; - return true; + return IPS_OK; } -bool CCDSim::GuideWest(float v) + +IPState CCDSim::GuideWest(float v) { float c; @@ -1017,7 +1013,7 @@ c=c/(cos(decPE*0.0174532925)); raPE=raPE-c; - return true; + return IPS_OK; } bool CCDSim::ISNewText( const char *dev, const char *name, char *texts[], char *names[], int n) @@ -1132,11 +1128,9 @@ void CCDSim::activeDevicesUpdated() { IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_PE"); - IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[1].text,"FWHM"); strncpy(EqPENP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); - strncpy(ScopeParametersNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); strncpy(FWHMNP.device, ActiveDeviceT[1].text, MAXINDIDEVICE); } @@ -1149,19 +1143,7 @@ if (isDebug()) IDLog("CCD Simulator: New FWHM value of %g\n", seeing); return true; - } - - if (IUSnoopNumber(root,&ScopeParametersNP)==0) - { - focallength = ScopeParametersNP.np[1].value; - guider_focallength = ScopeParametersNP.np[3].value; - if (isDebug()) - { - IDLog("CCD Simulator: New focalLength value of %g\n", focallength); - IDLog("CCD Simulator: New guider_focalLength value of %g\n", guider_focallength); - } - return true; - } + } // We try to snoop EQPEC first, if not found, we snoop regular EQNP if(IUSnoopNumber(root,&EqPENP)==0) diff -Nru libindi-1.0.0/drivers/ccd/ccd_simulator.h libindi-1.1.0/drivers/ccd/ccd_simulator.h --- libindi-1.0.0/drivers/ccd/ccd_simulator.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/ccd/ccd_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -58,10 +58,10 @@ int DrawImageStar(CCDChip *targetChip, float,float,float); int AddToPixel(CCDChip *targetChip, int,int,int); - bool GuideNorth(float); - bool GuideSouth(float); - bool GuideEast(float); - bool GuideWest(float); + IPState GuideNorth(float); + IPState GuideSouth(float); + IPState GuideEast(float); + IPState GuideWest(float); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); @@ -99,9 +99,8 @@ float seeing; float ImageScalex; float ImageScaley; - float focallength; - float guider_focallength; float OAGoffset; + float rotationCW; float TimeFactor; // our zero point calcs used for drawing stars float k; @@ -126,7 +125,7 @@ // And this lives in our simulator settings page INumberVectorProperty *SimulatorSettingsNV; - INumber SimulatorSettingsN[13]; + INumber SimulatorSettingsN[14]; ISwitch TimeFactorS[3]; ISwitchVectorProperty *TimeFactorSV; @@ -138,8 +137,8 @@ INumber FWHMN[1]; // We are going to snoop these from telescope - INumber ScopeParametersN[4]; - INumberVectorProperty ScopeParametersNP; + //INumber ScopeParametersN[4]; + //INumberVectorProperty ScopeParametersNP; INumberVectorProperty EqPENP; INumber EqPEN[2]; diff -Nru libindi-1.0.0/drivers/dome/baader_dome.cpp libindi-1.1.0/drivers/dome/baader_dome.cpp --- libindi-1.0.0/drivers/dome/baader_dome.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/dome/baader_dome.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -106,7 +106,7 @@ { targetAz = 0; - shutterStatus= SHUTTER_UNKNOWN; + shutterState= SHUTTER_UNKNOWN; flapStatus = FLAP_UNKNOWN; simShutterStatus = SHUTTER_CLOSED; simFlapStatus = FLAP_CLOSED; @@ -124,7 +124,8 @@ cap.canAbsMove = true; cap.canRelMove = true; cap.hasShutter = true; - cap.variableSpeed = false; + cap.canPark = true; + cap.hasVariableSpeed = false; SetDomeCapability(&cap); @@ -149,6 +150,8 @@ IUFillSwitch(&DomeFlapS[1],"FLAP_CLOSE","Close",ISS_ON); IUFillSwitchVector(&DomeFlapSP,DomeFlapS,2,getDeviceName(),"DOME_FLAP","Flap",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_OK); + SetParkDataType(PARK_AZ); + addAuxControls(); return true; @@ -170,6 +173,18 @@ if (UpdateFlapStatus()) IDSetSwitch(&DomeFlapSP, NULL); + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(0); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(0); + SetAxis1ParkDefault(0); + } + return true; } @@ -268,7 +283,7 @@ if (CalibrateSP.s == IPS_BUSY) { - AbortDome(); + Abort(); DEBUG(INDI::Logger::DBG_SESSION, "Calibration aborted."); status = DOME_UNKNOWN; CalibrateSP.s = IPS_IDLE; @@ -289,7 +304,7 @@ if (calibrationTarget1 > 360) calibrationTarget1 -= 360; - if (MoveAbsDome(calibrationTarget1) == false) + if (MoveAbs(calibrationTarget1) == false) { CalibrateSP.s = IPS_ALERT; DEBUG(INDI::Logger::DBG_ERROR, "Calibration failue due to dome motion failure."); @@ -454,28 +469,28 @@ if (!strcmp(status, "ope")) { - if (shutterStatus == SHUTTER_MOVING && targetShutter == SHUTTER_OPEN) + if (shutterState == SHUTTER_MOVING && targetShutter == SHUTTER_OPEN) DEBUGF(INDI::Logger::DBG_SESSION, "%s", GetShutterStatusString(SHUTTER_OPENED)); - shutterStatus = SHUTTER_OPENED; + shutterState = SHUTTER_OPENED; DomeShutterS[SHUTTER_OPEN].s = ISS_ON; } else if (!strcmp(status, "clo")) { - if (shutterStatus == SHUTTER_MOVING && targetShutter == SHUTTER_CLOSE) + if (shutterState == SHUTTER_MOVING && targetShutter == SHUTTER_CLOSE) DEBUGF(INDI::Logger::DBG_SESSION, "%s", GetShutterStatusString(SHUTTER_CLOSED)); - shutterStatus = SHUTTER_CLOSED; + shutterState = SHUTTER_CLOSED; DomeShutterS[SHUTTER_CLOSE].s = ISS_ON; } else if (!strcmp(status, "run")) { - shutterStatus = SHUTTER_MOVING; + shutterState = SHUTTER_MOVING; DomeShutterSP.s = IPS_BUSY; } else { - shutterStatus = SHUTTER_UNKNOWN; + shutterState = SHUTTER_UNKNOWN; DomeShutterSP.s = IPS_ALERT; DEBUGF(INDI::Logger::DBG_ERROR, "Unknown Shutter status: %s.", resp); } @@ -659,6 +674,10 @@ DomeAbsPosN[0].value = targetAz; DomeAbsPosNP.s = IPS_OK; DEBUG(INDI::Logger::DBG_SESSION, "Dome reached requested azimuth angle."); + + if (domeState == DOME_PARKING && status != DOME_CALIBRATING) + SetParked(true); + if (DomeGotoSP.s == IPS_BUSY) { DomeGotoSP.s = IPS_OK; @@ -677,14 +696,14 @@ DEBUG(INDI::Logger::DBG_SESSION, "Calibration stage 1 complete. Starting stage 2..."); calibrationTarget2 = DomeAbsPosN[0].value + 2; calibrationStage = CALIBRATION_STAGE2; - MoveAbsDome(calibrationTarget2); + MoveAbs(calibrationTarget2); DomeAbsPosNP.s = IPS_BUSY; } else if (calibrationStage == CALIBRATION_STAGE2) { DEBUGF(INDI::Logger::DBG_SESSION, "Calibration stage 2 complete. Returning to initial position %g...", calibrationStart); calibrationStage = CALIBRATION_STAGE3; - MoveAbsDome(calibrationStart); + MoveAbs(calibrationStart); DomeAbsPosNP.s = IPS_BUSY; } else if (calibrationStage == CALIBRATION_STAGE3) @@ -734,7 +753,7 @@ /************************************************************************************ * * ***********************************************************************************/ -int BaaderDome::MoveAbsDome(double az) +IPState BaaderDome::MoveAbs(double az) { int nbytes_written=0, nbytes_read=0, rc=-1; char errstr[MAXRBUF]; @@ -744,7 +763,7 @@ if (status == DOME_UNKNOWN) { DEBUG(INDI::Logger::DBG_WARNING, "Dome is not calibrated. Please calibrate dome before issuing any commands."); - return -1; + return IPS_ALERT; } targetAz = az; @@ -757,7 +776,7 @@ { tty_error_msg(rc, errstr, MAXRBUF); DEBUGF(INDI::Logger::DBG_ERROR, "%s MoveAbsDome error: %s.", cmd, errstr); - return false; + return IPS_ALERT; } DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); @@ -771,7 +790,7 @@ { tty_error_msg(rc, errstr, MAXRBUF); DEBUGF(INDI::Logger::DBG_ERROR, "MoveAbsDome error: %s.", errstr); - return false; + return IPS_ALERT; } resp[nbytes_read] = '\0'; @@ -779,18 +798,18 @@ DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", resp); if (!strcmp(resp, "d#gotmess")) - return 1; + return IPS_BUSY; else - return -1; + return IPS_ALERT; } /************************************************************************************ * * ***********************************************************************************/ -int BaaderDome::MoveRelDome(DomeDirection dir, double azDiff) +IPState BaaderDome::MoveRel(double azDiff) { - targetAz = DomeAbsPosN[0].value + (azDiff * (dir==DOME_CW ? 1 : -1)); + targetAz = DomeAbsPosN[0].value + azDiff; if (targetAz < DomeAbsPosN[0].min) targetAz += DomeAbsPosN[0].max; @@ -798,34 +817,43 @@ targetAz -= DomeAbsPosN[0].max; // It will take a few cycles to reach final position - return MoveAbsDome(targetAz); + return MoveAbs(targetAz); } /************************************************************************************ * * ***********************************************************************************/ -int BaaderDome::ParkDome() +IPState BaaderDome::Park() { - targetAz = DomeParamN[DOME_PARK].value; + targetAz = GetAxis1Park(); - return MoveAbsDome(targetAz); + return MoveAbs(targetAz); } /************************************************************************************ * * ***********************************************************************************/ -int BaaderDome::HomeDome() +IPState BaaderDome::UnPark() +{ + return IPS_OK; +} + + +/************************************************************************************ + * +* ***********************************************************************************/ +IPState BaaderDome::Home() { targetAz = DomeParamN[DOME_HOME].value; - return MoveAbsDome(targetAz); + return MoveAbs(targetAz); } /************************************************************************************ * * ***********************************************************************************/ -int BaaderDome::ControlDomeShutter(ShutterOperation operation) +IPState BaaderDome::ControlShutter(ShutterOperation operation) { int nbytes_written=0, nbytes_read=0, rc=-1; char errstr[MAXRBUF]; @@ -851,7 +879,7 @@ { tty_error_msg(rc, errstr, MAXRBUF); DEBUGF(INDI::Logger::DBG_ERROR, "%s ControlDomeShutter error: %s.", cmd, errstr); - return false; + return IPS_ALERT; } DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); @@ -866,7 +894,7 @@ { tty_error_msg(rc, errstr, MAXRBUF); DEBUGF(INDI::Logger::DBG_ERROR, "ControlDomeShutter error: %s.", errstr); - return false; + return IPS_ALERT; } resp[nbytes_read] = '\0'; @@ -875,20 +903,20 @@ if (!strcmp(resp, "d#gotmess")) { - shutterStatus = simShutterStatus = SHUTTER_MOVING; - return 1; + shutterState = simShutterStatus = SHUTTER_MOVING; + return IPS_BUSY; } else - return -1; + return IPS_ALERT; } /************************************************************************************ * * ***********************************************************************************/ -bool BaaderDome::AbortDome() +bool BaaderDome::Abort() { DEBUGF(INDI::Logger::DBG_SESSION, "Attempting to abort dome motion by stopping at %g", DomeAbsPosN[0].value); - MoveAbsDome(DomeAbsPosN[0].value); + MoveAbs(DomeAbsPosN[0].value); return true; } @@ -909,6 +937,7 @@ return "Flap is in motion."; break; case FLAP_UNKNOWN: + default: return "Flap status is unknown."; break; } @@ -1118,3 +1147,20 @@ return INDI::Dome::saveConfigItems(fp); } + +/************************************************************************************ + * +* ***********************************************************************************/ +void BaaderDome::SetCurrentPark() +{ + SetAxis1Park(DomeAbsPosN[0].value); +} +/************************************************************************************ + * +* ***********************************************************************************/ + +void BaaderDome::SetDefaultPark() +{ + // By default set position to 90 + SetAxis1Park(90); +} diff -Nru libindi-1.0.0/drivers/dome/baader_dome.h libindi-1.1.0/drivers/dome/baader_dome.h --- libindi-1.0.0/drivers/dome/baader_dome.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/dome/baader_dome.h 2015-09-06 13:17:35.000000000 +0000 @@ -52,12 +52,17 @@ virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveRelDome(DomeDirection dir, double azDiff); - virtual int MoveAbsDome(double az); - virtual int ParkDome(); - virtual int HomeDome(); - virtual int ControlDomeShutter(ShutterOperation operation); - virtual bool AbortDome(); + virtual IPState MoveRel(double azDiff); + virtual IPState MoveAbs(double az); + virtual IPState Home(); + virtual IPState ControlShutter(ShutterOperation operation); + virtual bool Abort(); + + // Parking + virtual IPState Park(); + virtual IPState UnPark(); + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); protected: diff -Nru libindi-1.0.0/drivers/dome/dome_simulator.cpp libindi-1.1.0/drivers/dome/dome_simulator.cpp --- libindi-1.0.0/drivers/dome/dome_simulator.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/dome/dome_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -26,6 +26,7 @@ #include +#include // We declare an auto pointer to domeSim. std::auto_ptr domeSim(0); @@ -103,23 +104,52 @@ cap.canAbsMove = true; cap.canRelMove = true; cap.hasShutter = true; - cap.variableSpeed = false; + cap.canPark = true; + cap.hasVariableSpeed = false; - SetDomeCapability(&cap); + SetDomeCapability(&cap); } +/************************************************************************************ + * +* ***********************************************************************************/ +bool DomeSim::initProperties() +{ + INDI::Dome::initProperties(); + + SetParkDataType(PARK_AZ); + + addAuxControls(); + + return true; +} + bool DomeSim::SetupParms() { targetAz = 0; shutterTimer = SHUTTER_TIMER; DomeAbsPosN[0].value = 0; - DomeParamN[0].value = 90; - DomeParamN[1].value = 90; + + DomeParamN[DOME_HOME].value = 90; + DomeParamN[DOME_AUTOSYNC].value = 5; IDSetNumber(&DomeAbsPosNP, NULL); IDSetNumber(&DomeParamNP, NULL); + + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(90); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(90); + SetAxis1ParkDefault(90); + } + return true; } @@ -174,16 +204,19 @@ DomeAbsPosN[0].value -= DOME_SPEED; } - if (DomeAbsPosN[0].value < DomeAbsPosN[0].min) - DomeAbsPosN[0].value += DomeAbsPosN[0].max; - if (DomeAbsPosN[0].value > DomeAbsPosN[0].max) - DomeAbsPosN[0].value -= DomeAbsPosN[0].max; + DomeAbsPosN[0].value = range360(DomeAbsPosN[0].value); if (fabs(targetAz - DomeAbsPosN[0].value) <= DOME_SPEED) { DomeAbsPosN[0].value = targetAz; DomeAbsPosNP.s = IPS_OK; DEBUG(INDI::Logger::DBG_SESSION, "Dome reached requested azimuth angle."); + + if (domeState == DOME_PARKING) + { + SetParked(true); + } + if (DomeGotoSP.s == IPS_BUSY) { DomeGotoSP.s = IPS_OK; @@ -213,22 +246,40 @@ return; } -int DomeSim::MoveAbsDome(double az) +bool DomeSim::Move(DomeDirection dir, DomeMotionCommand operation) +{ + if (operation == MOTION_START) + { + targetAz = (dir == DOME_CW) ? 1e6 : -1e6; + DomeAbsPosNP.s = IPS_BUSY; + } + else + { + targetAz = 0; + DomeAbsPosNP.s = IPS_IDLE; + } + + IDSetNumber(&DomeAbsPosNP, NULL); + return true; + +} + +IPState DomeSim::MoveAbs(double az) { // Requested position is within one cycle, let's declare it done if (fabs(az - DomeAbsPosN[0].value) < DOME_SPEED) - return 0; + return IPS_OK; targetAz = az; // It will take a few cycles to reach final position - return 1; + return IPS_BUSY; } -int DomeSim::MoveRelDome(DomeDirection dir, double azDiff) +IPState DomeSim::MoveRel(double azDiff) { - targetAz = DomeAbsPosN[0].value + (azDiff * (dir==DOME_CW ? 1 : -1)); + targetAz = DomeAbsPosN[0].value + azDiff;; if (targetAz < DomeAbsPosN[0].min) targetAz += DomeAbsPosN[0].max; @@ -237,35 +288,41 @@ // Requested position is within one cycle, let's declare it done if (fabs(targetAz - DomeAbsPosN[0].value) < DOME_SPEED) - return 0; + return IPS_OK; // It will take a few cycles to reach final position - return 1; + return IPS_BUSY; } -int DomeSim::ParkDome() +IPState DomeSim::Park() { targetAz = DomeParamN[1].value; - DomeAbsPosNP.s = IPS_BUSY; - return 1; + domeState = DOME_PARKING; + return MoveAbs(GetAxis1Park()); } -int DomeSim::HomeDome() +IPState DomeSim::UnPark() +{ + domeState = DOME_IDLE; + return IPS_OK; +} + +IPState DomeSim::Home() { targetAz = DomeParamN[0].value; DomeAbsPosNP.s = IPS_BUSY; - return 1; + return IPS_BUSY; } -int DomeSim::ControlDomeShutter(ShutterStatus operation) +IPState DomeSim::ControlShutter(ShutterStatus operation) { INDI_UNUSED(operation); shutterTimer = SHUTTER_TIMER; - return 1; + return IPS_BUSY; } -bool DomeSim::AbortDome() +bool DomeSim::Abort() { DomeAbsPosNP.s = IPS_IDLE; IDSetNumber(&DomeAbsPosNP, NULL); @@ -274,7 +331,7 @@ { IUResetSwitch(&DomeGotoSP); DomeGotoSP.s = IPS_IDLE; - IDSetSwitch(&DomeGotoSP, "Dome goto aborted."); + IDSetSwitch(&DomeGotoSP, "Dome Goto aborted."); } // If we abort while in the middle of opening/closing shutter, alert. @@ -287,3 +344,15 @@ return true; } + +void DomeSim::SetCurrentPark() +{ + SetAxis1Park(DomeAbsPosN[0].value); +} + +void DomeSim::SetDefaultPark() +{ + // By default set position to 90 + SetAxis1Park(90); +} + diff -Nru libindi-1.0.0/drivers/dome/dome_simulator.h libindi-1.1.0/drivers/dome/dome_simulator.h --- libindi-1.0.0/drivers/dome/dome_simulator.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/dome/dome_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -33,6 +33,7 @@ DomeSim(); virtual ~DomeSim(); + virtual bool initProperties(); const char *getDefaultName(); bool updateProperties(); @@ -41,12 +42,18 @@ void TimerHit(); - virtual int MoveRelDome(DomeDirection dir, double azDiff); - virtual int MoveAbsDome(double az); - virtual int ParkDome(); - virtual int HomeDome(); - virtual int ControlDomeShutter(ShutterStatus operation); - virtual bool AbortDome(); + virtual bool Move(DomeDirection dir, DomeMotionCommand operation); + virtual IPState MoveRel(double azDiff); + virtual IPState MoveAbs(double az); + virtual IPState Park(); + virtual IPState UnPark(); + virtual IPState Home(); + virtual IPState ControlShutter(ShutterStatus operation); + virtual bool Abort(); + + // Parking + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); protected: private: diff -Nru libindi-1.0.0/drivers/focuser/99-perfectstar.rules libindi-1.1.0/drivers/focuser/99-perfectstar.rules --- libindi-1.0.0/drivers/focuser/99-perfectstar.rules 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/99-perfectstar.rules 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1 @@ +SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f812", GROUP="plugdev", MODE="0666" diff -Nru libindi-1.0.0/drivers/focuser/focuslynx.cpp libindi-1.1.0/drivers/focuser/focuslynx.cpp --- libindi-1.0.0/drivers/focuser/focuslynx.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/focuslynx.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,2666 @@ +/* + Focus Lynx INDI driver + Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com) + + 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 "focuslynx.h" +#include "indicom.h" + +#include +#include +#include +#include +#include +#include +#include + +#define LYNXFOCUS_MAX_RETRIES 1 +#define LYNXFOCUS_TIMEOUT 2 +#define LYNXFOCUS_MAXBUF 16 +#define LYNXFOCUS_TEMPERATURE_FREQ 20 /* Update every 20 POLLMS cycles. For POLLMS 500ms = 10 seconds freq */ +#define LYNXFOCUS_POSITION_THRESHOLD 5 /* Only send position updates to client if the diff exceeds 5 steps */ + +#define FOCUS_SETTINGS_TAB "Settings" +#define FOCUS_STATUS_TAB "Status" + +#define POLLMS 1000 + +std::auto_ptr lynxDrive(0); + +void ISInit() +{ + static int isInit =0; + + if (isInit == 1) + return; + + isInit = 1; + if(lynxDrive.get() == 0) lynxDrive.reset(new FocusLynx()); +} + +void ISGetProperties(const char *dev) +{ + ISInit(); + lynxDrive->ISGetProperties(dev); +} + +void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) +{ + ISInit(); + lynxDrive->ISNewSwitch(dev, name, states, names, num); +} + +void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) +{ + ISInit(); + lynxDrive->ISNewText(dev, name, texts, names, num); +} + +void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) +{ + ISInit(); + lynxDrive->ISNewNumber(dev, name, values, names, num); +} + +void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + INDI_UNUSED(dev); + INDI_UNUSED(name); + INDI_UNUSED(sizes); + INDI_UNUSED(blobsizes); + INDI_UNUSED(blobs); + INDI_UNUSED(formats); + INDI_UNUSED(names); + INDI_UNUSED(n); +} + +void ISSnoopDevice (XMLEle *root) +{ + ISInit(); + lynxDrive->ISSnoopDevice(root); +} + +FocusLynx::FocusLynx() +{ + + lynxModels["OA"] = "Optec TCF-Lynx 2"; + lynxModels["OB"] = "Optec TCF-Lynx 3"; + lynxModels["OA"] = "Optec TCF-Lynx 2"; + lynxModels["OC"] = "Optec TCF-Lynx 2 with Extended Travel"; + lynxModels["OD"] = "Optec Fast Focus Secondary Focuser"; + lynxModels["OE"] = "Optec TCF-S Classic converted"; + lynxModels["OF"] = "Optec TCF-S3 Classic converted"; + lynxModels["OG"] = "Optec Gemini"; + lynxModels["FA"] = "FocusLynx QuickSync FT Hi-Torque"; + lynxModels["FB"] = "FocusLynx QuickSync FT Hi-Speed"; + lynxModels["FC"] = "FocusLynx QuickSync SV"; + lynxModels["SQ"] = "FeatherTouch Motor Hi-Speed"; + lynxModels["SP"] = "FeatherTouch Motor Hi-Torque"; + lynxModels["SQ"] = "Starlight Instruments - FTM with MicroTouch"; + lynxModels["TA"] = "Televue Focuser"; + + ModelS = NULL; + + focusMoveRequest = 0; + simPosition=0; + + // Can move in Absolute & Relative motions, can AbortFocuser motion, and has variable speed. + FocuserCapability cap; + cap.canAbort=true; + cap.canAbsMove=true; + cap.canRelMove=true; + cap.variableSpeed=false; + + isAbsolute = false; + isSynced = false; + isHoming = false; + + SetFocuserCapability(&cap); + + simStatus[STATUS_MOVING] = ISS_OFF; + simStatus[STATUS_HOMING] = ISS_OFF; + simStatus[STATUS_HOMED] = ISS_OFF; + simStatus[STATUS_FFDETECT] = ISS_OFF; + simStatus[STATUS_TMPPROBE] = ISS_ON; + simStatus[STATUS_REMOTEIO] = ISS_ON; + simStatus[STATUS_HNDCTRL] = ISS_ON; + simStatus[STATUS_REVERSE] = ISS_OFF; + + DBG_FOCUS = INDI::Logger::getInstance().addDebugLevel("Focus Verbose", "FOCUS"); + + //lastPos = 0; + //lastTemperature = 0; +} + +FocusLynx::~FocusLynx() +{ + +} + +bool FocusLynx::initProperties() +{ + INDI::Focuser::initProperties(); + + // Focuser temperature + IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.); + IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE); + + // Enable/Disable temperature compnesation + IUFillSwitch(&TemperatureCompensateS[0], "Enable", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateS[1], "Disable", "", ISS_ON); + IUFillSwitchVector(&TemperatureCompensateSP, TemperatureCompensateS, 2, getDeviceName(), "T. Compensation", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + // Enable/Disable temperature compnesation on start + IUFillSwitch(&TemperatureCompensateOnStartS[0], "Enable", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateOnStartS[1], "Disable", "", ISS_ON); + IUFillSwitchVector(&TemperatureCompensateOnStartSP, TemperatureCompensateOnStartS, 2, getDeviceName(), "T. Compensation @Start", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + // Temperature Coefficient + IUFillNumber(&TemperatureCoeffN[0], "A", "", "%.f", -9999, 9999, 100., 0.); + IUFillNumber(&TemperatureCoeffN[1], "B", "", "%.f", -9999, 9999, 100., 0.); + IUFillNumber(&TemperatureCoeffN[2], "C", "", "%.f", -9999, 9999, 100., 0.); + IUFillNumber(&TemperatureCoeffN[3], "D", "", "%.f", -9999, 9999, 100., 0.); + IUFillNumber(&TemperatureCoeffN[4], "E", "", "%.f", -9999, 9999, 100., 0.); + IUFillNumberVector(&TemperatureCoeffNP, TemperatureCoeffN, 5, getDeviceName(), "T. Coeff", "", FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE); + + // Enable/Disable temperature Mode + IUFillSwitch(&TemperatureCompensateModeS[0], "A", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateModeS[1], "B", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateModeS[2], "C", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateModeS[3], "D", "", ISS_OFF); + IUFillSwitch(&TemperatureCompensateModeS[4], "E", "", ISS_OFF); + IUFillSwitchVector(&TemperatureCompensateModeSP, TemperatureCompensateModeS, 5, getDeviceName(), "Compensate Mode", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Enable/Disable backlash + IUFillSwitch(&BacklashCompensationS[0], "Enable", "", ISS_OFF); + IUFillSwitch(&BacklashCompensationS[1], "Disable", "", ISS_ON); + IUFillSwitchVector(&BacklashCompensationSP, BacklashCompensationS, 2, getDeviceName(), "Backlash Compensation", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + // Backlash Value + IUFillNumber(&BacklashN[0], "Value", "", "%.f", 0, 99, 5., 0.); + IUFillNumberVector(&BacklashNP, BacklashN, 1, getDeviceName(), "Backlash", "", FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE); + + // Max Travel + IUFillNumber(&MaxTravelN[0], "Ticks", "", "%.f", 0, 100000, 0., 0.); + IUFillNumberVector(&MaxTravelNP, MaxTravelN, 1, getDeviceName(), "Max Travel", "", FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE); + + // Reset to Factory setting + IUFillSwitch(&ResetS[0], "Factory", "", ISS_OFF); + IUFillSwitchVector(&ResetSP, ResetS, 1, getDeviceName(), "Reset", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Go to home/center + IUFillSwitch(&GotoS[GOTO_CENTER], "Center", "", ISS_OFF); + IUFillSwitch(&GotoS[GOTO_HOME], "Home", "", ISS_OFF); + IUFillSwitchVector(&GotoSP, GotoS, 2, getDeviceName(), "GOTO", "", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Reverse direction + IUFillSwitch(&ReverseS[0], "Enable", "", ISS_OFF); + IUFillSwitch(&ReverseS[1], "Disable", "", ISS_ON); + IUFillSwitchVector(&ReverseSP, ReverseS, 2, getDeviceName(), "Reverse", "", FOCUS_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + // List all supported models + std::map::iterator iter; + int nModels=1; + ModelS = (ISwitch *) malloc(sizeof(ISwitch)); + IUFillSwitch(ModelS, "ZZ", "--", ISS_ON); + for (iter = lynxModels.begin(); iter != lynxModels.end(); ++iter) + { + ModelS = (ISwitch *) realloc(ModelS, (nModels+1)*sizeof(ISwitch)); + IUFillSwitch(ModelS+nModels, (iter->first).c_str(), (iter->second).c_str(), ISS_OFF); + nModels++; + } + IUFillSwitchVector(&ModelSP, ModelS, nModels, getDeviceName(), "Model", "", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Sync to a particular position + IUFillNumber(&SyncN[0], "Ticks", "", "%.f", 0, 200000, 100., 0.); + IUFillNumberVector(&SyncNP, SyncN, 1, getDeviceName(), "Sync", "", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); + + // Status indicators + IUFillLight(&StatusL[STATUS_MOVING], "Is Moving", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_HOMING], "Is Homing", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_HOMED], "Is Homed", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_FFDETECT], "FF Detect", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_TMPPROBE], "Tmp Probe", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_REMOTEIO], "Remote IO", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_HNDCTRL], "Hnd Ctrl", "", IPS_IDLE); + IUFillLight(&StatusL[STATUS_REVERSE], "Reverse", "", IPS_IDLE); + IUFillLightVector(&StatusLP, StatusL, 8, getDeviceName(), "Status", "", FOCUS_STATUS_TAB, IPS_IDLE); + + //simPosition = FocusAbsPosN[0].value; + addAuxControls(); + + return true; + +} + +void FocusLynx::ISGetProperties(const char *dev) +{ + if(dev && strcmp(dev,getDeviceName())) + return; + + INDI::Focuser::ISGetProperties(dev); + + defineSwitch(&ModelSP); + + loadConfig(true, "Models"); +} + +bool FocusLynx::updateProperties() +{ + INDI::Focuser::updateProperties(); + + if (isConnected()) + { + // If focuser is relative, we define SYNC command. + if (isAbsolute == false) + defineNumber(&SyncNP); + + defineNumber(&TemperatureNP); + defineNumber(&TemperatureCoeffNP); + defineSwitch(&TemperatureCompensateModeSP); + defineSwitch(&TemperatureCompensateSP); + defineSwitch(&TemperatureCompensateOnStartSP); + + defineSwitch(&BacklashCompensationSP); + defineNumber(&BacklashNP); + + if (isAbsolute == false) + defineNumber(&MaxTravelNP); + + defineSwitch(&ResetSP); + + // If focuser is relative, we only exposure "Center" command as it cannot home + if (isAbsolute == false) + GotoSP.nsp = 1; + + defineSwitch(&GotoSP); + defineSwitch(&ReverseSP); + + defineLight(&StatusLP); + + if (getFocusConfig()) + DEBUG(INDI::Logger::DBG_SESSION, "FocusLynx paramaters updated, focuser ready for use."); + else + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to retrieve focuser configuration settings..."); + return false; + } + } + else + { + if (isAbsolute == false) + deleteProperty(SyncNP.name); + + deleteProperty(TemperatureNP.name); + deleteProperty(TemperatureCoeffNP.name); + deleteProperty(TemperatureCompensateModeSP.name); + deleteProperty(TemperatureCompensateSP.name); + deleteProperty(TemperatureCompensateOnStartSP.name); + + deleteProperty(BacklashCompensationSP.name); + deleteProperty(BacklashNP.name); + + if (isAbsolute == false) + deleteProperty(MaxTravelNP.name); + + deleteProperty(ResetSP.name); + deleteProperty(GotoSP.name); + deleteProperty(ReverseSP.name); + + deleteProperty(StatusLP.name); + } + + return true; + +} + +bool FocusLynx::Connect() +{ + int connectrc=0; + char errorMsg[MAXRBUF]; + + configurationComplete = false; + + int modelIndex = IUFindOnSwitchIndex(&ModelSP); + if (modelIndex == 0) + { + DEBUG(INDI::Logger::DBG_ERROR, "You must select a model before establishing connection"); + return false; + } + + if (!isSimulation() && (connectrc = tty_connect(PortT[0].text, 115200, 8, 0, 1, &PortFD)) != TTY_OK) + { + tty_error_msg(connectrc, errorMsg, MAXRBUF); + + DEBUGF(INDI::Logger::DBG_SESSION, "Failed to connect to port %s. Error: %s", PortT[0].text, errorMsg); + + return false; + + } + + if (ack()) + { + DEBUG(INDI::Logger::DBG_SESSION, "FocusLynx is online. Getting focus parameters..."); + setDeviceType(modelIndex); + SetTimer(POLLMS); + return true; + } + + DEBUG(INDI::Logger::DBG_SESSION, "Error retreiving data from FocusLynx, please ensure FocusLynx controller is powered and the port is correct."); + return false; +} + +bool FocusLynx::Disconnect() +{ + if (!isSimulation()) + tty_disconnect(PortFD); + DEBUG(INDI::Logger::DBG_SESSION, "FocusLynx is offline."); + return true; +} + +const char * FocusLynx::getDefaultName() +{ + return "FocusLynx"; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) + { + // Models + if (!strcmp(ModelSP.name, name)) + { + IUUpdateSwitch(&ModelSP, states, names, n); + ModelSP.s = IPS_OK; + IDSetSwitch(&ModelSP, NULL); + if (isConnected()) + DEBUG(INDI::Logger::DBG_SESSION, "Focuser model set. Please disconnect and reconnect now..."); + else + DEBUG(INDI::Logger::DBG_SESSION, "Focuser model set. Please connect now..."); + + const char *focusName = IUFindOnSwitch(&ModelSP)->label; + + // Check if we have absolute or relative focusers + if (strstr(focusName, "TCF") || !strcmp(focusName, "FastFocus")) + { + DEBUG(INDI::Logger::DBG_DEBUG, "Absolute focuser detected."); + isAbsolute = true; + } + else + { + DEBUG(INDI::Logger::DBG_DEBUG, "Relative focuser detected."); + isAbsolute = false; + } + + return true; + } + + // Temperature Compensation + if (!strcmp(TemperatureCompensateSP.name, name)) + { + int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateSP); + IUUpdateSwitch(&TemperatureCompensateSP, states, names, n); + if (setTemperatureCompensation(TemperatureCompensateS[0].s == ISS_ON)) + { + TemperatureCompensateSP.s = IPS_OK; + } + else + { + IUResetSwitch(&TemperatureCompensateSP); + TemperatureCompensateSP.s = IPS_ALERT; + TemperatureCompensateS[prevIndex].s = ISS_ON; + } + + IDSetSwitch(&TemperatureCompensateSP, NULL); + return true; + } + + // Temperature Compensation on Start + if (!strcmp(TemperatureCompensateOnStartSP.name, name)) + { + int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateOnStartSP); + IUUpdateSwitch(&TemperatureCompensateOnStartSP, states, names, n); + if (setTemperatureCompensationOnStart(TemperatureCompensateOnStartS[0].s == ISS_ON)) + { + TemperatureCompensateOnStartSP.s = IPS_OK; + } + else + { + IUResetSwitch(&TemperatureCompensateOnStartSP); + TemperatureCompensateOnStartSP.s = IPS_ALERT; + TemperatureCompensateOnStartS[prevIndex].s = ISS_ON; + } + + IDSetSwitch(&TemperatureCompensateOnStartSP, NULL); + return true; + } + + // Temperature Compensation Mode + if (!strcmp(TemperatureCompensateModeSP.name, name)) + { + int prevIndex = IUFindOnSwitchIndex(&TemperatureCompensateModeSP); + IUUpdateSwitch(&TemperatureCompensateModeSP, states, names, n); + char mode = IUFindOnSwitchIndex(&TemperatureCompensateModeSP) + 'A'; + if (setTemperatureCompensationMode(mode)) + { + TemperatureCompensateModeSP.s = IPS_OK; + } + else + { + IUResetSwitch(&TemperatureCompensateModeSP); + TemperatureCompensateModeSP.s = IPS_ALERT; + TemperatureCompensateModeS[prevIndex].s = ISS_ON; + } + + IDSetSwitch(&TemperatureCompensateModeSP, NULL); + return true; + } + + // Backlash enable/disable + if (!strcmp(BacklashCompensationSP.name, name)) + { + int prevIndex = IUFindOnSwitchIndex(&BacklashCompensationSP); + IUUpdateSwitch(&BacklashCompensationSP, states, names, n); + if (setBacklashCompensation(BacklashCompensationS[0].s == ISS_ON)) + { + BacklashCompensationSP.s = IPS_OK; + } + else + { + IUResetSwitch(&BacklashCompensationSP); + BacklashCompensationSP.s = IPS_ALERT; + BacklashCompensationS[prevIndex].s = ISS_ON; + } + + IDSetSwitch(&BacklashCompensationSP, NULL); + return true; + } + + // Reset to Factory setting + if (!strcmp(ResetSP.name, name)) + { + IUResetSwitch(&ResetSP); + if (resetFactory()) + ResetSP.s = IPS_OK; + else + ResetSP.s = IPS_ALERT; + + IDSetSwitch(&ResetSP, NULL); + return true; + } + + // Go to home/center + if (!strcmp(GotoSP.name, name)) + { + IUUpdateSwitch(&GotoSP, states, names, n); + + if (GotoS[GOTO_HOME].s == ISS_ON) + { + if (home()) + GotoSP.s = IPS_BUSY; + else + GotoSP.s = IPS_ALERT; + } + else + { + if (center()) + GotoSP.s = IPS_BUSY; + else + GotoSP.s = IPS_ALERT; + } + + IDSetSwitch(&GotoSP, NULL); + return true; + } + + // Reverse Direction + if (!strcmp(ReverseSP.name, name)) + { + IUUpdateSwitch(&ReverseSP, states, names, n); + + if (reverse(ReverseS[0].s == ISS_ON)) + ReverseSP.s = IPS_OK; + else + ReverseSP.s = IPS_ALERT; + + IDSetSwitch(&ReverseSP, NULL); + return true; + } + + } + + return INDI::Focuser::ISNewSwitch(dev, name, states, names, n); +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + + if(strcmp(dev,getDeviceName())==0) + { + // Temperature Coefficient + if (!strcmp(TemperatureCoeffNP.name, name)) + { + IUUpdateNumber(&TemperatureCoeffNP, values, names, n); + for (int i=0; i < n; i++) + { + if (setTemperatureCompensationCoeff('A' + i, TemperatureCoeffN[i].value) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to set temperature coefficeints."); + TemperatureCoeffNP.s = IPS_ALERT; + IDSetNumber(&TemperatureCoeffNP, NULL); + return false; + } + } + + TemperatureCoeffNP.s = IPS_OK; + IDSetNumber(&TemperatureCoeffNP, NULL); + return true; + } + + // Backlash Value + if (!strcmp(BacklashNP.name, name)) + { + IUUpdateNumber(&BacklashNP, values, names, n); + if (setBacklashCompensationSteps(BacklashN[0].value) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to set temperature coefficients."); + BacklashNP.s = IPS_ALERT; + IDSetNumber(&BacklashNP, NULL); + return false; + } + + BacklashNP.s = IPS_OK; + IDSetNumber(&BacklashNP, NULL); + return true; + } + + // Sync + if (!strcmp(SyncNP.name, name)) + { + IUUpdateNumber(&SyncNP, values, names, n); + if (sync(SyncN[0].value) == false) + SyncNP.s = IPS_ALERT; + else + SyncNP.s = IPS_OK; + + IDSetNumber(&SyncNP, NULL); + return true; + } + + // Max Travel + if (!strcmp(MaxTravelNP.name, name)) + { + IUUpdateNumber(&MaxTravelNP, values, names, n); + + if (MaxTravelN[0].value > 0) + { + // If reverse is enabled. + if (ReverseS[0].s == ISS_ON) + { + FocusAbsPosN[0].min = SyncN[0].min = (maxControllerTicks - MaxTravelN[0].value); + FocusAbsPosN[0].max = SyncN[0].max = maxControllerTicks; + FocusAbsPosN[0].step = SyncN[0].step = maxControllerTicks/50.0; + } + // If reverse is disabled + else + { + FocusAbsPosN[0].min = SyncN[0].min = 0; + FocusAbsPosN[0].max = SyncN[0].max = MaxTravelN[0].value; + FocusAbsPosN[0].step = SyncN[0].step = MaxTravelN[0].value/50.0; + } + + FocusRelPosN[0].max = (FocusAbsPosN[0].max-FocusAbsPosN[0].min)/2; + FocusRelPosN[0].step = FocusRelPosN[0].max/100.0; + FocusRelPosN[0].min = 0; + + IUUpdateMinMax(&FocusAbsPosNP); + IUUpdateMinMax(&FocusRelPosNP); + IUUpdateMinMax(&SyncNP); + + DEBUGF(INDI::Logger::DBG_SESSION, "Focuser absolute limits: min (%g) max (%g)", FocusAbsPosN[0].min, FocusAbsPosN[0].max); + } + + MaxTravelNP.s = IPS_OK; + IDSetNumber(&MaxTravelNP, NULL); + return true; + } + } + + return INDI::Focuser::ISNewNumber(dev, name, values, names, n); + +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::ack() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "Optec 2\" TCF-S", 16); + nbytes_read = strlen(response)+1; + } + else + { + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + DEBUGF(INDI::Logger::DBG_SESSION, "%s is detected.", response); + + return true; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::getFocusConfig() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + int nbytes_written=0; + char key[16]; + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "CONFIG1", 16); + nbytes_read = strlen(response)+1; + } + else + { + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (strcmp(response, "CONFIG1")) + return false; + } + + memset(response, 0, sizeof(response)); + + // Nickname + if (isSimulation()) + { + strncpy(response, "Optec 2\" TCF-S\n", 16); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + memset(response, 0, sizeof(response)); + + // Get Max Position + if (isSimulation()) + { + snprintf(response, 32, "Max Pos = %06d\n", 100000); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + uint32_t maxPos=0; + int rc = sscanf(response, "%16[^=]=%d", key, &maxPos); + if (rc == 2) + { + FocusAbsPosN[0].max = SyncN[0].max = maxPos; + FocusAbsPosN[0].step = SyncN[0].step = maxPos/50.0; + FocusAbsPosN[0].min = SyncN[0].min = 0; + + FocusRelPosN[0].max = maxPos/2; + FocusRelPosN[0].step = maxPos/100.0; + FocusRelPosN[0].min = 0; + + IUUpdateMinMax(&FocusAbsPosNP); + IUUpdateMinMax(&FocusRelPosNP); + IUUpdateMinMax(&SyncNP); + + maxControllerTicks = maxPos; + } + else + return false; + + memset(response, 0, sizeof(response)); + + // Get Device Type + if (isSimulation()) + { + snprintf(response, 32, "Dev Typ = %s\n", "OA"); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + // Get Status Parameters + + memset(response, 0, sizeof(response)); + + // Temperature Compensation On? + if (isSimulation()) + { + snprintf(response, 32, "TComp ON = %d\n", TemperatureCompensateS[0].s == ISS_ON ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCompOn; + rc = sscanf(response, "%16[^=]=%d", key, &TCompOn); + if (rc != 2) + return false; + + IUResetSwitch(&TemperatureCompensateSP); + TemperatureCompensateS[0].s = TCompOn ? ISS_ON : ISS_OFF; + TemperatureCompensateS[0].s = TCompOn ? ISS_OFF : ISS_ON; + TemperatureCompensateSP.s = IPS_OK; + IDSetSwitch(&TemperatureCompensateSP, NULL); + + memset(response, 0, sizeof(response)); + + // Temperature Coeff A + if (isSimulation()) + { + snprintf(response, 32, "TempCo A = %d\n", (int) TemperatureCoeffN[FOCUS_A_COEFF].value); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCoeffA; + rc = sscanf(response, "%16[^=]=%d", key, &TCoeffA); + if (rc != 2) + return false; + + TemperatureCoeffN[FOCUS_A_COEFF].value = TCoeffA; + + memset(response, 0, sizeof(response)); + + // Temperature Coeff B + if (isSimulation()) + { + snprintf(response, 32, "TempCo B = %d\n", (int) TemperatureCoeffN[FOCUS_B_COEFF].value); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCoeffB; + rc = sscanf(response, "%16[^=]=%d", key, &TCoeffB); + if (rc != 2) + return false; + + TemperatureCoeffN[FOCUS_B_COEFF].value = TCoeffB; + + memset(response, 0, sizeof(response)); + + // Temperature Coeff C + if (isSimulation()) + { + snprintf(response, 32, "TempCo C = %d\n", (int) TemperatureCoeffN[FOCUS_C_COEFF].value); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCoeffC; + rc = sscanf(response, "%16[^=]=%d", key, &TCoeffC); + if (rc != 2) + return false; + + TemperatureCoeffN[FOCUS_C_COEFF].value = TCoeffC; + + memset(response, 0, sizeof(response)); + + // Temperature Coeff D + if (isSimulation()) + { + snprintf(response, 32, "TempCo D = %d\n", (int) TemperatureCoeffN[FOCUS_D_COEFF].value); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCoeffD; + rc = sscanf(response, "%16[^=]=%d", key, &TCoeffD); + if (rc != 2) + return false; + + TemperatureCoeffN[FOCUS_D_COEFF].value = TCoeffD; + + memset(response, 0, sizeof(response)); + + // Temperature Coeff E + if (isSimulation()) + { + snprintf(response, 32, "TempCo E = %d\n", (int) TemperatureCoeffN[FOCUS_E_COEFF].value); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCoeffE; + rc = sscanf(response, "%16[^=]=%d", key, &TCoeffE); + if (rc != 2) + return false; + + TemperatureCoeffN[FOCUS_E_COEFF].value = TCoeffE; + + TemperatureCoeffNP.s = IPS_OK; + IDSetNumber(&TemperatureCoeffNP, NULL); + + memset(response, 0, sizeof(response)); + + // Temperature Compensation Mode + if (isSimulation()) + { + snprintf(response, 32, "TC Mode = %c\n", 'C'); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + char compensateMode; + rc = sscanf(response, "%16[^=]= %c", key, &compensateMode); + if (rc != 2) + return false; + + IUResetSwitch(&TemperatureCompensateModeSP); + int index = compensateMode - 'A'; + if (index >= 0 && index <= 5) + { + TemperatureCompensateModeS[index].s = ISS_ON; + TemperatureCompensateModeSP.s = IPS_OK; + } + else + { + DEBUGF(INDI::Logger::DBG_ERROR, "Invalid index %d for compensation mode.", index); + TemperatureCompensateModeSP.s = IPS_ALERT; + } + + IDSetSwitch(&TemperatureCompensateModeSP, NULL); + + // Backlash Compensation + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "BLC En = %d\n", BacklashCompensationS[0].s == ISS_ON ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int BLCCompensate; + rc = sscanf(response, "%16[^=]=%d", key, &BLCCompensate); + if (rc != 2) + return false; + + IUResetSwitch(&BacklashCompensationSP); + BacklashCompensationS[0].s = BLCCompensate ? ISS_ON : ISS_OFF; + BacklashCompensationS[1].s = BLCCompensate ? ISS_OFF : ISS_ON; + BacklashCompensationSP.s = IPS_OK; + IDSetSwitch(&BacklashCompensationSP, NULL); + + + // Backlash Value + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "BLC Stps = %d\n", 50); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int BLCValue; + rc = sscanf(response, "%16[^=]=%d", key, &BLCValue); + if (rc != 2) + return false; + + BacklashN[0].value = BLCValue; + BacklashNP.s = IPS_OK; + IDSetNumber(&BacklashNP, NULL); + + // Led brightnesss + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "LED Brt = %d\n", 75); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int LEDBrightness; + rc = sscanf(response, "%16[^=]=%d", key, &LEDBrightness); + if (rc != 2) + return false; + + // Temperature Compensation on Start + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "TC@Start = %d\n", TemperatureCompensateOnStartS[0].s == ISS_ON ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int TCOnStart; + rc = sscanf(response, "%16[^=]=%d", key, &TCOnStart); + if (rc != 2) + return false; + + IUResetSwitch(&TemperatureCompensateOnStartSP); + TemperatureCompensateOnStartS[0].s = TCOnStart ? ISS_ON : ISS_OFF; + TemperatureCompensateOnStartS[1].s = TCOnStart ? ISS_OFF : ISS_ON; + TemperatureCompensateOnStartSP.s = IPS_OK; + IDSetSwitch(&TemperatureCompensateOnStartSP, NULL); + + // Added By Philippe Besson the 28th of June for 'END' evalution + // END is reached + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + strncpy(response, "END\n", 16); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + + // DIsplay the response to be sure to have read the complet TTY Buffer. + // DEBUGF(DBG_FOCUS, "RES (%s)", response); + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (strcmp(response, "END")) + return false; + } + // End of added code by Philippe Besson + + tcflush(PortFD, TCIFLUSH); + + configurationComplete = true; + + return true; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::getFocusStatus() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + int nbytes_written=0; + char key[16]; + + memset(response, 0, sizeof(response)); + + DEBUGF(DBG_FOCUS, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "STATUS1\n", 16); + nbytes_read = strlen(response); + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + if (strcmp(response, "STATUS1")) + return false; + + // Get Temperature + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + strncpy(response, "Temp(C) = +21.7\n", 16); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + float temperature=0; + int rc = sscanf(response, "%16[^=]=%f", key, &temperature); + if (rc == 2) + { + TemperatureN[0].value = temperature; + IDSetNumber(&TemperatureNP, NULL); + } + else + { + char np[8]; + int rc = sscanf(response, "%16[^=]= %s", key, np); + + if (rc != 2 || strcmp(np, "NP")) + { + if (TemperatureNP.s != IPS_ALERT) + { + TemperatureNP.s = IPS_ALERT; + IDSetNumber(&TemperatureNP, NULL); + } + return false; + } + } + + // Get Current Position + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Curr Pos = %06d\n", simPosition); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + uint32_t currPos=0; + rc = sscanf(response, "%16[^=]=%d", key, &currPos); + if (rc == 2) + { + FocusAbsPosN[0].value = currPos; + IDSetNumber(&FocusAbsPosNP, NULL); + } + else + return false; + + // Get Target Position + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Targ Pos = %06d\n", targetPosition); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + // Get Status Parameters + + // #1 is Moving? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Is Moving = %d\n", (simStatus[STATUS_MOVING] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int isMoving; + rc = sscanf(response, "%16[^=]=%d", key, &isMoving); + if (rc != 2) + return false; + + StatusL[STATUS_MOVING].s = isMoving ? IPS_BUSY : IPS_IDLE; + + // #2 is Homing? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Is Homing = %d\n", (simStatus[STATUS_HOMING] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int _isHoming; + rc = sscanf(response, "%16[^=]=%d", key, &_isHoming); + if (rc != 2) + return false; + + StatusL[STATUS_HOMING].s = _isHoming ? IPS_BUSY : IPS_IDLE; + // For relative focusers home is not applicable. + if (isAbsolute == false) + StatusL[STATUS_HOMING].s = IPS_IDLE; + + // We set that isHoming in process, but we don't set it to false here it must be reset in TimerHit + if (StatusL[STATUS_HOMING].s == IPS_BUSY) + isHoming = true; + + // #3 is Homed? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Is Homed = %d\n", (simStatus[STATUS_HOMED] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int isHomed; + rc = sscanf(response, "%16[^=]=%d", key, &isHomed); + if (rc != 2) + return false; + + StatusL[STATUS_HOMED].s = isHomed ? IPS_OK : IPS_IDLE; + // For relative focusers home is not applicable. + if (isAbsolute == false) + StatusL[STATUS_HOMED].s = IPS_IDLE; + + // #4 FF Detected? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "FFDetect = %d\n", (simStatus[STATUS_FFDETECT] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int FFDetect; + rc = sscanf(response, "%16[^=]=%d", key, &FFDetect); + if (rc != 2) + return false; + + StatusL[STATUS_FFDETECT].s = FFDetect ? IPS_OK : IPS_IDLE; + + // #5 Temperature probe? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "TmpProbe = %d\n", (simStatus[STATUS_TMPPROBE] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int TmpProbe; + rc = sscanf(response, "%16[^=]=%d", key, &TmpProbe); + if (rc != 2) + return false; + + StatusL[STATUS_TMPPROBE].s = TmpProbe ? IPS_OK : IPS_IDLE; + + // #6 Remote IO? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "RemoteIO = %d\n", (simStatus[STATUS_REMOTEIO] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int RemoteIO; + rc = sscanf(response, "%16[^=]=%d", key, &RemoteIO); + if (rc != 2) + return false; + + StatusL[STATUS_REMOTEIO].s = RemoteIO ? IPS_OK : IPS_IDLE; + + // #7 Hand controller? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Hnd Ctlr = %d\n", (simStatus[STATUS_HNDCTRL] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int HndCtlr; + rc = sscanf(response, "%16[^=]=%d", key, &HndCtlr); + if (rc != 2) + return false; + + StatusL[STATUS_HNDCTRL].s = HndCtlr ? IPS_OK : IPS_IDLE; + + // #8 Reverse? + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + snprintf(response, 32, "Reverse = %d\n", (simStatus[STATUS_REVERSE] == ISS_ON) ? 1 : 0); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + response[nbytes_read-1] = '\0'; + DEBUGF(DBG_FOCUS, "RES (%s)", response); + + int reverse; + rc = sscanf(response, "%16[^=]=%d", key, &reverse); + if (rc != 2) + return false; + + StatusL[STATUS_REVERSE].s = reverse ? IPS_OK : IPS_IDLE; + + // If reverse is enable and switch shows disabled, let's change that + // same thing is reverse is disabled but switch is enabled + if ( (reverse && ReverseS[1].s == ISS_ON) || (!reverse && ReverseS[0].s == ISS_ON)) + { + IUResetSwitch(&ReverseSP); + ReverseS[0].s = (reverse == 1) ? ISS_ON : ISS_OFF; + ReverseS[1].s = (reverse == 0) ? ISS_ON : ISS_OFF; + IDSetSwitch(&ReverseSP, NULL); + } + + StatusLP.s = IPS_OK; + IDSetLight(&StatusLP, NULL); + + // Added By Philippe Besson the 28th of June for 'END' evalution + // END is reached + memset(response, 0, sizeof(response)); + if (isSimulation()) + { + strncpy(response, "END\n", 16); + nbytes_read = strlen(response); + } + else if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + + // DIsplay the response to be sure to have read the complet TTY Buffer. + // DEBUGF(DBG_FOCUS, "RES (%s)", response); + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (strcmp(response, "END")) + return false; + } + // End of added code by Philippe Besson + + tcflush(PortFD, TCIFLUSH); + + return true; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setDeviceType(int index) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", ModelS[index].name); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response)+1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::home() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "H", 16); + nbytes_read = strlen(response)+1; + simStatus[STATUS_HOMING] = ISS_ON; + targetPosition = 0; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + FocusAbsPosNP.s = IPS_BUSY; + IDSetNumber(&FocusAbsPosNP, NULL); + + isHoming = true; + DEBUG(INDI::Logger::DBG_SESSION, "Focuser moving to home position..."); + + tcflush(PortFD, TCIFLUSH); + + return true; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::center() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + if (isAbsolute == false) + return (MoveAbsFocuser(FocusAbsPosN[0].max/2) != IPS_ALERT); + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "M", 16); + nbytes_read = strlen(response) + 1; + simStatus[STATUS_MOVING] = ISS_ON; + targetPosition = FocusAbsPosN[0].max/2; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + DEBUG(INDI::Logger::DBG_SESSION, "Focuser moving to center position..."); + + FocusAbsPosNP.s = IPS_BUSY; + IDSetNumber(&FocusAbsPosNP, NULL); + + tcflush(PortFD, TCIFLUSH); + + return true; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setTemperatureCompensation(bool enable) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", enable ? 1 : 0); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setTemperatureCompensationMode(char mode) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", mode); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response)+1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setTemperatureCompensationCoeff(char mode, int16_t coeff) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", mode, coeff >= 0 ? '+' : '-', abs(coeff)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setTemperatureCompensationOnStart(bool enable) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", enable ? 1 : 0); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setBacklashCompensation(bool enable) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", enable ? 1 : 0); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + } + else + { + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::setBacklashCompensationSteps(uint16_t steps) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", steps); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + } + else + { + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::reverse(bool enable) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", enable ? 1 : 0); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response) + 1; + simStatus[STATUS_REVERSE] = enable ? ISS_ON : ISS_OFF; + } + else + { + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + return true; + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::sync(uint32_t position) +{ + char cmd[32]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 32, "", position); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + simPosition = position; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return IPS_ALERT; + } + + if (isResponseOK() == false) + return false; + + } + + tcflush(PortFD, TCIFLUSH); + DEBUGF(INDI::Logger::DBG_SESSION, "Setting current position to %d", position); + isSynced=true; + return true; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::resetFactory() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "SET", 16); + nbytes_read = strlen(response)+1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + tcflush(PortFD, TCIFLUSH); + + if (!strcmp(response, "SET")) + { + return true; + getFocusConfig(); + } + else + return false; + } + + return false; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::isResponseOK() +{ + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + + memset(response, 0, sizeof(response)); + + if (isSimulation()) + { + strcpy(response, "!"); + nbytes_read= strlen(response)+1; + } + else + { + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT , &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "TTY error: %s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (response[0] == '!') + return true; + else + { + DEBUGF(INDI::Logger::DBG_ERROR, "Controller error: %s", response); + return false; + } + } +} + +/************************************************************************************ +* +* ***********************************************************************************/ +IPState FocusLynx::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + // Relative focusers must be synced initially. + if (isAbsolute == false && isSynced == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Relative focusers must be synced. Please sync before issuing any motion commands."); + return IPS_ALERT; + } + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 16, "", (dir == FOCUS_INWARD) ? 'I' : 'O', (speed == 0) ? '0' : '1'); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "M", 16); + nbytes_read = strlen(response)+1; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return IPS_ALERT; + } + + if (isResponseOK() == false) + return IPS_ALERT; + + gettimeofday(&focusMoveStart,NULL); + focusMoveRequest = duration/1000.0; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return IPS_ALERT; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (duration <= POLLMS) + { + usleep(POLLMS * 1000); + AbortFocuser(); + return IPS_OK; + } + + tcflush(PortFD, TCIFLUSH); + + return IPS_BUSY; + } + + return IPS_ALERT; + +} + +/************************************************************************************ +* +* ***********************************************************************************/ +IPState FocusLynx::MoveAbsFocuser(uint32_t targetTicks) +{ + char cmd[32]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + // Relative focusers must be synced initially. + if (isAbsolute == false && isSynced == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Relative focusers must be synced. Please sync before issuing any motion commands."); + return IPS_ALERT; + } + + targetPosition = targetTicks; + + memset(response, 0, sizeof(response)); + + snprintf(cmd, 32, "", targetTicks); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "M", 16); + nbytes_read = strlen(response)+1; + simStatus[STATUS_MOVING] = ISS_ON; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return IPS_ALERT; + } + + if (isResponseOK() == false) + return IPS_ALERT; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return IPS_ALERT; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + FocusAbsPosNP.s = IPS_BUSY; + + tcflush(PortFD, TCIFLUSH); + + return IPS_BUSY; + } + + return IPS_ALERT; +} + +/************************************************************************************ +* +* ***********************************************************************************/ +IPState FocusLynx::MoveRelFocuser(FocusDirection dir, uint32_t ticks) +{ + uint32_t newPosition=0; + + // Relative focusers must be synced initially. + if (isAbsolute == false && isSynced == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Relative focusers must be synced. Please sync before issuing any motion commands."); + return IPS_ALERT; + } + + if (dir == FOCUS_INWARD) + newPosition = FocusAbsPosN[0].value - ticks; + else + newPosition = FocusAbsPosN[0].value + ticks; + + return MoveAbsFocuser(newPosition); +} + +void FocusLynx::TimerHit() +{ + if (isConnected() == false) + return; + + if (configurationComplete == false) + { + SetTimer(POLLMS); + return; + } + + bool statusrc=false; + for (int i=0; i < 2; i++) + { + statusrc = getFocusStatus(); + if (statusrc) + break; + } + + if (statusrc == false) + { + DEBUG(INDI::Logger::DBG_WARNING, "Unable to read focuser status...."); + SetTimer(POLLMS); + return; + } + + if (FocusAbsPosNP.s == IPS_BUSY || FocusRelPosNP.s == IPS_BUSY) + { + if (isSimulation()) + { + if (FocusAbsPosN[0].value < targetPosition) + simPosition += 100; + else + simPosition -= 100; + + simStatus[STATUS_MOVING] = ISS_ON; + + if (fabs(simPosition - targetPosition) < 100) + { + FocusAbsPosN[0].value = targetPosition; + simPosition = FocusAbsPosN[0].value; + simStatus[STATUS_MOVING] = ISS_OFF; + StatusL[STATUS_MOVING].s = IPS_IDLE; + if (simStatus[STATUS_HOMING] == ISS_ON) + { + StatusL[STATUS_HOMED].s = IPS_OK; + simStatus[STATUS_HOMING] == ISS_OFF; + } + } + } + + if (isHoming && StatusL[STATUS_HOMED].s == IPS_OK) + { + isHoming = false; + GotoSP.s = IPS_OK; + IUResetSwitch(&GotoSP); + GotoS[GOTO_HOME].s = ISS_ON; + IDSetSwitch(&GotoSP, NULL); + FocusAbsPosNP.s = IPS_OK; + IDSetNumber(&FocusRelPosNP, NULL); + DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached home position."); + } + else if (StatusL[STATUS_MOVING].s == IPS_IDLE) + { + FocusAbsPosNP.s = IPS_OK; + FocusRelPosNP.s = IPS_OK; + IDSetNumber(&FocusAbsPosNP, NULL); + IDSetNumber(&FocusRelPosNP, NULL); + if (GotoSP.s == IPS_BUSY) + { + IUResetSwitch(&GotoSP); + GotoSP.s = IPS_OK; + IDSetSwitch(&GotoSP, NULL); + } + DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached requested position."); + } + else if (StatusL[STATUS_MOVING].s == IPS_BUSY && focusMoveRequest > 0) + { + float remaining = calcTimeLeft(focusMoveStart, focusMoveRequest); + + if (remaining < POLLMS) + { + sleep(remaining); + AbortFocuser(); + focusMoveRequest=0; + } + } + } + + if (StatusL[STATUS_HOMING].s == IPS_BUSY && GotoSP.s != IPS_BUSY) + { + GotoSP.s = IPS_BUSY; + IDSetSwitch(&GotoSP, NULL); + } + + + SetTimer(POLLMS); + +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::AbortFocuser() +{ + char cmd[] = ""; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + memset(response, 0, sizeof(response)); + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (isSimulation()) + { + strncpy(response, "HALTED", 16); + nbytes_read = strlen(response)+1; + simStatus[STATUS_MOVING] = ISS_OFF; + simStatus[STATUS_HOMING] = ISS_OFF; + } + else + { + tcflush(PortFD, TCIFLUSH); + + if ( (errcode = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if (isResponseOK() == false) + return false; + + if ( (errcode = tty_read_section(PortFD, response, 0xA, LYNXFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read-1] = '\0'; + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (FocusRelPosNP.s == IPS_BUSY) + { + FocusRelPosNP.s = IPS_IDLE; + IDSetNumber(&FocusRelPosNP, NULL); + } + + FocusTimerNP.s = FocusAbsPosNP.s = GotoSP.s = IPS_IDLE; + IUResetSwitch(&GotoSP); + IDSetNumber(&FocusTimerNP, NULL); + IDSetNumber(&FocusAbsPosNP, NULL); + IDSetSwitch(&GotoSP, NULL); + + tcflush(PortFD, TCIFLUSH); + + return true; + } + + return false; + +} + +/************************************************************************************ + * +* ***********************************************************************************/ +float FocusLynx::calcTimeLeft(timeval start,float req) +{ + double timesince; + double timeleft; + struct timeval now; + gettimeofday(&now,NULL); + + timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec/1000); + timesince=timesince/1000; + timeleft=req-timesince; + return timeleft; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +bool FocusLynx::saveConfigItems(FILE *fp) +{ + INDI::Focuser::saveConfigItems(fp); + + IUSaveConfigSwitch(fp, &ModelSP); + IUSaveConfigSwitch(fp, &TemperatureCompensateSP); + IUSaveConfigSwitch(fp, &TemperatureCompensateOnStartSP); + IUSaveConfigSwitch(fp, &ReverseSP); + IUSaveConfigNumber(fp, &TemperatureCoeffNP); + IUSaveConfigSwitch(fp, &TemperatureCompensateModeSP); + IUSaveConfigSwitch(fp, &BacklashCompensationSP); + IUSaveConfigNumber(fp, &BacklashNP); + if (isAbsolute == false) + IUSaveConfigNumber(fp, &MaxTravelNP); + + return true; +} + +/************************************************************************************ + * +* ***********************************************************************************/ +void FocusLynx::debugTriggered(bool enable) +{ + //tty_set_debug(enable ? 1 : 0); +} diff -Nru libindi-1.0.0/drivers/focuser/focuslynx.h libindi-1.1.0/drivers/focuser/focuslynx.h --- libindi-1.0.0/drivers/focuser/focuslynx.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/focuslynx.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,176 @@ +/* + Focus Lynx INDI driver + Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com) + + 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 + +*/ + +#ifndef FOCUSLYNX_H +#define FOCUSLYNX_H + +#include +#include "indibase/indifocuser.h" + +class FocusLynx : public INDI::Focuser +{ +public: + FocusLynx(); + ~FocusLynx(); + + enum { FOCUS_A_COEFF, FOCUS_B_COEFF, FOCUS_C_COEFF, FOCUS_D_COEFF, FOCUS_E_COEFF, FOCUS_F_COEFF }; + typedef enum { STATUS_MOVING, STATUS_HOMING, STATUS_HOMED, STATUS_FFDETECT, STATUS_TMPPROBE, STATUS_REMOTEIO, STATUS_HNDCTRL, STATUS_REVERSE, STATUS_UNKNOWN} LYNX_STATUS; + enum { GOTO_CENTER, GOTO_HOME }; + + virtual bool Connect(); + virtual bool Disconnect(); + const char * getDefaultName(); + virtual bool initProperties(); + virtual void ISGetProperties(const char *dev); + virtual bool updateProperties(); + virtual bool saveConfigItems(FILE *fp); + + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual bool AbortFocuser(); + virtual void TimerHit(); + + void debugTriggered(bool enable); + +private: + + int PortFD; + uint32_t simPosition; + uint32_t targetPosition; + uint32_t maxControllerTicks; + uint32_t DBG_FOCUS; + ISState simStatus[8]; + bool simCompensationOn; + bool configurationComplete; + + //double targetPos, lastPos, lastTemperature, simPosition; + //unsigned int currentSpeed, temperaturegetCounter; + + std::map lynxModels; + + struct timeval focusMoveStart; + float focusMoveRequest; + + // Get functions + bool getFocusConfig(); + bool getFocusStatus(); + + // Set functions + + // Device + bool setDeviceType(int index); + + // Position + bool setFocusPosition(u_int16_t position); + + // Temperature + bool setTemperatureCompensation(bool enable); + bool setTemperatureCompensationMode(char mode); + bool setTemperatureCompensationCoeff(char mode, int16_t coeff); + bool setTemperatureCompensationOnStart(bool enable); + + // Backlash + bool setBacklashCompensation(bool enable); + bool setBacklashCompensationSteps(uint16_t steps); + + // Sync + bool sync(uint32_t position); + + // Motion functions + bool stop(); + bool home(); + bool center(); + bool reverse(bool enable); + + // Misc functions + bool ack(); + bool resetFactory(); + float calcTimeLeft(timeval,float); + bool isResponseOK(); + + // Properties + + // Set/Get Temperature + INumber TemperatureN[1]; + INumberVectorProperty TemperatureNP; + + // Enable/Disable temperature compnesation + ISwitch TemperatureCompensateS[2]; + ISwitchVectorProperty TemperatureCompensateSP; + + // Enable/Disable temperature compnesation on start + ISwitch TemperatureCompensateOnStartS[2]; + ISwitchVectorProperty TemperatureCompensateOnStartSP; + + // Temperature Coefficient + INumber TemperatureCoeffN[5]; + INumberVectorProperty TemperatureCoeffNP; + + // Temperature Coefficient Mode + ISwitch TemperatureCompensateModeS[5]; + ISwitchVectorProperty TemperatureCompensateModeSP; + + // Enable/Disable backlash + ISwitch BacklashCompensationS[2]; + ISwitchVectorProperty BacklashCompensationSP; + + // Backlash Value + INumber BacklashN[1]; + INumberVectorProperty BacklashNP; + + // Reset to Factory setting + ISwitch ResetS[1]; + ISwitchVectorProperty ResetSP; + + // Reverse Direction + ISwitch ReverseS[2]; + ISwitchVectorProperty ReverseSP; + + // Go to home/center + ISwitch GotoS[2]; + ISwitchVectorProperty GotoSP; + + // List all supported models + ISwitch *ModelS; + ISwitchVectorProperty ModelSP; + + // Status indicators + ILight StatusL[8]; + ILightVectorProperty StatusLP; + + // Sync to a particular position + INumber SyncN[1]; + INumberVectorProperty SyncNP; + + // Max Travel for relative focusers + INumber MaxTravelN[1]; + INumberVectorProperty MaxTravelNP; + + bool isAbsolute; + bool isSynced; + bool isHoming; + +}; + +#endif // FocusLynx_H diff -Nru libindi-1.0.0/drivers/focuser/focus_simulator.cpp libindi-1.1.0/drivers/focuser/focus_simulator.cpp --- libindi-1.0.0/drivers/focuser/focus_simulator.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/focus_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -137,6 +137,8 @@ IUFillNumberVector(&FWHMNP,FWHMN,1,getDeviceName(), "FWHM","FWHM",MAIN_CONTROL_TAB,IP_RO,60,IPS_IDLE); ticks = initTicks = sqrt(FWHMN[0].value - SeeingN[0].value) / 0.75; + + FocusAbsPosN[0].value = FocusAbsPosN[0].max / 2; return true; } @@ -207,7 +209,7 @@ return INDI::Focuser::ISNewSwitch(dev,name,states,names,n); } -int FocusSim::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState FocusSim::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { double targetTicks = (speed * duration) / (FocusSpeedN[0].max * FocusTimerN[0].max); double plannedTicks=ticks; @@ -226,7 +228,7 @@ if (plannedAbsPos < FocusAbsPosN[0].min || plannedAbsPos > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested position is out of range."); - return -1; + return IPS_ALERT; } ticks = plannedTicks; @@ -244,16 +246,16 @@ IDSetNumber(&FWHMNP, NULL); IDSetNumber(&FocusAbsPosNP, NULL); - return 0; + return IPS_OK; } -int FocusSim::MoveAbsFocuser(int targetTicks) +IPState FocusSim::MoveAbsFocuser(uint32_t targetTicks) { if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested absolute position is out of range."); - return -1; + return IPS_ALERT; } double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min)/2; @@ -270,6 +272,8 @@ usleep( abs(targetTicks - FocusAbsPosN[0].value) * FOCUS_MOTION_DELAY); + FocusAbsPosN[0].value = targetTicks; + FWHMN[0].value = 0.5625*ticks*ticks + SeeingN[0].value; if (FWHMN[0].value < SeeingN[0].value) @@ -277,7 +281,17 @@ IDSetNumber(&FWHMNP, NULL); - return 0; + return IPS_OK; + +} + +IPState FocusSim::MoveRelFocuser(FocusDirection dir, uint32_t ticks) +{ + uint32_t targetTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1)); + + FocusAbsPosNP.s = IPS_BUSY; + IDSetNumber(&FocusAbsPosNP, NULL); + return MoveAbsFocuser(targetTicks); } diff -Nru libindi-1.0.0/drivers/focuser/focus_simulator.h libindi-1.1.0/drivers/focuser/focus_simulator.h --- libindi-1.0.0/drivers/focuser/focus_simulator.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/focus_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -59,8 +59,9 @@ virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); - virtual int MoveAbsFocuser(int ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); }; diff -Nru libindi-1.0.0/drivers/focuser/moonlite.cpp libindi-1.1.0/drivers/focuser/moonlite.cpp --- libindi-1.0.0/drivers/focuser/moonlite.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/moonlite.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -785,7 +785,7 @@ return true; } -int MoonLite::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState MoonLite::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { if (speed != currentSpeed) { @@ -793,7 +793,7 @@ rc = setSpeed(speed); if (rc == false) - return -1; + return IPS_ALERT; } gettimeofday(&focusMoveStart,NULL); @@ -806,15 +806,16 @@ if (duration <= POLLMS) { - usleep(POLLMS * 1000); + usleep(duration * 1000); AbortFocuser(); + return IPS_OK; } - return 1; + return IPS_BUSY; } -int MoonLite::MoveAbsFocuser(int targetTicks) +IPState MoonLite::MoveAbsFocuser(uint32_t targetTicks) { targetPos = targetTicks; @@ -823,14 +824,14 @@ rc = MoveFocuser(targetPos); if (rc == false) - return -1; + return IPS_ALERT; FocusAbsPosNP.s = IPS_BUSY; - return 1; + return IPS_BUSY; } -int MoonLite::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState MoonLite::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { double newPosition=0; bool rc=false; @@ -843,12 +844,12 @@ rc = MoveFocuser(newPosition); if (rc == false) - return -1; + return IPS_ALERT; FocusRelPosN[0].value = ticks; FocusRelPosNP.s = IPS_BUSY; - return 1; + return IPS_BUSY; } void MoonLite::TimerHit() diff -Nru libindi-1.0.0/drivers/focuser/moonlite.h libindi-1.1.0/drivers/focuser/moonlite.h --- libindi-1.0.0/drivers/focuser/moonlite.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/moonlite.h 2015-09-06 13:17:35.000000000 +0000 @@ -39,9 +39,9 @@ virtual void ISGetProperties(const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); - virtual int MoveAbsFocuser(int ticks); - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); virtual bool SetFocuserSpeed(int speed); virtual bool AbortFocuser(); virtual void TimerHit(); diff -Nru libindi-1.0.0/drivers/focuser/nfocus.cpp libindi-1.1.0/drivers/focuser/nfocus.cpp --- libindi-1.0.0/drivers/focuser/nfocus.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/nfocus.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -1181,7 +1181,7 @@ } -int NFocus::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState NFocus::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { INDI_UNUSED(speed); double pos=0; @@ -1197,12 +1197,10 @@ if (dir == FOCUS_INWARD) { - fprintf(stderr, "FOCUS_IN: ") ; updateNFPositionRelativeInward(&pos); } else { - fprintf(stderr, "FOCUS_OUT: ") ; updateNFPositionRelativeOutward(&pos); } @@ -1210,18 +1208,16 @@ dt = tv_finish.tv_sec - tv_start.tv_sec + (tv_finish.tv_usec - tv_start.tv_usec)/1e6; - - duration -= dt * 1000; // IDLog("dt is: %g --- duration is: %d -- pos: %g\n", dt, duration, pos); } - return true; + return IPS_BUSY; } -int NFocus::MoveAbsFocuser(int targetTicks) +IPState NFocus::MoveAbsFocuser(uint32_t targetTicks) { int ret= -1 ; double new_apos = targetTicks; @@ -1229,7 +1225,7 @@ if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested absolute position is out of range."); - return -1; + return IPS_ALERT; } IDMessage(getDeviceName() , "Focuser is moving to requested position..."); @@ -1245,7 +1241,7 @@ { IDMessage(getDeviceName(),"Unknown error while reading Nfocus position: %d.", ret); if (i == NF_MAX_TRIES) - return false; + return IPS_ALERT; else usleep(NF_MAX_DELAY); } @@ -1254,14 +1250,14 @@ IDMessage( getDeviceName(), "Nfocus position recovered resuming normal operation"); /* We have to leave here, because new_apos is not set */ - return -1; + return IPS_ALERT; } - return 0; + return IPS_OK; } -int NFocus::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState NFocus::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { double cur_rpos=0 ; double new_rpos = 0 ; @@ -1280,7 +1276,7 @@ if((currentPosition + new_rpos < currentMinPosition) || (currentPosition + new_rpos > currentMaxPosition)) { IDMessage(getDeviceName(), "Value out of limits %5.0f", currentPosition + new_rpos); - return -1 ; + return IPS_ALERT; } ret= updateNFPositionRelativeOutward(&new_rpos) ; } @@ -1289,7 +1285,7 @@ if((currentPosition - new_rpos < currentMinPosition) || (currentPosition - new_rpos > currentMaxPosition)) { IDMessage(getDeviceName(), "Value out of limits %5.0f", currentPosition - new_rpos); - return -1 ; + return IPS_ALERT; } ret= updateNFPositionRelativeInward(&new_rpos) ; } @@ -1302,21 +1298,21 @@ { IDMessage(getDeviceName(), "Unknown error while reading Nfocus position: %d", ret); - return false; + return IPS_ALERT; } IDMessage(getDeviceName(), "Nfocus position recovered %5.0f", currentPosition); // We have to leave here, because new_rpos is not set - return -1 ; + return IPS_ALERT; } currentRelativeMovement= cur_rpos ; // currentAbsoluteMovement= currentPosition; - return 0; + return IPS_OK; } { IDMessage(getDeviceName(), "Value out of limits."); - return -1; + return IPS_ALERT; } @@ -1328,5 +1324,6 @@ IUSaveConfigNumber(fp, &SettingsNP); IUSaveConfigNumber(fp, &SetBacklashNP); IUSaveConfigNumber(fp, &InOutScalarNP); + return true; } diff -Nru libindi-1.0.0/drivers/focuser/nfocus.h libindi-1.1.0/drivers/focuser/nfocus.h --- libindi-1.0.0/drivers/focuser/nfocus.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/nfocus.h 2015-09-06 13:17:35.000000000 +0000 @@ -44,9 +44,9 @@ virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); - virtual int MoveAbsFocuser(int ticks); - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); protected: bool saveConfigItems(FILE *fp); diff -Nru libindi-1.0.0/drivers/focuser/perfectstar.cpp libindi-1.1.0/drivers/focuser/perfectstar.cpp --- libindi-1.0.0/drivers/focuser/perfectstar.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/perfectstar.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,697 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + PerfectStar Focuser + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + . + 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 + Library General Public License for more details. + . + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*******************************************************************************/ + +#include "perfectstar.h" + +#include +#include +#include +#include +#include + +#include + +#define POLLMS 1000 /* 1000 ms */ +#define PERFECTSTAR_TIMEOUT 1000 /* 1000 ms */ + +#define FOCUS_SETTINGS_TAB "Settings" + +// We declare an auto pointer to PerfectStar. +std::auto_ptr perfectStar(0); + +void ISPoll(void *p); + +void ISInit() +{ + static int isInit =0; + + if (isInit == 1) + return; + + isInit = 1; + if(perfectStar.get() == 0) perfectStar.reset(new PerfectStar()); + +} + +void ISGetProperties(const char *dev) +{ + ISInit(); + perfectStar->ISGetProperties(dev); +} + +void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) +{ + ISInit(); + perfectStar->ISNewSwitch(dev, name, states, names, num); +} + +void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) +{ + ISInit(); + perfectStar->ISNewText(dev, name, texts, names, num); +} + +void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) +{ + ISInit(); + perfectStar->ISNewNumber(dev, name, values, names, num); +} + +void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + INDI_UNUSED(dev); + INDI_UNUSED(name); + INDI_UNUSED(sizes); + INDI_UNUSED(blobsizes); + INDI_UNUSED(blobs); + INDI_UNUSED(formats); + INDI_UNUSED(names); + INDI_UNUSED(n); +} + +void ISSnoopDevice (XMLEle *root) +{ + ISInit(); + perfectStar->ISSnoopDevice(root); +} + +PerfectStar::PerfectStar() +{ + FocuserCapability cap; + cap.canAbort=true; + cap.canAbsMove=true; + cap.canRelMove=true; + cap.variableSpeed=false; + + handle = 0; + + SetFocuserCapability(&cap); +} + +PerfectStar::~PerfectStar() +{ + sim = false; + simPosition = 0; + status = PS_NOOP; +} + +bool PerfectStar::Connect() +{ + sim = isSimulation(); + + if (sim) + { + SetTimer(POLLMS); + return true; + } + + handle = hid_open(0x04D8, 0xF812,0); + + if(handle==NULL) + { + DEBUG(INDI::Logger::DBG_ERROR, "No PerfectStar focuser found."); + return false; + } + else + SetTimer(POLLMS); + + return (handle != NULL); +} + +bool PerfectStar::Disconnect() +{ + if (!sim) + { + hid_close(handle); + hid_exit(); + } + + return true; +} + +const char * PerfectStar::getDefaultName() +{ + return (char *)"PerfectStar"; +} + +void PerfectStar::ISGetProperties (const char *dev) +{ + INDI::Focuser::ISGetProperties(dev); + + // We don't need port property + deleteProperty(PortTP.name); + +} + +bool PerfectStar::initProperties() +{ + INDI::Focuser::initProperties(); + + // Max Position + IUFillNumber(&MaxPositionN[0], "Steps", "", "%.f", 0, 500000, 0., 10000); + IUFillNumberVector(&MaxPositionNP, MaxPositionN, 1, getDeviceName(), "Max Position", "", FOCUS_SETTINGS_TAB, IP_RW, 0, IPS_IDLE); + + // Sync to a particular position + IUFillNumber(&SyncN[0], "Ticks", "", "%.f", 0, 100000, 100., 0.); + IUFillNumberVector(&SyncNP, SyncN, 1, getDeviceName(), "Sync", "", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); + + FocusAbsPosN[0].min = SyncN[0].min = 0; + FocusAbsPosN[0].max = SyncN[0].max = MaxPositionN[0].value; + FocusAbsPosN[0].step = SyncN[0].step = MaxPositionN[0].value/50.0; + FocusAbsPosN[0].value = 0; + + FocusRelPosN[0].max = (FocusAbsPosN[0].max-FocusAbsPosN[0].min)/2; + FocusRelPosN[0].step = FocusRelPosN[0].max/100.0; + FocusRelPosN[0].value = 100; + + addSimulationControl(); + + return true; +} + +bool PerfectStar::updateProperties() +{ + INDI::Focuser::updateProperties(); + + if (isConnected()) + { + defineNumber(&SyncNP); + defineNumber(&MaxPositionNP); + } + else + { + deleteProperty(SyncNP.name); + deleteProperty(MaxPositionNP.name); + } +} + +void PerfectStar::TimerHit() +{ + if (isConnected() == false) + return; + + uint32_t currentTicks=0; + + bool rc = getPosition(¤tTicks); + + if (rc) + FocusAbsPosN[0].value = currentTicks; + + rc = getStatus(&status); + + if (FocusAbsPosNP.s == IPS_BUSY || FocusRelPosNP.s == IPS_BUSY) + { + if (sim) + { + if ( FocusAbsPosN[0].value < targetPosition) + simPosition += 500; + else + simPosition -= 500; + + if (fabs(simPosition - targetPosition) < 500) + { + FocusAbsPosN[0].value = targetPosition; + simPosition = FocusAbsPosN[0].value; + status = PS_NOOP; + } + + + FocusAbsPosN[0].value = simPosition; + } + + if (status == PS_HALT && targetPosition == FocusAbsPosN[0].value) + { + if (FocusRelPosNP.s == IPS_BUSY) + { + FocusRelPosNP.s = IPS_OK; + IDSetNumber(&FocusRelPosNP, NULL); + } + + FocusAbsPosNP.s = IPS_OK; + DEBUG(INDI::Logger::DBG_DEBUG, "Focuser reached target position."); + } + else if (status == PS_NOOP) + { + if (FocusRelPosNP.s == IPS_BUSY) + { + FocusRelPosNP.s = IPS_OK; + IDSetNumber(&FocusRelPosNP, NULL); + } + + FocusAbsPosNP.s = IPS_OK; + DEBUG(INDI::Logger::DBG_SESSION, "Focuser reached home position."); + } + } + + IDSetNumber(&FocusAbsPosNP, NULL); + + SetTimer(POLLMS); +} + +bool PerfectStar::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + + if(strcmp(dev,getDeviceName())==0) + { + // Max Travel + if (!strcmp(MaxPositionNP.name, name)) + { + IUUpdateNumber(&MaxPositionNP, values, names, n); + + if (MaxPositionN[0].value > 0) + { + FocusAbsPosN[0].min = SyncN[0].min = 0; + FocusAbsPosN[0].max = SyncN[0].max = MaxPositionN[0].value; + FocusAbsPosN[0].step = SyncN[0].step = MaxPositionN[0].value/50.0; + + + FocusRelPosN[0].max = (FocusAbsPosN[0].max-FocusAbsPosN[0].min)/2; + FocusRelPosN[0].step = FocusRelPosN[0].max/100.0; + FocusRelPosN[0].min = 0; + + IUUpdateMinMax(&FocusAbsPosNP); + IUUpdateMinMax(&FocusRelPosNP); + IUUpdateMinMax(&SyncNP); + + DEBUGF(INDI::Logger::DBG_SESSION, "Focuser absolute limits: min (%g) max (%g)", FocusAbsPosN[0].min, FocusAbsPosN[0].max); + } + + MaxPositionNP.s = IPS_OK; + IDSetNumber(&MaxPositionNP, NULL); + return true; + } + + // Sync + if (!strcmp(SyncNP.name, name)) + { + IUUpdateNumber(&SyncNP, values, names, n); + if (sync(SyncN[0].value) == false) + SyncNP.s = IPS_ALERT; + else + SyncNP.s = IPS_OK; + + IDSetNumber(&SyncNP, NULL); + return true; + } + + } + + return INDI::Focuser::ISNewNumber(dev, name, values, names, n); + +} + +IPState PerfectStar::MoveAbsFocuser(uint32_t ticks) +{ + + bool rc = false; + + rc = setPosition(ticks); + + if (rc == false) + return IPS_ALERT; + + targetPosition = ticks; + + rc = setStatus(PS_GOTO); + + if (rc == false) + return IPS_ALERT; + + FocusAbsPosNP.s = IPS_BUSY; + + return IPS_BUSY; + +} + +IPState PerfectStar::MoveRelFocuser(FocusDirection dir, uint32_t ticks) +{ + uint32_t finalTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1)); + + return MoveAbsFocuser(finalTicks); +} + +bool PerfectStar::setPosition(uint32_t ticks) +{ + int rc=0; + unsigned char command[3]; + unsigned char response[3]; + + // 20 bit resolution position. 4 high bits + 16 lower bits + + // Send 4 high bits first + command[0] = 0x28; + command[1] = (ticks & 0x40000) >> 16; + + DEBUGF(INDI::Logger::DBG_DEBUG, "Set Position (%ld)", ticks); + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X %02X)", command[0], command[1]); + + if (sim) + rc = 2; + else + rc = hid_write(handle, command, 2); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setPosition: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 2; + response[0] = 0x28; + response[1] = command[1]; + } + else + rc = hid_read_timeout(handle, response, 2, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setPosition: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X)", response[0], response[1]); + + // Send lower 16 bit + command[0] = 0x20; + // Low Byte + command[1] = ticks & 0xFF; + // High Byte + command[2] = (ticks & 0xFF00) >> 8; + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X)", command[0], command[1], command[2]); + + if (sim) + rc = 3; + else + rc = hid_write(handle, command, 3); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setPosition: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 3; + response[0] = command[0]; + response[1] = command[1]; + response[2] = command[2]; + } + else + rc = hid_read_timeout(handle, response, 3, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setPosition: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0], response[1], response[2]); + + + targetPosition = ticks; + + // TODO add checking later + return true; +} + +bool PerfectStar::getPosition(uint32_t *ticks) +{ + + int rc=0; + uint32_t pos=0; + unsigned char command[1]; + unsigned char response[3]; + + // 20 bit resolution position. 4 high bits + 16 lower bits + + // Get 4 high bits first + command[0] = 0x29; + + DEBUG(INDI::Logger::DBG_DEBUG, "Get Position (High 4 bits)"); + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X)", command[0]); + + if (sim) + rc = 2; + else + rc = hid_write(handle, command, 1); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getPosition: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 2; + response[0] = command[0]; + response[1] = simPosition >> 16; + } + else + rc = hid_read_timeout(handle, response, 2, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getPosition: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X)", response[0], response[1]); + + // Store 4 high bits part of a 20 bit number + pos = response[1] << 16; + + // Get 16 lower bits + command[0] = 0x21; + + DEBUG(INDI::Logger::DBG_DEBUG, "Get Position (Lower 16 bits)"); + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X)", command[0]); + + if (sim) + rc = 1; + else + rc = hid_write(handle, command, 1); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getPosition: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 3; + response[0] = command[0]; + response[1] = simPosition & 0xFF; + response[2] = (simPosition & 0xFF00) >> 8; + } + else + rc = hid_read_timeout(handle, response, 3, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getPosition: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0], response[1], response[2]); + + // Res[1] is lower byte and Res[2] is high byte. Combine them and add them to ticks. + pos |= response[1] | response[2] << 8; + + *ticks = pos; + + DEBUGF(INDI::Logger::DBG_DEBUG, "Position: %ld", pos); + + return true; + +} + +bool PerfectStar::setStatus(PS_STATUS targetStatus) +{ + int rc=0; + unsigned char command[2]; + unsigned char response[3]; + + command[0] = 0x10; + command[1] = (targetStatus == PS_HALT) ? 0xFF : targetStatus; + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X %02X)", command[0], command[1]); + + if (sim) + rc = 2; + else + rc = hid_write(handle, command, 2); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setStatus: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 3; + response[0] = command[0]; + response[1] = 0; + response[2] = command[1]; + status = targetStatus; + // Convert Goto to either "moving in" or "moving out" status + if (status == PS_GOTO) + { + // Moving in state + if (targetPosition < FocusAbsPosN[0].value) + status = PS_IN; + else + // Moving out state + status = PS_OUT; + } + } + else + rc = hid_read_timeout(handle, response, 3, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "setStatus: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0], response[1], response[2]); + + if (response[1] == 0xFF) + { + DEBUG(INDI::Logger::DBG_ERROR, "setStatus: Invalid state change."); + return false; + } + + + return true; +} + +bool PerfectStar::getStatus(PS_STATUS *currentStatus) +{ + int rc=0; + unsigned char command[1]; + unsigned char response[2]; + + command[0] = 0x11; + + DEBUGF(INDI::Logger::DBG_DEBUG, "CMD (%02X)", command[0]); + + if (sim) + rc = 1; + else + rc = hid_write(handle, command, 1); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getStatus: Error writing to device (%s)", hid_error(handle)); + return false; + } + + if (sim) + { + rc = 2; + response[0] = command[0]; + response[1] = status; + // Halt/SetPos is state = 0 "not moving". + if (response[1] == PS_HALT || response[1] == PS_SETPOS) + response[1] = 0; + } + else + rc = hid_read_timeout(handle, response, 2, PERFECTSTAR_TIMEOUT); + + if (rc < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "getStatus: Error reading from device (%s)", hid_error(handle)); + return false; + } + + DEBUGF(INDI::Logger::DBG_DEBUG, "RES (%02X %02X)", response[0], response[1]); + + switch (response[1]) + { + case 0: + *currentStatus = PS_HALT; + DEBUG(INDI::Logger::DBG_DEBUG, "State: Not moving."); + break; + + case 1: + *currentStatus = PS_IN; + DEBUG(INDI::Logger::DBG_DEBUG, "State: Moving in."); + break; + + case 3: + *currentStatus = PS_GOTO; + DEBUG(INDI::Logger::DBG_DEBUG, "State: Goto."); + break; + + case 2: + *currentStatus = PS_OUT; + DEBUG(INDI::Logger::DBG_DEBUG, "State: Moving out."); + break; + + case 5: + *currentStatus = PS_LOCKED; + DEBUG(INDI::Logger::DBG_DEBUG, "State: Locked."); + break; + + default: + DEBUGF(INDI::Logger::DBG_WARNING, "Warning: Unknown status (%d)", response[1]); + return false; + break; + } + + return true; + +} + +bool PerfectStar::AbortFocuser() +{ + return setStatus(PS_HALT); +} + +bool PerfectStar::sync(uint32_t ticks) +{ + bool rc = setPosition(ticks); + + if (rc == false) + return false; + + simPosition = ticks; + + rc = setStatus(PS_SETPOS); + + return rc; +} + +bool PerfectStar::saveConfigItems(FILE *fp) +{ + INDI::Focuser::saveConfigItems(fp); + + IUSaveConfigNumber(fp, &MaxPositionNP); + + return true; +} + diff -Nru libindi-1.0.0/drivers/focuser/perfectstar.h libindi-1.1.0/drivers/focuser/perfectstar.h --- libindi-1.0.0/drivers/focuser/perfectstar.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/perfectstar.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,85 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + PerfectStar Focuser + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + . + 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 + Library General Public License for more details. + . + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*******************************************************************************/ + +#ifndef PERFECTSTAR_H +#define PERFECTSTAR_H + +#include "indibase/indifocuser.h" +#include "indibase/indiusbdevice.h" +#include "indibase/hidapi.h" + +/* Some headers we need */ +#include +#include + +class PerfectStar : public INDI::Focuser +{ +public: + + // Perfect Star (PS) status + typedef enum { PS_NOOP, PS_IN, PS_OUT, PS_GOTO, PS_SETPOS, PS_LOCKED, PS_HALT=0xFF } PS_STATUS; + + PerfectStar(); + virtual ~PerfectStar(); + + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + + const char *getDefaultName(); + virtual bool initProperties(); + virtual void ISGetProperties (const char *dev); + virtual bool updateProperties(); + virtual bool saveConfigItems(FILE *fp); + + bool Connect(); + bool Disconnect(); + + void TimerHit(); + + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); + virtual bool AbortFocuser(); + +private: + + hid_device *handle; + PS_STATUS status; + bool sim; + uint32_t simPosition; + uint32_t targetPosition; + + bool setPosition(uint32_t ticks); + bool getPosition(uint32_t *ticks); + + bool setStatus(PS_STATUS targetStatus); + bool getStatus(PS_STATUS *currentStatus); + + bool sync(uint32_t ticks); + + // Max position in ticks + INumber MaxPositionN[1]; + INumberVectorProperty MaxPositionNP; + + // Sync to a particular position + INumber SyncN[1]; + INumberVectorProperty SyncNP; + +}; + +#endif diff -Nru libindi-1.0.0/drivers/focuser/robofocus.cpp libindi-1.1.0/drivers/focuser/robofocus.cpp --- libindi-1.0.0/drivers/focuser/robofocus.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/robofocus.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -1462,7 +1462,7 @@ } -int RoboFocus::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState RoboFocus::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { INDI_UNUSED(speed); double pos=0; @@ -1490,11 +1490,11 @@ // IDLog("dt is: %g --- duration is: %d -- pos: %g\n", dt, duration, pos); } - return 0; + return IPS_BUSY; } -int RoboFocus::MoveAbsFocuser(int targetTicks) +IPState RoboFocus::MoveAbsFocuser(uint32_t targetTicks) { int ret= -1 ; targetPos = targetTicks; @@ -1502,7 +1502,7 @@ if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested absolute position is out of range."); - return -1; + return IPS_ALERT; } //IDMessage(getDeviceName() , "Focuser is moving to requested position %d...", targetTicks); @@ -1518,7 +1518,7 @@ { IDMessage(getDeviceName(),"Unknown error while reading Robofocus position: %d.", ret); if (i == RF_MAX_TRIES) - return false; + return IPS_ALERT; else usleep(RF_MAX_DELAY); } @@ -1527,13 +1527,13 @@ IDMessage( getDeviceName(), "Robofocus position recovered resuming normal operation"); /* We have to leave here, because new_apos is not set */ - return -1; + return IPS_ALERT; } - return 1; + return IPS_BUSY; } -int RoboFocus::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState RoboFocus::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { double cur_rpos=0 ; double new_rpos = 0 ; @@ -1551,7 +1551,7 @@ { IDMessage(getDeviceName(), "Value out of limits %5.0f", currentPosition + new_rpos); - return -1 ; + return IPS_ALERT; } if( dir == FOCUS_OUTWARD) @@ -1567,24 +1567,23 @@ { IDMessage(getDeviceName(), "Unknown error while reading Robofocus position: %d", ret); - return false; + return IPS_ALERT; } IDMessage(getDeviceName(), "Robofocus position recovered %5.0f", currentPosition); // We have to leave here, because new_rpos is not set - return -1 ; + return IPS_ALERT; } currentRelativeMovement= cur_rpos ; currentAbsoluteMovement= new_rpos; - return 0; + return IPS_OK; } { IDMessage(getDeviceName(), "Value out of limits."); - return -1; + return IPS_ALERT; } - } bool RoboFocus::saveConfigItems(FILE *fp) diff -Nru libindi-1.0.0/drivers/focuser/robofocus.h libindi-1.1.0/drivers/focuser/robofocus.h --- libindi-1.0.0/drivers/focuser/robofocus.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/robofocus.h 2015-09-06 13:17:35.000000000 +0000 @@ -39,9 +39,9 @@ virtual void ISGetProperties(const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); - virtual int MoveAbsFocuser(int ticks); - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); virtual bool AbortFocuser(); virtual void TimerHit(); diff -Nru libindi-1.0.0/drivers/focuser/steeldrive.cpp libindi-1.1.0/drivers/focuser/steeldrive.cpp --- libindi-1.0.0/drivers/focuser/steeldrive.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/steeldrive.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -678,6 +678,7 @@ DEBUGF(INDI::Logger::DBG_ERROR, "Unknown error: updateAcceleration value (%s)", resp); return false; } + return true; } /************************************************************************************ @@ -1348,7 +1349,7 @@ return true; } -int SteelDrive::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState SteelDrive::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { if (speed != currentSpeed) { @@ -1356,7 +1357,7 @@ rc = setSpeed(speed); if (rc == false) - return -1; + return IPS_ALERT; } gettimeofday(&focusMoveStart,NULL); @@ -1368,13 +1369,14 @@ { usleep(POLLMS * 1000); AbortFocuser(); + return IPS_OK; } - return 1; + return IPS_BUSY; } -int SteelDrive::MoveAbsFocuser(int targetTicks) +IPState SteelDrive::MoveAbsFocuser(uint32_t targetTicks) { targetPos = targetTicks; @@ -1383,14 +1385,14 @@ rc = moveFocuser(targetPos); if (rc == false) - return -1; + return IPS_ALERT; FocusAbsPosNP.s = IPS_BUSY; - return 1; + return IPS_BUSY; } -int SteelDrive::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState SteelDrive::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { double newPosition=0; bool rc=false; @@ -1403,13 +1405,13 @@ rc = moveFocuser(newPosition); if (rc == false) - return -1; + return IPS_ALERT; FocusRelPosN[0].value = ticks; FocusRelPosNP.s = IPS_BUSY; FocusAbsPosNP.s = IPS_BUSY; - return 1; + return IPS_BUSY; } void SteelDrive::TimerHit() diff -Nru libindi-1.0.0/drivers/focuser/steeldrive.h libindi-1.1.0/drivers/focuser/steeldrive.h --- libindi-1.0.0/drivers/focuser/steeldrive.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/steeldrive.h 2015-09-06 13:17:35.000000000 +0000 @@ -51,9 +51,9 @@ virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); - virtual int MoveAbsFocuser(int ticks); - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, unsigned int ticks); virtual bool SetFocuserSpeed(int speed); virtual bool AbortFocuser(); virtual void TimerHit(); diff -Nru libindi-1.0.0/drivers/focuser/tcfs.cpp libindi-1.1.0/drivers/focuser/tcfs.cpp --- libindi-1.0.0/drivers/focuser/tcfs.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/tcfs.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -160,6 +160,7 @@ FocusRelPosN[0].value = 0; DEBUG(INDI::Logger::DBG_DEBUG, "TCF-S detected. Updating maximum position value to 7000."); } + return true; } /**************************************************************** @@ -202,6 +203,7 @@ loadConfig(true); SetTimer(POLLMS); + return true; } else { @@ -209,7 +211,9 @@ deleteProperty(FocusTemperatureNP->name); deleteProperty(FocusPowerSP->name); deleteProperty(FocusModeSP->name); + return false; } + return true; } /**************************************************************** @@ -493,26 +497,26 @@ return INDI::Focuser::ISNewSwitch(dev, name, states, names, n); } -int TCFS::MoveAbsFocuser(int ticks) +IPState TCFS::MoveAbsFocuser(uint32_t ticks) { int delta=0; delta = ticks - currentPosition; if (delta < 0) - MoveRelFocuser(FOCUS_INWARD, (unsigned int) fabs(delta)); + return MoveRelFocuser(FOCUS_INWARD, (uint32_t) fabs(delta)); else - MoveRelFocuser(FOCUS_OUTWARD, (unsigned int) fabs(delta)); + return MoveRelFocuser(FOCUS_OUTWARD, (uint32_t) fabs(delta)); } -int TCFS::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState TCFS::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { if (inAutoMode) { DEBUG(INDI::Logger::DBG_WARNING, "The focuser can only be moved in Manual mode."); - return -1; + return IPS_ALERT; } targetTicks = ticks; @@ -538,7 +542,7 @@ simulated_position = targetPosition; - return 1; + return IPS_BUSY; } diff -Nru libindi-1.0.0/drivers/focuser/tcfs.h libindi-1.1.0/drivers/focuser/tcfs.h --- libindi-1.0.0/drivers/focuser/tcfs.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/focuser/tcfs.h 2015-09-06 13:17:35.000000000 +0000 @@ -69,8 +69,8 @@ virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); protected: - virtual int MoveAbsFocuser(int ticks); - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveAbsFocuser(uint32_t ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); virtual void TimerHit(); private: diff -Nru libindi-1.0.0/drivers/telescope/celestrondriver.cpp libindi-1.1.0/drivers/telescope/celestrondriver.cpp --- libindi-1.0.0/drivers/telescope/celestrondriver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/celestrondriver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,1361 @@ +/* + Celestron driver + + Copyright (C) 2015 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "indicom.h" +#include "indidevapi.h" +#include "indilogger.h" + +#include "celestrondriver.h" + +#define CELESTRON_TIMEOUT 5 /* FD timeout in seconds */ +std::map celestronModels; + +bool celestron_debug = false; +bool celestron_simulation = false; +char celestron_device[MAXINDIDEVICE] = "Celestron GPS"; +double currentRA, currentDEC, currentSlewRate; + +struct +{ + double ra; + double dec; + double az; + double alt; + CELESTRON_GPS_STATUS gpsStatus; + CELESTRON_SLEW_RATE slewRate; + bool isSlewing; +} simData; + +void set_celestron_debug(bool enable) +{ + celestron_debug = enable; +} + +void set_celestron_simulation(bool enable) +{ + celestron_simulation = enable; +} + +void set_celestron_device(const char *name) +{ + strncpy(celestron_device, name, MAXINDIDEVICE); +} + +void set_sim_gps_status(CELESTRON_GPS_STATUS value) +{ + simData.gpsStatus = value; +} + +void set_sim_slew_rate(CELESTRON_SLEW_RATE value) +{ + simData.slewRate = value; +} + +void set_sim_slewing(bool isSlewing) +{ + simData.isSlewing = isSlewing; +} + +void set_sim_ra(double ra) +{ + simData.ra = ra; +} + +void set_sim_dec(double dec) +{ + simData.dec = dec; +} + +void set_sim_az(double az) +{ + simData.az = az; +} + +void set_sim_alt(double alt) +{ + simData.alt = alt; +} + +bool check_celestron_connection(int fd) +{ + char initCMD[] = "Kx"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (celestronModels.empty()) + { + celestronModels[1] = "GPS Series"; + celestronModels[3] = "i-Series"; + celestronModels[4] = "i-Series SE"; + celestronModels[5] = "CGE"; + celestronModels[6] = "Advanced GT"; + celestronModels[7] = "SLT"; + celestronModels[9] = "CPC"; + celestronModels[10] = "GT"; + celestronModels[11] = "4/5 SE"; + celestronModels[12] = "6/8 SE"; + celestronModels[14] = "CGEM DX"; + } + + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Initializing Celestron using Kx CMD..."); + + for (int i=0; i < 2; i++) + { + if (celestron_simulation) + { + strcpy(response, "x#"); + nbytes_read= strlen(response); + } + else + { + if ( (errcode = tty_write(fd, initCMD, 2, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + usleep(50000); + continue; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + usleep(50000); + continue; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "x#")) + return true; + } + + usleep(50000); + } + + return false; +} + +bool get_celestron_firmware(int fd, FirmwareInfo *info) +{ + bool rc = false; + + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Getting controller version..."); + rc = get_celestron_version(fd, info); + + if (rc == false) + return false; + + if (info->controllerVersion >= 2.2) + { + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Getting controller model..."); + rc = get_celestron_model(fd, info); + if (rc == false) + return rc; + } + else + info->Model = "Unknown"; + + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Getting GPS firmware version..."); + rc = get_celestron_gps_firmware(fd, info); + + if (rc == false) + return rc; + + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Getting RA firmware version..."); + rc = get_celestron_ra_firmware(fd, info); + + if (rc == false) + return rc; + + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Getting DE firmware version..."); + rc = get_celestron_dec_firmware(fd, info); + + return rc; +} + +bool get_celestron_version (int fd, FirmwareInfo *info) +{ + char cmd[] = "V"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + char major = 4; + char minor = 4; + snprintf(response, 16, "%c%c#", major, minor); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0],response[1], response[2]); + + if (nbytes_read == 3) + { + int major = response[0]; + int minor = response[1]; + + char versionStr[8]; + snprintf(versionStr, 8, "%01d.%01d", major, minor); + + info->controllerVersion = atof(versionStr); + info->Version = versionStr; + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 3.", nbytes_read); + return false; + +} + +bool get_celestron_model (int fd, FirmwareInfo *info) +{ + char cmd[] = "m"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + char device = 6; + snprintf(response, 16, "%c#", device); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X)", response[0],response[1]); + + if (nbytes_read == 2) + { + response[1] = '\0'; + int model = response[0]; + + if (model >= 1 && model <= 14) + info->Model = celestronModels[model]; + else + { + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_WARNING, "Unrecognized model (%d).", model); + info->Model = "Unknown"; + } + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 2.", nbytes_read); + return false; + +} + +bool get_celestron_ra_firmware(int fd, FirmwareInfo *info) +{ + unsigned char cmd[] = { 0x50, 0x01, 0x10, 0xFE, 0x0, 0x0, 0x0, 0x02}; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + if (celestron_simulation) + { + char major = 1; + char minor = 9; + snprintf(response, 16, "%c%c#", major, minor); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, (char *) cmd, 8, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0],response[1], response[2]); + + if (nbytes_read == 3) + { + int major = response[0]; + int minor = response[1]; + + char versionStr[8]; + snprintf(versionStr, 8, "%01d.%01d", major, minor); + + info->RAFirmware = versionStr; + + tcflush(fd, TCIFLUSH); + + return true; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 3.", nbytes_read); + return false; +} + +bool get_celestron_dec_firmware(int fd, FirmwareInfo *info) +{ + unsigned char cmd[] = { 0x50, 0x01, 0x11, 0xFE, 0x0, 0x0, 0x0, 0x02}; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + if (celestron_simulation) + { + char major = 1; + char minor = 6; + snprintf(response, 16, "%c%c#", major, minor); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, (char *) cmd, 8, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0],response[1], response[2]); + + if (nbytes_read == 3) + { + int major = response[0]; + int minor = response[1]; + + char versionStr[8]; + snprintf(versionStr, 8, "%01d.%01d", major, minor); + + info->DEFirmware = versionStr; + + tcflush(fd, TCIFLUSH); + + return true; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 3.", nbytes_read); + return false; +} + +bool get_celestron_gps_firmware(int fd, FirmwareInfo *info) +{ + unsigned char cmd[] = { 0x50, 0x01, 0x10, 0xFE, 0x0, 0x0, 0x0, 0x02}; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + if (celestron_simulation) + { + char major = 1; + char minor = 6; + snprintf(response, 16, "%c%c#", major, minor); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, (char *) cmd, 8, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X)", response[0],response[1], response[2]); + + if (nbytes_read == 3) + { + int major = response[0]; + int minor = response[1]; + + char versionStr[8]; + snprintf(versionStr, 8, "%01d.%01d", major, minor); + + info->GPSFirmware = versionStr; + + tcflush(fd, TCIFLUSH); + + return true; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 3.", nbytes_read); + return false; +} + +bool start_celestron_motion(int fd, CELESTRON_DIRECTION dir, CELESTRON_SLEW_RATE rate) +{ + char cmd[] = { 0x50, 0x02, 0x11, 0x24, 0x09, 0x00, 0x00, 0x00}; + int errcode = 0; + char errmsg[MAXRBUF]; + int nbytes_written=0, nbytes_read=0; + char response[8]; + + switch (dir) + { + case CELESTRON_N: + cmd[2] = 0x11; + cmd[3] = 0x24; + cmd[4] = rate; + break; + + case CELESTRON_S: + cmd[2] = 0x11; + cmd[3] = 0x25; + cmd[4] = rate; + break; + + case CELESTRON_W: + cmd[2] = 0x10; + cmd[3] = 0x24; + cmd[4] = rate; + break; + + case CELESTRON_E: + cmd[2] = 0x10; + cmd[3] = 0x25; + cmd[4] = rate; + break; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, 8, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool stop_celestron_motion(int fd, CELESTRON_DIRECTION dir) +{ + char cmd[] = { 0x50, 0x02, 0x11, 0x24, 0x00, 0x00, 0x00, 0x00}; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + switch (dir) + { + case CELESTRON_N: + case CELESTRON_S: + cmd[2] = 0x11; + cmd[3] = 0x24; + break; + + case CELESTRON_W: + case CELESTRON_E: + cmd[2] = 0x10; + cmd[3] = 0x24; + break; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, 8, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool abort_celestron(int fd) +{ + char cmd[] = "M"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool slew_celestron(int fd, double ra, double dec) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + int ra_int, de_int; + + ra_int = get_ra_fraction(ra); + de_int = get_de_fraction(dec); + + char RAStr[16], DecStr[16]; + fs_sexa(RAStr, ra, 2, 3600); + fs_sexa(DecStr, dec, 2, 3600); + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Goto (%s,%s)", RAStr, DecStr); + + snprintf(cmd, 16, "R%04X,%04X", ra_int, de_int); + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + set_sim_slewing(true); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "#")) + { + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Requested object is below horizon."); + tcflush(fd, TCIFLUSH); + return false; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool slew_celestron_azalt(int fd, double az, double alt) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + int az_int, alt_int; + + az_int = get_angle_fraction(az); + alt_int = get_angle_fraction(alt); + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, az, 3, 3600); + fs_sexa(AltStr, alt, 2, 3600); + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Goto AZM-ALT (%s,%s)", AzStr, AltStr); + + snprintf(cmd, 16, "B%04X,%04X", az_int, alt_int); + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + set_sim_slewing(true); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "#")) + { + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Requested object is below horizon."); + tcflush(fd, TCIFLUSH); + return false; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool sync_celestron(int fd, double ra, double dec) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + int ra_int, de_int; + + char RAStr[16], DecStr[16]; + fs_sexa(RAStr, ra, 2, 3600); + fs_sexa(DecStr, dec, 2, 3600); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "Sync (%s,%s)", RAStr, DecStr); + + ra_int = get_ra_fraction(ra); + de_int = get_de_fraction(dec); + + snprintf(cmd, 16, "S%04X,%04X", ra_int, de_int); + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + simData.ra = ra; + simData.dec = dec; + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "#")) + { + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Requested object is below horizon."); + tcflush(fd, TCIFLUSH); + return false; + } + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool get_celestron_coords(int fd, double *ra, double *dec) +{ + char cmd[] = "E"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_EXTRA_1, "CMD (%s)", cmd); + + if (celestron_simulation) + { + int ra_int = get_ra_fraction(simData.ra); + int de_int = get_de_fraction(simData.dec); + snprintf(response, 16, "%04X,%04X#", ra_int, de_int); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + tcflush(fd, TCIFLUSH); + response[nbytes_read] = '\0'; + + char ra_str[16], de_str[16]; + memset(ra_str, 0, 16); + memset(de_str, 0, 16); + + strncpy(ra_str, response, 4); + strncpy(de_str, response+5, 4); + + int CELESTRONRA = strtol(ra_str, NULL, 16); + int CELESTRONDE = strtol(de_str, NULL, 16); + + *ra = (CELESTRONRA / 65536.0) * (360.0 / 15.0); + *dec = (CELESTRONDE / 65536.0) * 360.0; + + /* Account for the quadrant in declination + * Author: John Kielkopf (kielkopf@louisville.edu) */ + /* 90 to 180 */ + if ( (*dec > 90.) && (*dec <= 180.) ) + *dec = 180. - *dec; + /* 180 to 270 */ + if ( (*dec > 180.) && (*dec <= 270.) ) + *dec = *dec - 270.; + /* 270 to 360 */ + if ( (*dec > 270.) && (*dec <= 360.) ) + *dec = *dec - 360.; + + char RAStr[16], DecStr[16]; + fs_sexa(RAStr, *ra, 2, 3600); + fs_sexa(DecStr, *dec, 2, 3600); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_EXTRA_1, "RES (%s) ==> RA-DEC (%s,%s)", response, RAStr, DecStr); + + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 10.", nbytes_read); + return false; +} + +bool get_celestron_coords_azalt(int fd, double *az, double *alt) +{ + char cmd[] = "Z"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_EXTRA_1, "CMD (%s)", cmd); + + if (celestron_simulation) + { + int az_int = get_angle_fraction(simData.az); + int alt_int = get_angle_fraction(simData.alt); + snprintf(response, 16, "%04X,%04X#", az_int, alt_int); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + tcflush(fd, TCIFLUSH); + response[nbytes_read] = '\0'; + + char az_str[16], alt_str[16]; + memset(az_str, 0, 16); + memset(alt_str, 0, 16); + + strncpy(az_str, response, 4); + strncpy(alt_str, response+5, 4); + + int CELESTRONAZ = strtol(az_str, NULL, 16); + int CELESTRONALT = strtol(alt_str, NULL, 16); + + *az = (CELESTRONAZ / 65536.0) * 360.0; + *alt = (CELESTRONALT / 65536.0) * 360.0; + + if (*alt > 90) + *alt -= 360; + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, *az, 3, 3600); + fs_sexa(AltStr, *alt, 2, 3600); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_EXTRA_1, "RES (%s) ==> AZM-ALT (%s,%s)", response, AzStr, AltStr); + + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 10.", nbytes_read); + return false; +} + +bool set_celestron_location(int fd, double longitude, double latitude) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + int lat_d, lat_m, lat_s; + int long_d, long_m ,long_s; + + // Convert from INDI standard to regular east/west -180 to 180 + if (longitude > 180) + longitude -= 360; + + getSexComponents(latitude, &lat_d, &lat_m, &lat_s); + getSexComponents(longitude, &long_d, &long_m, &long_s); + + cmd[0] = 'W'; + cmd[1] = abs(lat_d); + cmd[2] = lat_m; + cmd[3] = lat_s; + cmd[4] = lat_d > 0 ? 0 : 1; + cmd[5] = abs(long_d); + cmd[6] = long_m; + cmd[7] = long_s; + cmd[8] = long_d > 0 ? 0 : 1; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7], cmd[8]); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, 9, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; + +} + +bool set_celestron_datetime(int fd, struct ln_date *utc, double utc_offset) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + struct ln_zonedate local_date; + + // Celestron takes local time + ln_date_to_zonedate(utc, &local_date, utc_offset*3600); + + cmd[0] = 'H'; + cmd[1] = local_date.hours; + cmd[2] = local_date.minutes; + cmd[3] = local_date.seconds; + cmd[4] = local_date.months; + cmd[5] = local_date.days; + cmd[6] = local_date.years - 2000; + + if (utc_offset < 0) + cmd[7] = 256 - ((unsigned int) fabs(utc_offset)); + else + cmd[7] = ((unsigned int) fabs(utc_offset)); + + // Always assume standard time + cmd[8] = 0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%02X %02X %02X %02X %02X %02X %02X %02X %02X)", cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7], cmd[8]); + + if (celestron_simulation) + { + strcpy(response, "#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, 9, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool get_celestron_utc_date_time(int fd, double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss) +{ + char cmd[] = "h"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + // HH MM SS MONTH DAY YEAR OFFSET DAYLIGHT + response[0] = 17; + response[1] = 30; + response[2] = 10; + response[3] = 4; + response[4] = 1; + response[5] = 15; + response[6] = 3; + response[7] = 0; + response[8] = '#'; + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + tcflush(fd, TCIFLUSH); + response[nbytes_read] = '\0'; + unsigned char *res = (unsigned char *) response; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%02X %02X %02X %02X %02X %02X %02X %02X)", res[0],res[1],res[2],res[3],res[4],res[5],res[6],res[7]); + + // HH MM SS MONTH DAY YEAR OFFSET DAYLIGHT + *hh = res[0]; + *minute = res[1]; + *ss = res[2]; + *mm = res[3]; + *dd = res[4]; + *yy = res[5] + 2000; + *utc_hours = res[6]; + + if (*utc_hours > 12) + *utc_hours -= 256; + + ln_zonedate localTime; + ln_date utcTime; + + localTime.years = *yy; + localTime.months = *mm; + localTime.days = *dd; + localTime.hours = *hh; + localTime.minutes = *minute; + localTime.seconds = *ss; + localTime.gmtoff = *utc_hours * 3600; + + ln_zonedate_to_date(&localTime, &utcTime); + + *yy = utcTime.years; + *mm = utcTime.months; + *dd = utcTime.days; + *hh = utcTime.hours; + *minute = utcTime.minutes; + *ss = utcTime.seconds; + + return true; + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool is_scope_slewing(int fd) +{ + char cmd[] = "L"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (celestron_simulation) + { + if (simData.isSlewing) + strcpy(response, "1#"); + else + strcpy(response, "0#"); + + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 2, CELESTRON_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + + if (response[0] == '0') + return false; + else + return true; + + } + + DEBUGFDEVICE(celestron_device, INDI::Logger::DBG_ERROR, "Received #%d bytes, expected 1.", nbytes_read); + return false; +} + +unsigned int get_angle_fraction(double angle) +{ + if (angle >= 0) + return ((unsigned int) (angle * 65536 / 360.0)); + else + return ((unsigned int) ((angle+360) * 65536 / 360.0)); +} + +unsigned int get_ra_fraction(double ra) +{ + return ((unsigned int) (ra * 15.0 * 65536 / 360.0)); +} + +unsigned int get_de_fraction(double de) +{ + unsigned int de_int=0; + + if (de >= 0) + de_int = (unsigned int) (de * 65536 / 360.0); + else + de_int = (unsigned int) ((de+360.0) * 65536 / 360.0); + + return de_int; +} + + diff -Nru libindi-1.0.0/drivers/telescope/celestrondriver.h libindi-1.1.0/drivers/telescope/celestrondriver.h --- libindi-1.0.0/drivers/telescope/celestrondriver.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/celestrondriver.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,113 @@ +/* + Celestron driver + + Copyright (C) 2015 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 +*/ + +#ifndef CELESTRONDRIVER_H +#define CELESTRONDRIVER_H + +#include + +typedef enum { GPS_OFF, GPS_ON } CELESTRON_GPS_STATUS; +typedef enum { SR_1, SR_2, SR_3, SR_4, SR_5, SR_6, SR_7, SR_8, SR_9} CELESTRON_SLEW_RATE; +typedef enum { RA_AXIS, DEC_AXIS } CELESTRON_AXIS; +typedef enum { CELESTRON_N, CELESTRON_S, CELESTRON_W, CELESTRON_E} CELESTRON_DIRECTION; +typedef enum { FW_MODEL, FW_VERSION, FW_GPS, FW_RA, FW_DEC } CELESTRON_FIRMWARE; + +typedef struct +{ + std::string Model; + std::string Version; + std::string GPSFirmware; + std::string RAFirmware; + std::string DEFirmware; + + float controllerVersion; +} FirmwareInfo; + +/************************************************************************** + Misc. +**************************************************************************/ +void set_celestron_debug(bool enable); +void set_celestron_simulation(bool enable); +void set_celestron_device(const char *name); + +/************************************************************************** + Simulation +**************************************************************************/ +void set_sim_gps_status(CELESTRON_GPS_STATUS value); +void set_sim_slew_rate(CELESTRON_SLEW_RATE value); +void set_sim_slewing(bool isSlewing); +void set_sim_ra(double ra); +void set_sim_dec(double dec); +void set_sim_az(double az); +void set_sim_alt(double alt); + +/************************************************************************** + Diagnostics +**************************************************************************/ +bool check_celestron_connection(int fd); + +/************************************************************************** + Get Info +**************************************************************************/ +/** Get All firmware information in addition to model and version */ +bool get_celestron_firmware(int fd, FirmwareInfo *info); +/** Get version */ +bool get_celestron_version(int fd, FirmwareInfo *info); +/** Get Mount model */ +bool get_celestron_model(int fd, FirmwareInfo *info); +/** Get GPS Firmware version */ +bool get_celestron_gps_firmware(int fd, FirmwareInfo *info); +/** Get RA Firmware version */ +bool get_celestron_ra_firmware(int fd, FirmwareInfo *info); +/** Get DEC Firmware version */ +bool get_celestron_dec_firmware(int fd, FirmwareInfo *info); +/** Get RA/DEC */ +bool get_celestron_coords(int fd, double *ra, double *dec); +/** Get Az/Alt */ +bool get_celestron_coords_azalt(int fd, double *az, double *alt); +/** Get UTC/Date/Time */ +bool get_celestron_utc_date_time(int fd, double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss); + +/************************************************************************** + Motion +**************************************************************************/ +bool start_celestron_motion(int fd, CELESTRON_DIRECTION dir, CELESTRON_SLEW_RATE rate); +bool stop_celestron_motion(int fd, CELESTRON_DIRECTION dir); +bool abort_celestron(int fd); +bool slew_celestron(int fd, double ra, double dec); +bool slew_celestron_azalt(int fd, double az, double alt); +bool sync_celestron(int fd, double ra, double dec); + +/************************************************************************** + Time & Location +**************************************************************************/ +bool set_celestron_location(int fd, double longitude, double latitude); +bool set_celestron_datetime(int fd, struct ln_date *utc, double utc_offset); + +/************************************************************************** + Utility functions +**************************************************************************/ +unsigned int get_ra_fraction(double ra); +unsigned int get_de_fraction(double de); +unsigned int get_angle_fraction(double angle); + +bool is_scope_slewing(int fd); + +#endif diff -Nru libindi-1.0.0/drivers/telescope/celestrongps.cpp libindi-1.1.0/drivers/telescope/celestrongps.cpp --- libindi-1.0.0/drivers/telescope/celestrongps.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/celestrongps.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -29,12 +29,18 @@ #include -#include "celestronprotocol.h" #include "celestrongps.h" /* Simulation Parameters */ -#define SLEWRATE 1 /* slew rate, degrees/s */ -#define SIDRATE 0.004178 /* sidereal rate, degrees/s */ +#define GOTO_RATE 5 /* slew rate, degrees/s */ +#define SLEW_RATE 0.5 /* slew rate, degrees/s */ +#define FINE_SLEW_RATE 0.1 /* slew rate, degrees/s */ +#define SID_RATE 0.004178 /* sidereal rate, degrees/s */ +#define GOTO_LIMIT 5.5 /* Move at GOTO_RATE until distance from target is GOTO_LIMIT degrees */ +#define SLEW_LIMIT 1 /* Move at SLEW_LIMIT until distance from target is SLEW_LIMIT degrees */ +#define FINE_SLEW_LIMIT 0.5 /* Move at FINE_SLEW_RATE until distance from target is FINE_SLEW_LIMIT degrees */ + +#define MOUNTINFO_TAB "Mount Info" std::auto_ptr telescope(0); @@ -84,24 +90,20 @@ CelestronGPS::CelestronGPS() { - setVersion(2, 0); - - lastRA = 0; - lastDEC = 0; - currentSet = 0; - lastSet = -1; - - controller = new INDI::Controller(this); - - controller->setJoystickCallback(joystickHelper); - controller->setButtonCallback(buttonHelper); + setVersion(3, 0); - TelescopeCapability cap; - - cap.canPark = false; - cap.canSync = true; - cap.canAbort = true; - SetTelescopeCapability(&cap); + PortFD = -1; + fwInfo.Version = "Invalid"; + fwInfo.controllerVersion = 0; + + INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); + + currentRA = 0; + currentDEC = 90; + currentAZ = 0; + currentALT = 0; + targetAZ = 0; + targetALT = 0; } @@ -114,20 +116,19 @@ { INDI::Telescope::initProperties(); - IUFillSwitch(&SlewModeS[0], "Max", "", ISS_ON); - IUFillSwitch(&SlewModeS[1], "Find", "", ISS_OFF); - IUFillSwitch(&SlewModeS[2], "Centering", "", ISS_OFF); - IUFillSwitch(&SlewModeS[3], "Guide", "", ISS_OFF); - IUFillSwitchVector(&SlewModeSP, SlewModeS, 4, getDeviceName(), "Slew Rate", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - controller->mapController("NSWE Control","NSWE Control", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1"); - controller->mapController("Slew Max", "Slew Max", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); - controller->mapController("Slew Find","Slew Find", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); - controller->mapController("Slew Centering", "Slew Centering", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); - controller->mapController("Slew Guide", "Slew Guide", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_4"); - controller->mapController("Abort Motion", "Abort Motion", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_5"); + /* Firmware */ + IUFillText(&FirmwareT[FW_MODEL], "Model", "", 0); + IUFillText(&FirmwareT[FW_VERSION], "Version", "", 0); + IUFillText(&FirmwareT[FW_GPS], "GPS", "", 0); + IUFillText(&FirmwareT[FW_RA], "RA", "", 0); + IUFillText(&FirmwareT[FW_DEC], "DEC", "", 0); + IUFillTextVector(&FirmwareTP, FirmwareT, 5, getDeviceName(), "Firmware Info", "", MOUNTINFO_TAB, IP_RO, 0, IPS_IDLE); + + IUFillNumber(&HorizontalCoordsN[AXIS_AZ], "AZ", "Az D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0); + IUFillNumber(&HorizontalCoordsN[AXIS_ALT], "ALT", "Alt D:M:S", "%10.6m", -90., 90.0, 0.0, 0); + IUFillNumberVector(&HorizontalCoordsNP, HorizontalCoordsN, 2, getDeviceName(), "HORIZONTAL_COORD", "Horizontal Coord", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); - controller->initProperties(); + SetParkDataType(PARK_AZ_ALT); addAuxControls(); @@ -142,139 +143,233 @@ INDI::Telescope::ISGetProperties(dev); if (isConnected()) - defineSwitch(&SlewModeSP); - - controller->ISGetProperties(dev); + { + defineNumber(&HorizontalCoordsNP); + defineSwitch(&SlewRateSP); + if (fwInfo.Version != "Invalid") + defineText(&FirmwareTP); + } } bool CelestronGPS::updateProperties() { - INDI::Telescope::updateProperties(); + TelescopeCapability cap; + cap.canPark = true; + cap.canSync = true; + cap.canAbort = true; + cap.hasTime = true; + cap.hasLocation = true; + cap.nSlewRate= 9; + + + if (get_celestron_firmware(PortFD, &fwInfo)) + { + IUSaveText(&FirmwareT[FW_MODEL], fwInfo.Model.c_str()); + IUSaveText(&FirmwareT[FW_VERSION], fwInfo.Version.c_str()); + IUSaveText(&FirmwareT[FW_GPS], fwInfo.GPSFirmware.c_str()); + IUSaveText(&FirmwareT[FW_RA], fwInfo.RAFirmware.c_str()); + IUSaveText(&FirmwareT[FW_DEC], fwInfo.DEFirmware.c_str()); + } + else + { + fwInfo.Version = "Invalid"; + DEBUG(INDI::Logger::DBG_WARNING, "Failed to retrive firmware information."); + } - if (isConnected()) + if (fwInfo.controllerVersion <= 4.1) { - defineSwitch(&SlewModeSP); - loadConfig(true); + DEBUG(INDI::Logger::DBG_WARNING, "Mount firmware does not support sync."); + cap.canSync = false; } - else - deleteProperty(SlewModeSP.name); - controller->updateProperties(); + if (fwInfo.controllerVersion < 2.3) + { + DEBUG(INDI::Logger::DBG_WARNING, "Mount firmware does not support update of time and location settings."); + cap.hasTime = cap.hasLocation = false; + } - return true; -} + SetTelescopeCapability(&cap); -bool CelestronGPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - if(strcmp(dev,getDeviceName())==0) + INDI::Telescope::updateProperties(); + + if (isConnected()) { - // Slew mode - if (!strcmp (name, SlewModeSP.name)) - { - int index=0; + defineNumber(&HorizontalCoordsNP); + if (fwInfo.Version != "Invalid") + defineText(&FirmwareTP); - IUResetSwitch(&SlewModeSP); - IUUpdateSwitch(&SlewModeSP, states, names, n); - index = IUFindOnSwitchIndex(&SlewModeSP); - if (isSimulation() == false) - SetRate(index); - SlewModeSP.s = IPS_OK; - IDSetSwitch(&SlewModeSP, NULL); - return true; + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(0); + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); } - + } + else + { + deleteProperty(HorizontalCoordsNP.name); + if (fwInfo.Version != "Invalid") + deleteProperty(FirmwareTP.name); } - controller->ISNewSwitch(dev, name, states, names, n); + if (fwInfo.controllerVersion >= 2.3) + { + double utc_offset; + int yy, dd, mm, hh, minute, ss; + if (get_celestron_utc_date_time(PortFD, &utc_offset, &yy, &mm, &dd, &hh, &minute, &ss)) + { + char isoDateTime[32]; + char utcOffset[8]; - return INDI::Telescope::ISNewSwitch(dev, name, states, names, n); -} + snprintf(isoDateTime, 32, "%04d-%02d-%02dT%02d:%02d:%02d", yy, mm, dd, hh, minute, ss); + snprintf(utcOffset, 8, "%4.2f", utc_offset); + IUSaveText(IUFindText(&TimeTP, "UTC"), isoDateTime); + IUSaveText(IUFindText(&TimeTP, "OFFSET"), utcOffset); -bool CelestronGPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - controller->ISNewText(dev, name, texts, names, n); + DEBUGF(INDI::Logger::DBG_SESSION, "Mount UTC offset is %s. UTC time is %s", utcOffset, isoDateTime); + + IDSetText(&TimeTP, NULL); + } + } - return INDI::Telescope::ISNewText(dev, name, texts, names, n); + return true; } bool CelestronGPS::Goto(double ra, double dec) { - int i=0; char RAStr[32], DecStr[32]; targetRA = ra; targetDEC = dec; - if (EqNP.s == IPS_BUSY) + if (EqNP.s == IPS_BUSY || MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { - if (isSimulation() == false) - StopNSEW(); + abort_celestron(PortFD); // sleep for 500 mseconds usleep(500000); } - if (isSimulation() == false && (i = SlewToCoords(targetRA, targetDEC))) + if (slew_celestron(PortFD, targetRA, targetDEC) == false) { - slewError(i); - return false; + DEBUG(INDI::Logger::DBG_ERROR, "Failed to slew telescope in RA/DEC."); + return false; } + HorizontalCoordsNP.s = IPS_BUSY; + TrackState = SCOPE_SLEWING; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); - IDMessage(getDeviceName(), "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr); - - if (isDebug()) - IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr); + DEBUGF(INDI::Logger::DBG_SESSION, "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr); return true; +} + +bool CelestronGPS::Sync(double ra, double dec) +{ + if (fwInfo.controllerVersion <= 4.1) + { + DEBUGF(INDI::Logger::DBG_WARNING, "Firmwre version 4.1 or higher is required to sync. Current version is %3.1f", fwInfo.controllerVersion); + return false; + } + + if (sync_celestron(PortFD, ra, dec) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Sync failed."); + return false; + } + + currentRA = ra; + currentDEC = dec; + DEBUG(INDI::Logger::DBG_SESSION, "Sync successful."); + + return true; } -bool CelestronGPS::Sync(double targetRA, double targetDEC) +bool CelestronGPS::GotoAzAlt(double az, double alt) { if (isSimulation()) { - currentRA = targetRA; - currentDEC = targetDEC; + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = az + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = alt; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + targetRA = equatorialPos.ra/15.0; + targetDEC = equatorialPos.dec; } - else if (SyncToCoords(targetRA, targetDEC)) + + if (slew_celestron_azalt(PortFD, az, alt) == false) { - IDMessage(getDeviceName(), "Sync failed."); + DEBUG(INDI::Logger::DBG_ERROR, "Failed to slew telescope in Az/Alt."); return false; } - IDMessage(getDeviceName(), "Synchronization successful."); + targetAZ = az; + targetALT= alt; + + TrackState = SCOPE_SLEWING; + + HorizontalCoordsNP.s = IPS_BUSY; + + char AZStr[16], ALTStr[16]; + fs_sexa(AZStr, targetAZ, 3, 3600); + fs_sexa(ALTStr, targetALT, 2, 3600); + DEBUGF(INDI::Logger::DBG_SESSION, "Slewing to Az %s - Alt %s", AZStr, ALTStr); + return true; } -bool CelestronGPS::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool CelestronGPS::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { - int current_move = (dir == MOTION_NORTH) ? NORTH : SOUTH; + CELESTRON_DIRECTION current_move = (dir == DIRECTION_NORTH) ? CELESTRON_N : CELESTRON_S; + CELESTRON_SLEW_RATE rate = (CELESTRON_SLEW_RATE) IUFindOnSwitchIndex(&SlewRateSP); switch (command) { case MOTION_START: - if (isSimulation() == false && StartSlew(current_move) < 0) + if (start_celestron_motion(PortFD, current_move, rate) == false) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting N/S motion direction."); return false; } else - DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (current_move == NORTH) ? "North" : "South"); + DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (current_move == CELESTRON_N) ? "North" : "South"); break; case MOTION_STOP: - if (isSimulation() == false && StopSlew(current_move) < 0) + if (stop_celestron_motion(PortFD, current_move) == false) { DEBUG(INDI::Logger::DBG_ERROR, "Error stopping N/S motion."); return false; } else - DEBUGF(INDI::Logger::DBG_SESSION, "Movement toward %s halted.", (current_move == NORTH) ? "North" : "South"); + DEBUGF(INDI::Logger::DBG_SESSION, "Movement toward %s halted.", (current_move == CELESTRON_N) ? "North" : "South"); break; } @@ -282,59 +377,74 @@ } -bool CelestronGPS::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool CelestronGPS::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { - int current_move = (dir == MOTION_WEST) ? WEST : EAST; + CELESTRON_DIRECTION current_move = (dir == DIRECTION_WEST) ? CELESTRON_W : CELESTRON_E; + CELESTRON_SLEW_RATE rate = (CELESTRON_SLEW_RATE) IUFindOnSwitchIndex(&SlewRateSP); switch (command) { case MOTION_START: - if (isSimulation() == false && StartSlew(current_move) < 0) + if (start_celestron_motion(PortFD, current_move, rate) == false) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting W/E motion direction."); return false; } else - DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (current_move == WEST) ? "West" : "East"); + DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (current_move == CELESTRON_W) ? "West" : "East"); break; case MOTION_STOP: - if (isSimulation() == false && StopSlew(current_move) < 0) + if (stop_celestron_motion(PortFD, current_move) == false) { DEBUG(INDI::Logger::DBG_ERROR, "Error stopping W/E motion."); return false; } else - DEBUGF(INDI::Logger::DBG_SESSION, "Movement toward %s halted.", (current_move == WEST) ? "West" : "East"); + DEBUGF(INDI::Logger::DBG_SESSION, "Movement toward %s halted.", (current_move == CELESTRON_W) ? "West" : "East"); break; } return true; - } bool CelestronGPS::ReadScopeStatus() { if (isSimulation()) + mountSim(); + + if (get_celestron_coords(PortFD, ¤tRA, ¤tDEC) == false) { - mountSim(); - return true; + DEBUG(INDI::Logger::DBG_ERROR, "Failed to read RA/DEC values."); + return false; } - if (CheckConnectTel() == -1) + if (get_celestron_coords_azalt(PortFD, ¤tAZ, ¤tALT) == false) + DEBUG(INDI::Logger::DBG_WARNING, "Failed to read AZ/ALT values."); + else { - IDMessage(getDeviceName(), "Problem communication with the mount."); - return false; + HorizontalCoordsN[AXIS_AZ].value = currentAZ; + HorizontalCoordsN[AXIS_ALT].value = currentALT; } switch (TrackState) { case SCOPE_SLEWING: // are we done? - if (isScopeSlewing() == 0) + if (is_scope_slewing(PortFD) == false) { - IDMessage(getDeviceName(), "Slew complete, tracking..."); + DEBUG(INDI::Logger::DBG_SESSION, "Slew complete, tracking..."); TrackState = SCOPE_TRACKING; + HorizontalCoordsNP.s = IPS_OK; + } + break; + + case SCOPE_PARKING: + // are we done? + if (is_scope_slewing(PortFD) == false) + { + SetParked(true); + HorizontalCoordsNP.s = IPS_OK; } break; @@ -342,10 +452,7 @@ break; } - - currentRA = GetRA(); - currentDEC = GetDec(); - + IDSetNumber(&HorizontalCoordsNP, NULL); NewRaDec(currentRA, currentDEC); return true; @@ -353,31 +460,11 @@ bool CelestronGPS::Abort() { - if (isSimulation() == false) - { - StopNSEW(); - StopSlew(NORTH); - StopSlew(SOUTH); - StopSlew(WEST); - StopSlew(EAST); - } - - TrackState = SCOPE_IDLE; - - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY) - { - MovementNSSP.s = MovementWESP.s = EqNP.s = IPS_IDLE; - IUResetSwitch(&MovementNSSP); - IUResetSwitch(&MovementWESP); - - IDSetSwitch(&MovementNSSP, NULL); - IDSetSwitch(&MovementWESP, NULL); - IDSetNumber(&EqNP, NULL); - - IDMessage(getDeviceName(), "Slew stopped."); - } - - return true; + stop_celestron_motion(PortFD, CELESTRON_N); + stop_celestron_motion(PortFD, CELESTRON_S); + stop_celestron_motion(PortFD, CELESTRON_W); + stop_celestron_motion(PortFD, CELESTRON_E); + return abort_celestron(PortFD); } bool CelestronGPS::Connect() @@ -386,7 +473,7 @@ if(isConnected()) return true; - rc=Connect(PortT[0].text); + rc=Connect(PortT[0].text, atoi(IUFindOnSwitch(&BaudRateSP)->name)); if(rc) SetTimer(POLLMS); @@ -394,31 +481,96 @@ return rc; } -bool CelestronGPS::Connect(char *port) +bool CelestronGPS::Connect(const char *port, uint16_t baud) { if (isSimulation()) { - IDMessage (getDeviceName(), "Simulated Celestron GPS is online. Retrieving basic data..."); - currentRA = 0; currentDEC=90; - return true; + set_celestron_device(getDeviceName()); + set_celestron_simulation(true); + set_sim_slew_rate(SR_5); + set_sim_ra(0); + set_sim_dec(90); } - - if (ConnectTel(port) < 0) + else if (tty_connect(port, baud, 8, 0, 1, &PortFD) != TTY_OK) { - IDMessage(getDeviceName(), "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); + DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to the port.", port); return false; } - IDMessage (getDeviceName(), "Telescope is online."); + if (check_celestron_connection(PortFD) == false) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Failed to connect to telescope port %s. Ensure telescope is powered and connected.", port); + return false; + } + + DEBUG(INDI::Logger::DBG_SESSION, "Telescope is online."); + + return true; - return true; } bool CelestronGPS::Disconnect() { - if (isSimulation() == false) - DisconnectTel(); + if (PortFD > 0) + tty_disconnect(PortFD); + + return true; +} + + +bool CelestronGPS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + double newAlt=0, newAz=0; + if(!strcmp(dev,getDeviceName())) + { + if ( !strcmp (name, HorizontalCoordsNP.name) ) + { + int i=0, nset=0; + + for (nset = i = 0; i < n; i++) + { + INumber *horp = IUFindNumber (&HorizontalCoordsNP, names[i]); + if (horp == &HorizontalCoordsN[AXIS_AZ]) + { + newAz = values[i]; + nset += newAz >= 0. && newAz <= 360.0; + + } else if (horp == &HorizontalCoordsN[AXIS_ALT]) + { + newAlt = values[i]; + nset += newAlt >= -90. && newAlt <= 90.0; + } + } + + if (nset == 2) + { + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, newAz, 3, 3600); + fs_sexa(AltStr, newAlt, 2, 3600); + + if (GotoAzAlt(newAz, newAlt) == false) + { + HorizontalCoordsNP.s = IPS_ALERT; + DEBUGF(INDI::Logger::DBG_ERROR, "Error slewing to Az: %s Alt: %s", AzStr, AltStr); + IDSetNumber(&HorizontalCoordsNP, NULL); + return false; + } + + return true; + + } + else + { + HorizontalCoordsNP.s = IPS_ALERT; + DEBUG(INDI::Logger::DBG_ERROR, "Altitude or Azimuth missing or invalid"); + IDSetNumber(&HorizontalCoordsNP, NULL); + return false; + } + } + } + + INDI::Telescope::ISNewNumber (dev, name, values, names, n); return true; } @@ -426,7 +578,7 @@ { static struct timeval ltv; struct timeval tv; - double dt, da, dx; + double dt,dx,da_ra=0, da_dec=0; int nlocked; /* update elapsed time since last poll, don't presume exactly POLLMS */ @@ -437,7 +589,101 @@ dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; - da = SLEWRATE*dt; + + if ( fabs(targetRA - currentRA)*15. >= GOTO_LIMIT ) + da_ra = GOTO_RATE *dt; + else if ( fabs(targetRA - currentRA)*15. >= SLEW_LIMIT ) + da_ra = SLEW_RATE *dt; + else + da_ra = FINE_SLEW_RATE *dt; + + if ( fabs(targetDEC - currentDEC) >= GOTO_LIMIT ) + da_dec = GOTO_RATE *dt; + else if ( fabs(targetDEC - currentDEC) >= SLEW_LIMIT ) + da_dec = SLEW_RATE *dt; + else + da_dec = FINE_SLEW_RATE *dt; + + if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) + { + int rate = IUFindOnSwitchIndex(&SlewRateSP); + + switch (rate) + { + case SLEW_GUIDE: + da_ra = FINE_SLEW_RATE *dt*0.05; + da_dec = FINE_SLEW_RATE *dt*0.05; + break; + + case SLEW_CENTERING: + da_ra = FINE_SLEW_RATE *dt*.1; + da_dec = FINE_SLEW_RATE *dt*.1; + break; + + case SLEW_FIND: + da_ra = SLEW_RATE *dt; + da_dec = SLEW_RATE *dt; + break; + + default: + da_ra = GOTO_RATE *dt; + da_dec = GOTO_RATE *dt; + break; + } + + switch (MovementNSSP.s) + { + case IPS_BUSY: + if (MovementNSS[DIRECTION_NORTH].s == ISS_ON) + currentDEC += da_dec; + else if (MovementNSS[DIRECTION_SOUTH].s == ISS_ON) + currentDEC -= da_dec; + + break; + } + + switch (MovementWESP.s) + { + case IPS_BUSY: + + if (MovementWES[DIRECTION_WEST].s == ISS_ON) + currentRA += da_ra/15.; + else if (MovementWES[DIRECTION_EAST].s == ISS_ON) + currentRA -= da_ra/15.; + + break; + } + + set_sim_ra(currentRA); + set_sim_dec(currentDEC); + + ln_equ_posn equatorialPos; + equatorialPos.ra = currentRA * 15; + equatorialPos.dec = currentDEC; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_hrz_posn horizontalPos; + + ln_get_hrz_from_equ(&equatorialPos, &observer, ln_get_julian_from_sys(), &horizontalPos); + + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az -= 180; + if (horizontalPos.az < 0) + horizontalPos.az += 360; + + set_sim_az(horizontalPos.az); + set_sim_alt(horizontalPos.alt); + + NewRaDec(currentRA, currentDEC); + return; + } /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ switch (TrackState) @@ -445,242 +691,183 @@ case SCOPE_TRACKING: /* RA moves at sidereal, Dec stands still */ - currentRA += (SIDRATE*dt/15.); + currentRA += (SID_RATE*dt/15.); break; case SCOPE_SLEWING: + case SCOPE_PARKING: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; dx = targetRA - currentRA; - if (fabs(dx) <= da) + // Take shortest path + if (fabs(dx) > 12) + dx *= -1; + + if (fabs(dx) <= da_ra) { currentRA = targetRA; nlocked++; } else if (dx > 0) - currentRA += da/15.; + currentRA += da_ra/15.; else - currentRA -= da/15.; + currentRA -= da_ra/15.; + + if (currentRA < 0) + currentRA += 24; + else if (currentRA > 24) + currentRA -= 24; dx = targetDEC - currentDEC; - if (fabs(dx) <= da) + if (fabs(dx) <= da_dec) { currentDEC = targetDEC; nlocked++; } else if (dx > 0) - currentDEC += da; + currentDEC += da_dec; else - currentDEC -= da; + currentDEC -= da_dec; if (nlocked == 2) { - IDMessage(getDeviceName(), "Simulated telescope slew is complete, tracking..."); - TrackState = SCOPE_TRACKING; + set_sim_slewing(false); } - break; default: break; } - NewRaDec(currentRA, currentDEC); + set_sim_ra(currentRA); + set_sim_dec(currentDEC); + ln_equ_posn equatorialPos; + equatorialPos.ra = currentRA * 15; + equatorialPos.dec = currentDEC; -} + ln_lnlat_posn observer; -void CelestronGPS::slewError(int slewCode) -{ + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; - switch (slewCode) - { - case 1: - IDMessage (getDeviceName(), "Invalid newDec in SlewToCoords"); - break; - case 2: - IDMessage (getDeviceName(), "RA count overflow in SlewToCoords"); - break; - case 3: - IDMessage (getDeviceName(), "Dec count overflow in SlewToCoords"); - break; - case 4: - IDMessage (getDeviceName(), "No acknowledgment from telescope after SlewToCoords"); - break; - default: - IDMessage (getDeviceName(), "Unknown error"); - break; - } + if (observer.lng > 180) + observer.lng -= 360; + + ln_hrz_posn horizontalPos; + + ln_get_hrz_from_equ(&equatorialPos, &observer, ln_get_julian_from_sys(), &horizontalPos); + + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az -= 180; + if (horizontalPos.az < 0) + horizontalPos.az += 360; + set_sim_az(horizontalPos.az); + set_sim_alt(horizontalPos.alt); } -bool CelestronGPS::ISSnoopDevice(XMLEle *root) +void CelestronGPS::simulationTriggered(bool enable) { - controller->ISSnoopDevice(root); - - return INDI::Telescope::ISSnoopDevice(root); + set_celestron_simulation(enable); } -void CelestronGPS::processButton(const char *button_n, ISState state) +bool CelestronGPS::updateLocation(double latitude, double longitude, double elevation) { - //ignore OFF - if (state == ISS_OFF) - return; + INDI_UNUSED(elevation); - // Max Slew speed - if (!strcmp(button_n, "Slew Max")) - { - SetRate(0); - IUResetSwitch(&SlewModeSP); - SlewModeS[0].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Find Slew speed - else if (!strcmp(button_n, "Slew Find")) + if (fwInfo.controllerVersion < 2.3) { - SetRate(1); - IUResetSwitch(&SlewModeSP); - SlewModeS[1].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Centering Slew - else if (!strcmp(button_n, "Slew Centering")) - { - SetRate(2); - IUResetSwitch(&SlewModeSP); - SlewModeS[2].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Guide Slew - else if (!strcmp(button_n, "Slew Guide")) - { - SetRate(3); - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + DEBUGF(INDI::Logger::DBG_WARNING, "Firmwre version 2.3 or higher is required to update location. Current version is %3.1f", fwInfo.controllerVersion); + return false; } - // Abort - else if (!strcmp(button_n, "Abort Motion")) - { - // Only abort if we have some sort of motion going on - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY) - { - Abort(); - } - } + return (set_celestron_location(PortFD, longitude, latitude)); } -void CelestronGPS::processNSWE(double mag, double angle) +bool CelestronGPS::updateTime(ln_date *utc, double utc_offset) { - if (mag < 0.5) + if (fwInfo.controllerVersion < 2.3) { - // Moving in the same direction will make it stop - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - Abort(); + DEBUGF(INDI::Logger::DBG_WARNING, "Firmwre version 2.3 or higher is required to update time. Current version is %3.1f", fwInfo.controllerVersion); + return false; } - // Put high threshold - else if (mag > 0.9) - { - // North - if (angle > 0 && angle < 180) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON) - MoveNS(MOTION_NORTH, MOTION_START); - MovementNSSP.s = IPS_BUSY; - MovementNSSP.sp[0].s = ISS_ON; - MovementNSSP.sp[1].s = ISS_OFF; - IDSetSwitch(&MovementNSSP, NULL); - } - // South - if (angle > 180 && angle < 360) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON) - MoveNS(MOTION_SOUTH, MOTION_START); - - MovementNSSP.s = IPS_BUSY; - MovementNSSP.sp[0].s = ISS_OFF; - MovementNSSP.sp[1].s = ISS_ON; - IDSetSwitch(&MovementNSSP, NULL); - } - // East - if (angle < 90 || angle > 270) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON) - MoveWE(MOTION_EAST, MOTION_START); - - MovementWESP.s = IPS_BUSY; - MovementWESP.sp[0].s = ISS_OFF; - MovementWESP.sp[1].s = ISS_ON; - IDSetSwitch(&MovementWESP, NULL); - } - - // West - if (angle > 90 && angle < 270) - { + return (set_celestron_datetime(PortFD, utc, utc_offset)); +} - // Don't try to move if you're busy and moving in the same direction - if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON) - MoveWE(MOTION_WEST, MOTION_START); +bool CelestronGPS::Park() +{ + if (GotoAzAlt(GetAxis1Park(), GetAxis2Park())) + { + TrackState = SCOPE_PARKING; + DEBUG(INDI::Logger::DBG_SESSION, "Parking is in progress..."); - MovementWESP.s = IPS_BUSY; - MovementWESP.sp[0].s = ISS_ON; - MovementWESP.sp[1].s = ISS_OFF; - IDSetSwitch(&MovementWESP, NULL); - } + return true; } - + else + return false; } -bool CelestronGPS::saveConfigItems(FILE *fp) +bool CelestronGPS::UnPark() { - INDI::Telescope::saveConfigItems(fp); + double parkAZ = GetAxis1Park(); + double parkAlt = GetAxis2Park(); - controller->saveConfigItems(fp); + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Unparking from Az (%s) Alt (%s)...", AzStr, AltStr); - return true; -} + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = parkAZ + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = parkAlt; -bool CelestronGPS::updateLocation(double latitude, double longitude, double elevation) -{ - INDI_UNUSED(elevation); + ln_lnlat_posn observer; - if (isSimulation()) - return true; + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; - return (::updateLocation(longitude, latitude) == 0); -} + if (observer.lng > 180) + observer.lng -= 360; -bool CelestronGPS::updateTime(ln_date *utc, double utc_offset) -{ - if (isSimulation()) + ln_equ_posn equatorialPos; + + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + char RAStr[16], DEStr[16]; + fs_sexa(RAStr, equatorialPos.ra/15.0, 2, 3600); + fs_sexa(DEStr, equatorialPos.dec, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Syncing to parked coordinates RA (%s) DEC (%s)...", RAStr, DEStr); + + if (Sync(equatorialPos.ra/15.0, equatorialPos.dec)) + { + SetParked(false); return true; + } + else + return false; - return (::updateTime(utc, utc_offset) == 0); } -void CelestronGPS::processJoystick(const char * joystick_n, double mag, double angle) +void CelestronGPS::SetCurrentPark() { - if (!strcmp(joystick_n, "NSWE Control")) - processNSWE(mag, angle); + SetAxis1Park(currentAZ); + SetAxis2Park(currentALT); } - -void CelestronGPS::joystickHelper(const char * joystick_n, double mag, double angle, void *context) +void CelestronGPS::SetDefaultPark() { - static_cast(context)->processJoystick(joystick_n, mag, angle); + // By defualt azimuth 0 + SetAxis1Park(0); -} - -void CelestronGPS::buttonHelper(const char * button_n, ISState state, void *context) -{ - static_cast(context)->processButton(button_n, state); + // Altitude = latitude of observer + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); } diff -Nru libindi-1.0.0/drivers/telescope/celestrongps.h libindi-1.1.0/drivers/telescope/celestrongps.h --- libindi-1.0.0/drivers/telescope/celestrongps.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/celestrongps.h 2015-09-06 13:17:35.000000000 +0000 @@ -26,6 +26,8 @@ #include "indicom.h" #include "indicontroller.h" +#include "celestrondriver.h" + #define POLLMS 1000 /* poll period, ms */ class CelestronGPS : public INDI::Telescope @@ -36,60 +38,51 @@ virtual const char *getDefaultName(); virtual bool Connect(); - virtual bool Connect(char *); + virtual bool Connect(const char * port, uint16_t baud); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual void ISGetProperties(const char *dev); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool initProperties(); virtual bool updateProperties(); - virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual bool ISSnoopDevice(XMLEle *root); - - static void joystickHelper(const char * joystick_n, double mag, double angle, void *context); - static void buttonHelper(const char * button_n, ISState state, void *context); protected: - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + // Goto, Sync, and Motion + bool Goto(double ra,double dec); + bool GotoAzAlt(double az, double alt); + bool Sync(double ra, double dec); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); virtual bool Abort(); + // Time and Location virtual bool updateLocation(double latitude, double longitude, double elevation); virtual bool updateTime(ln_date *utc, double utc_offset); - virtual bool saveConfigItems(FILE *fp); + // Parking + virtual bool Park(); + virtual bool UnPark(); + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); - bool Goto(double ra,double dec); - bool Sync(double ra, double dec); + virtual void simulationTriggered(bool enable); - void slewError(int slewCode); void mountSim(); - void processNSWE(double mag, double angle); - void processJoystick(const char * joystick_n, double mag, double angle); - void processButton(const char * button_n, ISState state); - - - /* Slew Speed */ - ISwitchVectorProperty SlewModeSP; - ISwitch SlewModeS[4]; - - -private: - int timeFormat; - - double lastRA; - double lastDEC; - - INDI::Controller *controller; - - int lastSet; - int currentSet; - double currentRA, currentDEC; - double targetRA, targetDEC; - + /* Firmware */ + IText FirmwareT[5]; + ITextVectorProperty FirmwareTP; + + INumberVectorProperty HorizontalCoordsNP; + INumber HorizontalCoordsN[2]; + +private: + int PortFD; + double currentRA, currentDEC, currentAZ, currentALT; + double targetRA, targetDEC, targetAZ, targetALT; + FirmwareInfo fwInfo; }; diff -Nru libindi-1.0.0/drivers/telescope/ieq45.cpp libindi-1.1.0/drivers/telescope/ieq45.cpp --- libindi-1.0.0/drivers/telescope/ieq45.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/ieq45.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -189,7 +189,7 @@ IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); //Track MODE - IUFillSwitch(&TrackModeS[0],"SIDERAL", "Sidereal", ISS_ON); + IUFillSwitch(&TrackModeS[0],"SIDEREAL", "Sidereal", ISS_ON); IUFillSwitch(&TrackModeS[1],"LUNAR","Lunar", ISS_OFF); IUFillSwitch(&TrackModeS[2],"SOLAR", "Solar", ISS_OFF); IUFillSwitch(&TrackModeS[3],"ZERO", "Stop", ISS_OFF); diff -Nru libindi-1.0.0/drivers/telescope/ieqpro.cpp libindi-1.1.0/drivers/telescope/ieqpro.cpp --- libindi-1.0.0/drivers/telescope/ieqpro.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/ieqpro.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,978 @@ +/* + INDI IEQ Pro driver + + Copyright (C) 2015 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 +#include +#include +#include +#include +#include + +#include "indicom.h" +#include "ieqpro.h" + +/* Simulation Parameters */ +#define SLEWRATE 1 /* slew rate, degrees/s */ +#define SIDRATE 0.004178 /* sidereal rate, degrees/s */ + +#define MOUNTINFO_TAB "Mount Info" + +// We declare an auto pointer to IEQPro. +std::auto_ptr scope(0); + +void ISInit() +{ + static int isInit =0; + + if (isInit == 1) + return; + + isInit = 1; + if(scope.get() == 0) scope.reset(new IEQPro()); +} + +void ISGetProperties(const char *dev) +{ + ISInit(); + scope->ISGetProperties(dev); +} + +void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) +{ + ISInit(); + scope->ISNewSwitch(dev, name, states, names, num); +} + +void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) +{ + ISInit(); + scope->ISNewText(dev, name, texts, names, num); +} + +void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) +{ + ISInit(); + scope->ISNewNumber(dev, name, values, names, num); +} + +void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + INDI_UNUSED(dev); + INDI_UNUSED(name); + INDI_UNUSED(sizes); + INDI_UNUSED(blobsizes); + INDI_UNUSED(blobs); + INDI_UNUSED(formats); + INDI_UNUSED(names); + INDI_UNUSED(n); +} +void ISSnoopDevice (XMLEle *root) +{ + scope->ISSnoopDevice(root); +} + +/* Constructor */ +IEQPro::IEQPro() +{ + timeUpdated = locationUpdated = false; + + set_ieqpro_device(getDeviceName()); + + //ctor + currentRA=ln_get_apparent_sidereal_time(ln_get_julian_from_sys()); + currentDEC=90; + + scopeInfo.gpsStatus = GPS_OFF; + scopeInfo.systemStatus = ST_STOPPED; + scopeInfo.trackRate = TR_SIDEREAL; + scopeInfo.slewRate = SR_1; + scopeInfo.timeSource = TS_RS232; + scopeInfo.hemisphere = HEMI_NORTH; + + DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); + + TelescopeCapability cap; + + cap.canPark = true; + cap.canSync = true; + cap.canAbort = true; + cap.hasLocation = true; + cap.hasTime = true; + cap.nSlewRate= 9; + + SetTelescopeCapability(&cap); +} + +IEQPro::~IEQPro() +{ +} + +const char *IEQPro::getDefaultName() +{ + return (const char *) "iEQ"; +} + +bool IEQPro::initProperties() +{ + INDI::Telescope::initProperties(); + + /* Firmware */ + IUFillText(&FirmwareT[FW_MODEL], "Model", "", 0); + IUFillText(&FirmwareT[FW_BOARD], "Board", "", 0); + IUFillText(&FirmwareT[FW_CONTROLLER], "Controller", "", 0); + IUFillText(&FirmwareT[FW_RA], "RA", "", 0); + IUFillText(&FirmwareT[FW_DEC], "DEC", "", 0); + IUFillTextVector(&FirmwareTP, FirmwareT, 5, getDeviceName(), "Firmware Info", "", MOUNTINFO_TAB, IP_RO, 0, IPS_IDLE); + + /* Tracking Mode */ + IUFillSwitch(&TrackModeS[TRACK_SIDEREAL], "TRACK_SIDEREAL", "Sidereal", ISS_ON); + IUFillSwitch(&TrackModeS[TRACK_SOLAR], "TRACK_SOLAR", "Solar", ISS_OFF); + IUFillSwitch(&TrackModeS[TRACK_LUNAR], "TRACK_LUNAR", "Lunar", ISS_OFF); + IUFillSwitch(&TrackModeS[TRACK_CUSTOM], "TRACK_CUSTOM", "Custom", ISS_OFF); + IUFillSwitchVector(&TrackModeSP, TrackModeS, 4, getDeviceName(), "TELESCOPE_TRACK_RATE", "Tracking Mode", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + /* Custom Tracking Rate */ + IUFillNumber(&CustomTrackRateN[0],"CUSTOM_RATE","Rate","%g",-0.0100, 0.0100, 0.005, 0); + IUFillNumberVector(&CustomTrackRateNP, CustomTrackRateN,1,getDeviceName(),"CUSTOM_RATE","Custom Track",MOTION_TAB,IP_RW,60,IPS_IDLE); + + /* GPS Status */ + IUFillSwitch(&GPSStatusS[GPS_OFF], "Off", "", ISS_ON); + IUFillSwitch(&GPSStatusS[GPS_ON], "On", "", ISS_OFF); + IUFillSwitch(&GPSStatusS[GPS_DATA_OK], "Data OK", "", ISS_OFF); + IUFillSwitchVector(&GPSStatusSP, GPSStatusS, 3, getDeviceName(), "GPS_STATUS", "GPS", MOUNTINFO_TAB, IP_RO, ISR_1OFMANY, 0, IPS_IDLE); + + /* Time Source */ + IUFillSwitch(&TimeSourceS[TS_RS232], "RS232", "", ISS_ON); + IUFillSwitch(&TimeSourceS[TS_CONTROLLER], "Controller", "", ISS_OFF); + IUFillSwitch(&TimeSourceS[TS_GPS], "GPS", "", ISS_OFF); + IUFillSwitchVector(&TimeSourceSP, TimeSourceS, 3, getDeviceName(), "TIME_SOURCE", "Time Source", MOUNTINFO_TAB, IP_RO, ISR_1OFMANY, 0, IPS_IDLE); + + /* Hemisphere */ + IUFillSwitch(&HemisphereS[HEMI_SOUTH], "South", "", ISS_OFF); + IUFillSwitch(&HemisphereS[HEMI_NORTH], "North", "", ISS_ON); + IUFillSwitchVector(&HemisphereSP, HemisphereS, 2, getDeviceName(), "HEMISPHERE", "Hemisphere", MOUNTINFO_TAB, IP_RO, ISR_1OFMANY, 0, IPS_IDLE); + + /* Home */ + IUFillSwitch(&HomeS[IEQ_FIND_HOME], "FindHome", "Find Home", ISS_OFF); + IUFillSwitch(&HomeS[IEQ_SET_HOME], "SetCurrentAsHome", "Set current as Home", ISS_OFF); + IUFillSwitch(&HomeS[IEQ_GOTO_HOME], "GoToHome", "Go to Home", ISS_OFF); + IUFillSwitchVector(&HomeSP, HomeS, 3, getDeviceName(), "HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + /* How fast do we guide compared to sidereal rate */ + IUFillNumber(&GuideRateN[0], "GUIDE_RATE", "x Sidereal", "%g", 0.1, 0.9, 0.1, 0.5); + IUFillNumberVector(&GuideRateNP, GuideRateN, 1, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0, IPS_IDLE); + + TrackState=SCOPE_IDLE; + + initGuiderProperties(getDeviceName(), MOTION_TAB); + + setInterfaceDescriptor(getInterfaceDescriptor() | GUIDER_INTERFACE); + + SetParkDataType(PARK_RA_DEC); + + addAuxControls(); + + return true; +} + +bool IEQPro::updateProperties() +{ + INDI::Telescope::updateProperties(); + + if (isConnected()) + { + defineSwitch(&HomeSP); + + defineSwitch(&TrackModeSP); + defineNumber(&CustomTrackRateNP); + + defineNumber(&GuideNSNP); + defineNumber(&GuideWENP); + defineNumber(&GuideRateNP); + + defineText(&FirmwareTP); + defineSwitch(&GPSStatusSP); + defineSwitch(&TimeSourceSP); + defineSwitch(&HemisphereSP); + + getStartupData(); + } + else + { + deleteProperty(HomeSP.name); + + deleteProperty(TrackModeSP.name); + deleteProperty(CustomTrackRateNP.name); + + deleteProperty(GuideNSNP.name); + deleteProperty(GuideWENP.name); + deleteProperty(GuideRateNP.name); + + deleteProperty(FirmwareTP.name); + deleteProperty(GPSStatusSP.name); + deleteProperty(TimeSourceSP.name); + deleteProperty(HemisphereSP.name); + } + + return true; +} + +void IEQPro::getStartupData() +{ + DEBUG(INDI::Logger::DBG_DEBUG, "Getting firmware data..."); + if (get_ieqpro_firmware(PortFD, &firmwareInfo)) + { + IUSaveText(&FirmwareT[0], firmwareInfo.Model.c_str()); + IUSaveText(&FirmwareT[1], firmwareInfo.MainBoardFirmware.c_str()); + IUSaveText(&FirmwareT[2], firmwareInfo.ControllerFirmware.c_str()); + IUSaveText(&FirmwareT[3], firmwareInfo.RAFirmware.c_str()); + IUSaveText(&FirmwareT[4], firmwareInfo.DEFirmware.c_str()); + + FirmwareTP.s = IPS_OK; + IDSetText(&FirmwareTP, NULL); + } + + DEBUG(INDI::Logger::DBG_DEBUG, "Getting guiding rate..."); + double guideRate=0; + if (get_ieqpro_guide_rate(PortFD, &guideRate)) + { + GuideRateN[0].value = guideRate; + IDSetNumber(&GuideRateNP, NULL); + } + + double HA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys()); + double DEC = (HemisphereS[HEMI_NORTH].s == ISS_ON) ? 90 : -90; + + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(HA); + SetAxis2ParkDefault(DEC); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(HA); + SetAxis2Park(DEC); + SetAxis1ParkDefault(HA); + SetAxis2ParkDefault(DEC); + } + + double utc_offset; + int yy, dd, mm, hh, minute, ss; + if (get_ieqpro_utc_date_time(PortFD, &utc_offset, &yy, &mm, &dd, &hh, &minute, &ss)) + { + char isoDateTime[32]; + char utcOffset[8]; + + snprintf(isoDateTime, 32, "%04d-%02d-%02dT%02d:%02d:%02d", yy, mm, dd, hh, minute, ss); + snprintf(utcOffset, 8, "%4.2f", utc_offset); + + IUSaveText(IUFindText(&TimeTP, "UTC"), isoDateTime); + IUSaveText(IUFindText(&TimeTP, "OFFSET"), utcOffset); + + DEBUGF(INDI::Logger::DBG_SESSION, "Mount UTC offset is %s. UTC time is %s", utcOffset, isoDateTime); + + IDSetText(&TimeTP, NULL); + } + + if (isSimulation()) + { + if (isParked()) + set_sim_system_status(ST_PARKED); + else + set_sim_system_status(ST_STOPPED); + } +} + +bool IEQPro::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + if (!strcmp (dev, getDeviceName())) + { + + // Custom Tracking Rate + if (!strcmp(name, CustomTrackRateNP.name)) + { + if (TrackModeS[TRACK_CUSTOM].s != ISS_ON) + { + CustomTrackRateNP.s = IPS_IDLE; + DEBUG(INDI::Logger::DBG_ERROR, "Can only set tracking rate if tracking mode is set to custom."); + IDSetNumber(&CustomTrackRateNP, NULL); + return true; + } + + IUUpdateNumber(&CustomTrackRateNP, values, names, n); + + if (set_ieqpro_custom_track_rate(PortFD, CustomTrackRateN[0].value)) + CustomTrackRateNP.s = IPS_OK; + else + CustomTrackRateNP.s = IPS_ALERT; + + IDSetNumber(&CustomTrackRateNP, NULL); + + return true; + + } + + // Guiding Rate + if (!strcmp(name, GuideRateNP.name)) + { + IUUpdateNumber(&GuideRateNP, values, names, n); + + if (set_ieqpro_guide_rate(PortFD, GuideRateN[0].value)) + GuideRateNP.s = IPS_OK; + else + GuideRateNP.s = IPS_ALERT; + + IDSetNumber(&GuideRateNP, NULL); + + return true; + } + + if (!strcmp(name,GuideNSNP.name) || !strcmp(name,GuideWENP.name)) + { + processGuiderProperties(name, values, names, n); + return true; + } + } + + return INDI::Telescope::ISNewNumber (dev, name, values, names, n); +} + +bool IEQPro::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) +{ + if (!strcmp (getDeviceName(), dev)) + { + if (!strcmp(name, HomeSP.name)) + { + IUUpdateSwitch(&HomeSP, states, names, n); + + IEQ_HOME_OPERATION operation = (IEQ_HOME_OPERATION) IUFindOnSwitchIndex(&HomeSP); + + IUResetSwitch(&HomeSP); + + switch (operation) + { + case IEQ_FIND_HOME: + if (firmwareInfo.Model.find("CEM") == std::string::npos) + { + HomeSP.s = IPS_IDLE; + IDSetSwitch(&HomeSP, NULL); + DEBUG(INDI::Logger::DBG_WARNING, "Home search is not supported in this model."); + return true; + } + + if (find_ieqpro_home(PortFD) == false) + { + HomeSP.s = IPS_ALERT; + IDSetSwitch(&HomeSP, NULL); + return false; + + } + + HomeSP.s = IPS_OK; + IDSetSwitch(&HomeSP, NULL); + DEBUG(INDI::Logger::DBG_SESSION, "Searching for home position..."); + return true; + + break; + + case IEQ_SET_HOME: + if (set_ieqpro_current_home(PortFD) == false) + { + HomeSP.s = IPS_ALERT; + IDSetSwitch(&HomeSP, NULL); + return false; + + } + + HomeSP.s = IPS_OK; + IDSetSwitch(&HomeSP, NULL); + DEBUG(INDI::Logger::DBG_SESSION, "Home position set to current coordinates."); + return true; + + break; + + case IEQ_GOTO_HOME: + if (goto_ieqpro_home(PortFD) == false) + { + HomeSP.s = IPS_ALERT; + IDSetSwitch(&HomeSP, NULL); + return false; + + } + + HomeSP.s = IPS_OK; + IDSetSwitch(&HomeSP, NULL); + DEBUG(INDI::Logger::DBG_SESSION, "Slewing to home position..."); + return true; + + break; + } + + return true; + } + + if (!strcmp(name, TrackModeSP.name)) + { + IUUpdateSwitch(&TrackModeSP, states, names, n); + + TelescopeTrackMode mode = (TelescopeTrackMode) IUFindOnSwitchIndex(&TrackModeSP); + + IEQ_TRACK_RATE rate; + + switch (mode) + { + case TRACK_SIDEREAL: + rate = TR_SIDEREAL; + break; + case TRACK_SOLAR: + rate = TR_SOLAR; + break; + case TRACK_LUNAR: + rate = TR_LUNAR; + break; + case TRACK_CUSTOM: + rate = TR_CUSTOM; + break; + } + + if (set_ieqpro_track_mode(PortFD, rate)) + { + if (TrackState == SCOPE_TRACKING) + TrackModeSP.s = IPS_BUSY; + else + TrackModeSP.s = IPS_OK; + } + else + TrackModeSP.s = IPS_ALERT; + + } + + } + + return INDI::Telescope::ISNewSwitch (dev, name, states, names, n); +} + +bool IEQPro::ReadScopeStatus() +{ + bool rc = false; + + IEQInfo newInfo; + + if (isSimulation()) + mountSim(); + + rc = get_ieqpro_status(PortFD, &newInfo); + + if (rc) + { + IUResetSwitch(&GPSStatusSP); + GPSStatusS[newInfo.gpsStatus].s = ISS_ON; + IDSetSwitch(&GPSStatusSP, NULL); + + IUResetSwitch(&TimeSourceSP); + TimeSourceS[newInfo.timeSource].s = ISS_ON; + IDSetSwitch(&TimeSourceSP, NULL); + + IUResetSwitch(&HemisphereSP); + HemisphereS[newInfo.hemisphere].s = ISS_ON; + IDSetSwitch(&HemisphereSP, NULL); + + TelescopeTrackMode trackMode; + + switch (newInfo.trackRate) + { + case TR_SIDEREAL: + trackMode = TRACK_SIDEREAL; + break; + case TR_SOLAR: + trackMode = TRACK_SOLAR; + break; + case TR_LUNAR: + trackMode = TRACK_LUNAR; + case TR_KING: + trackMode = TRACK_SIDEREAL; + break; + case TR_CUSTOM: + trackMode = TRACK_CUSTOM; + break; + } + + switch (newInfo.systemStatus) + { + case ST_STOPPED: + TrackModeSP.s = IPS_IDLE; + TrackState = SCOPE_IDLE; + break; + case ST_PARKED: + TrackModeSP.s = IPS_IDLE; + TrackState = SCOPE_PARKED; + if (isParked() == false) + SetParked(true); + break; + case ST_HOME: + TrackModeSP.s = IPS_IDLE; + TrackState = SCOPE_IDLE; + break; + case ST_SLEWING: + case ST_MERIDIAN_FLIPPING: + if (TrackState != SCOPE_SLEWING && TrackState != SCOPE_PARKING) + TrackState = SCOPE_SLEWING; + break; + case ST_TRACKING_PEC_OFF: + case ST_TRACKING_PEC_ON: + case ST_GUIDING: + TrackModeSP.s = IPS_BUSY; + TrackState = SCOPE_TRACKING; + if (scopeInfo.systemStatus == ST_SLEWING) + DEBUG(INDI::Logger::DBG_SESSION, "Slew complete, tracking..."); + else if (scopeInfo.systemStatus == ST_MERIDIAN_FLIPPING) + DEBUG(INDI::Logger::DBG_SESSION, "Meridian flip complete, tracking..."); + break; + } + + IUResetSwitch(&TrackModeSP); + TrackModeS[trackMode].s = ISS_ON; + IDSetSwitch(&TrackModeSP, NULL); + + scopeInfo = newInfo; + + } + + rc = get_ieqpro_coords(PortFD, ¤tRA, ¤tDEC); + + if (rc) + NewRaDec(currentRA, currentDEC); + + return rc; +} + +bool IEQPro::Goto(double r,double d) +{ + targetRA=r; + targetDEC=d; + char RAStr[64], DecStr[64]; + + fs_sexa(RAStr, targetRA, 2, 3600); + fs_sexa(DecStr, targetDEC, 2, 3600); + + if (set_ieqpro_ra(PortFD, r) == false || set_ieqpro_dec(PortFD, d) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting RA/DEC."); + return false; + } + + if (slew_ieqpro(PortFD) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to slew."); + return false; + } + + TrackState = SCOPE_SLEWING; + + IDMessage(getDeviceName(), "Slewing to RA: %s - DEC: %s", RAStr, DecStr); + return true; +} + +bool IEQPro::Sync(double ra, double dec) +{ + + if (set_ieqpro_ra(PortFD, ra) == false || set_ieqpro_dec(PortFD, dec) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting RA/DEC."); + return false; + } + + if (sync_ieqpro(PortFD) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to sync."); + } + + TrackState = SCOPE_IDLE; + EqNP.s = IPS_OK; + + currentRA = ra; + currentDEC = dec; + + NewRaDec(currentRA, currentDEC); + + return true; +} + +bool IEQPro::Abort() +{ + return abort_ieqpro(PortFD); +} + +bool IEQPro::Park() +{ + targetRA = GetAxis1Park(); + targetDEC = GetAxis2Park(); + if (set_ieqpro_ra(PortFD, targetRA) == false || set_ieqpro_dec(PortFD, targetDEC) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting RA/DEC."); + return false; + } + + if (park_ieqpro(PortFD)) + { + char RAStr[64], DecStr[64]; + fs_sexa(RAStr, targetRA, 2, 3600); + fs_sexa(DecStr, targetDEC, 2, 3600); + + TrackState = SCOPE_PARKING; + DEBUGF(INDI::Logger::DBG_SESSION, "Telescope parking in progress to RA: %s DEC: %s", RAStr, DecStr); + return true; + } + else + return false; +} + +bool IEQPro::UnPark() +{ + if (unpark_ieqpro(PortFD)) + { + SetParked(false); + TrackState = SCOPE_IDLE; + return true; + } + else + return false; +} + +bool IEQPro::Connect(const char *port, uint16_t baud) +{ + set_ieqpro_device(getDeviceName()); + sim = isSimulation(); + + if (sim) + { + set_sim_gps_status(GPS_DATA_OK); + set_sim_system_status(ST_STOPPED); + set_sim_track_rate(TR_SIDEREAL); + set_sim_slew_rate(SR_3); + set_sim_time_source(TS_GPS); + set_sim_hemisphere(HEMI_NORTH); + } + else if (tty_connect(port, baud, 8, 0, 1, &PortFD) != TTY_OK) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to the port.", port); + return false; + } + + if (check_ieqpro_connection(PortFD) == false) + return false; + + DEBUG(INDI::Logger::DBG_SESSION, "Telescope is online."); + + return true; +} + +bool IEQPro::Disconnect() +{ + timeUpdated = false; + locationUpdated = false; + + // Disconnect + return true; +} + +bool IEQPro::updateTime(ln_date * utc, double utc_offset) +{ + struct ln_zonedate ltm; + + ln_date_to_zonedate(utc, <m, utc_offset*3600.0); + + // Set Local Time + if (set_ieqpro_local_time(PortFD, ltm.hours, ltm.minutes, ltm.seconds) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting local time."); + return false; + } + + // Send it as YY (i.e. 2015 --> 15) + ltm.years -= 2000; + + // Set Local date + if (set_ieqpro_local_date(PortFD, ltm.years, ltm.months, ltm.days) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting local date."); + return false; + } + + // UTC Offset + if (set_ieqpro_utc_offset(PortFD, utc_offset) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting UTC Offset."); + return false; + } + + DEBUG(INDI::Logger::DBG_SESSION, "Time and date updated."); + + timeUpdated = true; + + return true; +} + +bool IEQPro::updateLocation(double latitude, double longitude, double elevation) +{ + INDI_UNUSED(elevation); + + if (longitude > 180) + longitude -= 360; + + if (set_ieqpro_longitude(PortFD, longitude) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to set longitude."); + return false; + } + + if (set_ieqpro_latitude(PortFD, latitude) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Failed to set longitude."); + return false; + } + + char l[32], L[32]; + fs_sexa (l, latitude, 3, 3600); + fs_sexa (L, longitude, 4, 3600); + + IDMessage(getDeviceName(), "Site location updated to Lat %.32s - Long %.32s", l, L); + + locationUpdated = true; + + return true; +} + +void IEQPro::debugTriggered(bool enable) +{ + set_ieqpro_debug(enable); +} + +void IEQPro::simulationTriggered(bool enable) +{ + set_ieqpro_simulation(enable); +} + +bool IEQPro::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) +{ + if (TrackState == SCOPE_PARKED) + { + DEBUG(INDI::Logger::DBG_ERROR, "Please unpark the mount before issuing any motion commands."); + return false; + } + + switch (command) + { + case MOTION_START: + if (start_ieqpro_motion(PortFD, (dir == DIRECTION_NORTH ? IEQ_N : IEQ_S)) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting N/S motion direction."); + return false; + } + else + DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (dir == DIRECTION_NORTH) ? "North" : "South"); + break; + + case MOTION_STOP: + if (stop_ieqpro_motion(PortFD, (dir == DIRECTION_NORTH ? IEQ_N : IEQ_S)) < 0) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error stopping N/S motion."); + return false; + } + else + DEBUGF(INDI::Logger::DBG_SESSION, "%s motion stopped.", (dir == DIRECTION_NORTH) ? "North" : "South"); + break; + } + + return true; +} + +bool IEQPro::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) +{ + if (TrackState == SCOPE_PARKED) + { + DEBUG(INDI::Logger::DBG_ERROR, "Please unpark the mount before issuing any motion commands."); + return false; + } + + switch (command) + { + case MOTION_START: + if (start_ieqpro_motion(PortFD, (dir == DIRECTION_WEST ? IEQ_W : IEQ_E)) == false) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error setting N/S motion direction."); + return false; + } + else + DEBUGF(INDI::Logger::DBG_SESSION,"Moving toward %s.", (dir == DIRECTION_WEST) ? "West" : "East"); + break; + + case MOTION_STOP: + if (stop_ieqpro_motion(PortFD, (dir == DIRECTION_WEST ? IEQ_W : IEQ_E)) < 0) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error stopping W/E motion."); + return false; + } + else + DEBUGF(INDI::Logger::DBG_SESSION, "%s motion stopped.", (dir == DIRECTION_WEST) ? "West" : "East"); + break; + } + + return true; +} + +IPState IEQPro::GuideNorth(float ms) +{ + bool rc = start_ieqpro_guide(PortFD, IEQ_N, (int) ms); + return (rc ? IPS_OK : IPS_ALERT); +} + +IPState IEQPro::GuideSouth(float ms) +{ + bool rc = start_ieqpro_guide(PortFD, IEQ_S, (int) ms); + return (rc ? IPS_OK : IPS_ALERT); +} + +IPState IEQPro::GuideEast(float ms) +{ + bool rc = start_ieqpro_guide(PortFD, IEQ_E, (int) ms); + return (rc ? IPS_OK : IPS_ALERT); +} + +IPState IEQPro::GuideWest(float ms) +{ + bool rc = start_ieqpro_guide(PortFD, IEQ_W, (int) ms); + return (rc ? IPS_OK : IPS_ALERT); +} + +bool IEQPro::SetSlewRate(int index) +{ + IEQ_SLEW_RATE rate = (IEQ_SLEW_RATE) index; + return set_ieqpro_slew_rate(PortFD, rate); +} + +bool IEQPro::saveConfigItems(FILE *fp) +{ + INDI::Telescope::saveConfigItems(fp); + + IUSaveConfigNumber(fp, &CustomTrackRateNP); + + return true; +} + +void IEQPro::mountSim () +{ + static struct timeval ltv; + struct timeval tv; + double dt, da, dx; + int nlocked; + + /* update elapsed time since last poll, don't presume exactly POLLMS */ + gettimeofday (&tv, NULL); + + if (ltv.tv_sec == 0 && ltv.tv_usec == 0) + ltv = tv; + + dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; + ltv = tv; + da = SLEWRATE*dt; + + /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ + switch (TrackState) + { + + case SCOPE_TRACKING: + /* RA moves at sidereal, Dec stands still */ + currentRA += (SIDRATE*dt/15.); + break; + + case SCOPE_SLEWING: + case SCOPE_PARKING: + /* slewing - nail it when both within one pulse @ SLEWRATE */ + nlocked = 0; + + dx = targetRA - currentRA; + + // Take shortest path + if (fabs(dx) > 12) + dx *= -1; + + if (fabs(dx) <= da) + { + currentRA = targetRA; + nlocked++; + } + else if (dx > 0) + currentRA += da/15.; + else + currentRA -= da/15.; + + if (currentRA < 0) + currentRA += 24; + else if (currentRA > 24) + currentRA -= 24; + + dx = targetDEC - currentDEC; + if (fabs(dx) <= da) + { + currentDEC = targetDEC; + nlocked++; + } + else if (dx > 0) + currentDEC += da; + else + currentDEC -= da; + + if (nlocked == 2) + { + if (TrackState == SCOPE_SLEWING) + set_sim_system_status(ST_TRACKING_PEC_OFF); + else + set_sim_system_status(ST_PARKED); + } + + break; + + default: + break; + } + + set_sim_ra(currentRA); + set_sim_dec(currentDEC); + +} + +void IEQPro::SetCurrentPark() +{ + SetAxis1Park(currentRA); + SetAxis2Park(currentDEC); +} + +void IEQPro::SetDefaultPark() +{ + // By default set RA to HA + SetAxis1Park(ln_get_apparent_sidereal_time(ln_get_julian_from_sys())); + + // Set DEC to 90 or -90 depending on the hemisphere + SetAxis2Park( (HemisphereS[HEMI_NORTH].s == ISS_ON) ? 90 : -90); + +} diff -Nru libindi-1.0.0/drivers/telescope/ieqprodriver.cpp libindi-1.1.0/drivers/telescope/ieqprodriver.cpp --- libindi-1.0.0/drivers/telescope/ieqprodriver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/ieqprodriver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,1820 @@ +/* + IEQ Pro driver + + Copyright (C) 2015 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "indicom.h" +#include "indidevapi.h" +#include "indilogger.h" + +#include + +#include "ieqprodriver.h" + +#define IEQPRO_TIMEOUT 5 /* FD timeout in seconds */ + +bool ieqpro_debug = false; +bool ieqpro_simulation = false; +char ieqpro_device[MAXINDIDEVICE] = "iEQ"; +IEQInfo simInfo; + +struct +{ + double ra; + double dec; + double guide_rate; +} simData; + +void set_ieqpro_debug(bool enable) +{ + ieqpro_debug = enable; +} + +void set_ieqpro_simulation(bool enable) +{ + ieqpro_simulation = enable; + if (enable) + simData.guide_rate = 0.5; +} + +void set_ieqpro_device(const char *name) +{ + strncpy(ieqpro_device, name, MAXINDIDEVICE); +} + +void set_sim_gps_status(IEQ_GPS_STATUS value) +{ + simInfo.gpsStatus = value; +} + +void set_sim_system_status(IEQ_SYSTEM_STATUS value) +{ + simInfo.systemStatus = value; +} + +void set_sim_track_rate(IEQ_TRACK_RATE value) +{ + simInfo.trackRate = value; +} + +void set_sim_slew_rate(IEQ_SLEW_RATE value) +{ + simInfo.slewRate = value; +} + +void set_sim_time_source(IEQ_TIME_SOURCE value) +{ + simInfo.timeSource = value; +} + +void set_sim_hemisphere(IEQ_HEMISPHERE value) +{ + simInfo.hemisphere = value; +} + +void set_sim_ra(double ra) +{ + simData.ra = ra; +} + +void set_sim_dec(double dec) +{ + simData.dec = dec; +} + +void set_sim_guide_rate(double rate) +{ + simData.guide_rate = rate; +} + +bool check_ieqpro_connection(int fd) +{ + char initCMD[] = ":V#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "Initializing IOptron using :V# CMD..."); + + for (int i=0; i < 2; i++) + { + if (ieqpro_simulation) + { + strcpy(response, "V1.00#"); + nbytes_read= strlen(response); + } + else + { + if ( (errcode = tty_write(fd, initCMD, 3, &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + usleep(50000); + continue; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + usleep(50000); + continue; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "V1.00#")) + return true; + } + + usleep(50000); + } + + return false; +} + +bool get_ieqpro_status(int fd, IEQInfo *info) +{ + char cmd[] = ":GAS#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_EXTRA_1, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + snprintf(response, 8, "%d%d%d%d%d%d#", simInfo.gpsStatus, simInfo.systemStatus, simInfo.trackRate, simInfo.slewRate+1, simInfo.timeSource+1, simInfo.hemisphere); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_EXTRA_1, "RES (%s)", response); + + if (nbytes_read == 7) + { + info->gpsStatus = (IEQ_GPS_STATUS) (response[0] - '0'); + info->systemStatus = (IEQ_SYSTEM_STATUS) (response[1] - '0'); + info->trackRate = (IEQ_TRACK_RATE) (response[2] - '0'); + info->slewRate = (IEQ_SLEW_RATE) (response[3] - '0' - 1); + info->timeSource = (IEQ_TIME_SOURCE) (response[4] - '0' - 1); + info->hemisphere = (IEQ_HEMISPHERE) (response[5] - '0'); + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 7.", nbytes_read); + return false; +} + +bool get_ieqpro_firmware(int fd, FirmwareInfo *info) +{ + bool rc = false; + + rc = get_ieqpro_model(fd, info); + + if (rc == false) + return rc; + + rc = get_ieqpro_main_firmware(fd, info); + + if (rc == false) + return rc; + + rc = get_ieqpro_radec_firmware(fd, info); + + return rc; +} + +bool get_ieqpro_model (int fd, FirmwareInfo *info) +{ + char cmd[] = ":MountInfo#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "0045"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 4, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (nbytes_read == 4) + { + if (!strcmp(response, "0060")) + info->Model = "CEM60"; + else if (!strcmp(response, "0061")) + info->Model = "CEM60-EC"; + else if (!strcmp(response, "0045")) + info->Model = "iEQ45 Pro"; + else if (!strcmp(response, "0046")) + info->Model = "iEQ45 Pro AA"; + else + info->Model = "Unknown"; + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 4.", nbytes_read); + return false; + +} + +bool get_ieqpro_main_firmware(int fd, FirmwareInfo *info) +{ + char cmd[] = ":FW1#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "150324150101#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (nbytes_read == 13) + { + char board[6], controller[6]; + + strncpy(board, response, 6); + strncpy(controller, response + 6, 6); + + info->MainBoardFirmware.assign(board, 6); + info->ControllerFirmware.assign(controller, 6); + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 13.", nbytes_read); + return false; +} + +bool get_ieqpro_radec_firmware(int fd, FirmwareInfo *info) +{ + char cmd[] = ":FW2#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[16]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "140324140101#"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (nbytes_read == 13) + { + char ra[6], dec[6]; + + strncpy(ra, response, 6); + strncpy(dec, response + 6, 6); + + info->RAFirmware.assign(ra, 6); + info->DEFirmware.assign(dec, 6); + + tcflush(fd, TCIFLUSH); + + return true; + } + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 13.", nbytes_read); + return false; +} + +bool start_ieqpro_motion(int fd, IEQ_DIRECTION dir) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + int nbytes_written=0; + + switch (dir) + { + case IEQ_N: + strcpy(cmd, ":mn#"); + break; + case IEQ_S: + strcpy(cmd, ":ms#"); + break; + case IEQ_W: + strcpy(cmd, ":mw#"); + break; + case IEQ_E: + strcpy(cmd, ":me#"); + break; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + return true; + + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + tcflush(fd, TCIFLUSH); + return true; +} + +bool stop_ieqpro_motion(int fd, IEQ_DIRECTION dir) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + switch (dir) + { + case IEQ_N: + case IEQ_S: + strcpy(cmd, ":qD#"); + break; + + case IEQ_W: + case IEQ_E: + strcpy(cmd, ":qR#"); + break; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool find_ieqpro_home(int fd) +{ + char cmd[] = ":MSH#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; + +} + +bool goto_ieqpro_home(int fd) +{ + char cmd[] = ":MH#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_current_home(int fd) +{ + char cmd[] = ":SZP#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; + +} + +bool set_ieqpro_slew_rate(int fd, IEQ_SLEW_RATE rate) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + snprintf(cmd, 16, ":SR%d#", ((int) rate) + 1 ); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simInfo.slewRate = rate; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_track_mode(int fd, IEQ_TRACK_RATE rate) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + switch (rate) + { + case TR_SIDEREAL: + strcpy(cmd, ":RT0#"); + break; + case TR_LUNAR: + strcpy(cmd, ":RT1#"); + break; + case TR_SOLAR: + strcpy(cmd, ":RT2#"); + break; + case TR_KING: + strcpy(cmd, ":RT3#"); + case TR_CUSTOM: + strcpy(cmd, ":RT4#"); + break; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simInfo.trackRate = rate; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_custom_track_rate(int fd, double rate) +{ + char cmd[16]; + char sign; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (rate < 0) + sign = '-'; + else + sign = '+'; + + snprintf(cmd, 16, ":RR%c%07.4f#", sign, fabs(rate )); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_guide_rate(int fd, double rate) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + int num = rate * 100; + snprintf(cmd, 16, ":RG%03d#", num ); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simData.guide_rate = rate; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool get_ieqpro_guide_rate(int fd, double *rate) +{ + char cmd[] = ":AG#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + snprintf(response, 8, "%3d#", (int) (simData.guide_rate * 100)); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 4, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + int rate_num; + + if (sscanf(response, "%d#", &rate_num) > 0) + { + *rate = rate_num / 100.0; + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Error: Malformed result (%s).", response); + return false; + } + + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool start_ieqpro_guide(int fd, IEQ_DIRECTION dir, int ms) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + char dir_c; + switch (dir) + { + case IEQ_N: + dir_c = 'n'; + break; + + case IEQ_S: + dir_c = 's'; + break; + + case IEQ_W: + dir_c = 'w'; + break; + + case IEQ_E: + dir_c = 'e'; + break; + } + + snprintf(cmd, 16, ":M%c%05d#", dir_c, ms ); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + return true; + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + tcflush(fd, TCIFLUSH); + return true; + +} + +bool park_ieqpro(int fd) +{ + char cmd[] = ":MP1#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + set_sim_system_status(ST_SLEWING); + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "1")) + { + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Error: Requested parking position is below horizon."); + return false; + } + + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool unpark_ieqpro(int fd) +{ + char cmd[] = ":MP0#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + set_sim_system_status(ST_STOPPED); + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool abort_ieqpro(int fd) +{ + char cmd[] = ":Q#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simInfo.systemStatus = ST_STOPPED; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool slew_ieqpro(int fd) +{ + char cmd[] = ":MS#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simInfo.systemStatus = ST_SLEWING; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + if (!strcmp(response, "1")) + { + tcflush(fd, TCIFLUSH); + return true; + } + else + { + DEBUGDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Requested object is below horizon."); + tcflush(fd, TCIFLUSH); + return false; + } + + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool sync_ieqpro(int fd) +{ + char cmd[] = ":CM#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_ra(int fd, double ra) +{ + char cmd[32]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + // Send as milliseconds resolution + int ieqValue = ra * 60 * 60 * 1000; + + snprintf(cmd, 32, ":Sr%08d#", ieqValue); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simData.ra = ra; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_dec(int fd, double dec) +{ + char cmd[32]; + char sign; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (dec >= 0) + sign = '+'; + else + sign = '-'; + + // Send as 0.01 arcseconds resolution + int ieqValue = fabs(dec) * 60 * 60 * 100; + + snprintf(cmd, 32, ":Sd%c%08d#", sign, ieqValue); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + simData.dec = dec; + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_longitude(int fd, double longitude) +{ + char cmd[16]; + char sign; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (longitude >= 0) + sign = '+'; + else + sign = '-'; + + int longitude_arcsecs = fabs(longitude) * 60 * 60; + snprintf(cmd, 16, ":Sg%c%06d#", sign, longitude_arcsecs); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; + +} + +bool set_ieqpro_latitude(int fd, double latitude) +{ + char cmd[16]; + char sign; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (latitude >= 0) + sign = '+'; + else + sign = '-'; + + int latitude_arcsecs = fabs(latitude) * 60 * 60; + snprintf(cmd, 16, ":St%c%06d#", sign, latitude_arcsecs); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_local_date(int fd, int yy, int mm, int dd) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + snprintf(cmd, 16, ":SC%02d%02d%02d#", yy, mm, dd); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_local_time(int fd, int hh, int mm, int ss) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + snprintf(cmd, 16, ":SL%02d%02d%02d#", hh, mm, ss); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_daylight_saving(int fd, bool enabled) +{ + char cmd[16]; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (enabled) + strcpy(cmd, ":SDS1#"); + else + strcpy(cmd, ":SDS0#"); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool set_ieqpro_utc_offset(int fd, double offset) +{ + char cmd[16]; + char sign; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[8]; + int nbytes_read=0; + int nbytes_written=0; + + if (offset >= 0) + sign = '+'; + else + sign = '-'; + + int offset_minutes = fabs(offset) * 60.0; + + snprintf(cmd, 16, ":SG%c%03d#", sign, offset_minutes); + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strcpy(response, "1"); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read(fd, response, 1, IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + tcflush(fd, TCIFLUSH); + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + +bool get_ieqpro_coords(int fd, double *ra, double *dec) +{ + char cmd[] = ":GEC#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_EXTRA_1, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + char ra_str[16], dec_str[16]; + + char sign; + if (simData.dec >= 0) + sign = '+'; + else + sign = '-'; + + int ieqDEC = fabs(simData.dec) * 60 * 60 * 100; + + snprintf(dec_str, 16, "%c%08d", sign, ieqDEC); + + int ieqRA = simData.ra * 60 * 60 * 1000; + snprintf(ra_str, 16, "%08d", ieqRA); + + snprintf(response, 32, "%s%s#", dec_str, ra_str); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + tcflush(fd, TCIFLUSH); + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_EXTRA_1, "RES (%s)", response); + + char ra_str[16], dec_str[16]; + + strncpy(dec_str, response, 9); + strncpy(ra_str, response+9, 8); + + int ieqDEC = atoi(dec_str); + int ieqRA = atoi(ra_str); + + *ra = ieqRA / (60.0 * 60.0 * 1000.0); + *dec = ieqDEC / (60.0 * 60.0 * 100.0); + + return true; + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; + +} + +bool get_ieqpro_utc_date_time(int fd, double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss) +{ + char cmd[] = ":GLT#"; + int errcode = 0; + char errmsg[MAXRBUF]; + char response[32]; + int nbytes_read=0; + int nbytes_written=0; + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "CMD (%s)", cmd); + + if (ieqpro_simulation) + { + strncpy(response, "+180150331173000#" , 32); + nbytes_read = strlen(response); + } + else + { + if ( (errcode = tty_write(fd, cmd, strlen(cmd), &nbytes_written)) != TTY_OK) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + + if ( (errcode = tty_read_section(fd, response, '#', IEQPRO_TIMEOUT, &nbytes_read))) + { + tty_error_msg(errcode, errmsg, MAXRBUF); + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "%s", errmsg); + return false; + } + } + + if (nbytes_read > 0) + { + tcflush(fd, TCIFLUSH); + response[nbytes_read] = '\0'; + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_DEBUG, "RES (%s)", response); + + char utc_str[4], yy_str[2], mm_str[2], dd_str[2], hh_str[2], minute_str[2], ss_str[2]; + + strncpy(utc_str, response, 4); + strncpy(yy_str, response+4, 2); + strncpy(mm_str, response+6, 2); + strncpy(dd_str, response+8, 2); + strncpy(hh_str, response+10, 2); + strncpy(minute_str, response+12, 2); + strncpy(ss_str, response+14, 2); + + *utc_hours = atoi(utc_str) / 60.0; + *yy = atoi(yy_str) + 2000; + *mm = atoi(mm_str); + *dd = atoi(dd_str); + *hh = atoi(hh_str); + *minute = atoi(minute_str); + *ss = atoi(ss_str); + + ln_zonedate localTime; + ln_date utcTime; + + localTime.years = *yy; + localTime.months = *mm; + localTime.days = *dd; + localTime.hours = *hh; + localTime.minutes = *minute; + localTime.seconds = *ss; + localTime.gmtoff = *utc_hours * 3600; + + ln_zonedate_to_date(&localTime, &utcTime); + + *yy = utcTime.years; + *mm = utcTime.months; + *dd = utcTime.days; + *hh = utcTime.hours; + *minute = utcTime.minutes; + *ss = utcTime.seconds; + + return true; + + } + + DEBUGFDEVICE(ieqpro_device, INDI::Logger::DBG_ERROR, "Only received #%d bytes, expected 1.", nbytes_read); + return false; +} + diff -Nru libindi-1.0.0/drivers/telescope/ieqprodriver.h libindi-1.1.0/drivers/telescope/ieqprodriver.h --- libindi-1.0.0/drivers/telescope/ieqprodriver.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/ieqprodriver.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,144 @@ +/* + IEQ Pro driver + + Copyright (C) 2015 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 +*/ + +#ifndef IEQPRODRIVER_H +#define IEQPRODRIVER_H + +#include + +typedef enum { GPS_OFF, GPS_ON, GPS_DATA_OK } IEQ_GPS_STATUS; +typedef enum { ST_STOPPED, ST_TRACKING_PEC_OFF, ST_SLEWING, ST_GUIDING, ST_MERIDIAN_FLIPPING, ST_TRACKING_PEC_ON, ST_PARKED, ST_HOME } IEQ_SYSTEM_STATUS; +typedef enum { TR_SIDEREAL, TR_LUNAR, TR_SOLAR, TR_KING, TR_CUSTOM} IEQ_TRACK_RATE; +typedef enum { SR_1, SR_2, SR_3, SR_4, SR_5, SR_6, SR_7, SR_8, SR_MAX} IEQ_SLEW_RATE; +typedef enum { TS_RS232, TS_CONTROLLER, TS_GPS } IEQ_TIME_SOURCE; +typedef enum { HEMI_SOUTH, HEMI_NORTH} IEQ_HEMISPHERE; +typedef enum { FW_MODEL, FW_BOARD, FW_CONTROLLER, FW_RA, FW_DEC } IEQ_FIRMWARE; +typedef enum { RA_AXIS, DEC_AXIS } IEQ_AXIS; +typedef enum { IEQ_N, IEQ_S, IEQ_W, IEQ_E} IEQ_DIRECTION; +typedef enum { IEQ_FIND_HOME, IEQ_SET_HOME, IEQ_GOTO_HOME} IEQ_HOME_OPERATION; + +typedef struct +{ + IEQ_GPS_STATUS gpsStatus; + IEQ_SYSTEM_STATUS systemStatus; + IEQ_TRACK_RATE trackRate; + IEQ_SLEW_RATE slewRate; + IEQ_TIME_SOURCE timeSource; + IEQ_HEMISPHERE hemisphere; +} IEQInfo; + +typedef struct +{ + std::string Model; + std::string MainBoardFirmware; + std::string ControllerFirmware; + std::string RAFirmware; + std::string DEFirmware; +} FirmwareInfo; + +/************************************************************************** + Misc. +**************************************************************************/ + +void set_ieqpro_debug(bool enable); +void set_ieqpro_simulation(bool enable); +void set_ieqpro_device(const char *name); + +/************************************************************************** + Simulation +**************************************************************************/ +void set_sim_gps_status(IEQ_GPS_STATUS value); +void set_sim_system_status(IEQ_SYSTEM_STATUS value); +void set_sim_track_rate(IEQ_TRACK_RATE value); +void set_sim_slew_rate(IEQ_SLEW_RATE value); +void set_sim_time_source(IEQ_TIME_SOURCE value); +void set_sim_hemisphere(IEQ_HEMISPHERE value); +void set_sim_ra(double ra); +void set_sim_dec(double dec); +void set_sim_guide_rate(double rate); + +/************************************************************************** + Diagnostics +**************************************************************************/ +bool check_ieqpro_connection(int fd); + +/************************************************************************** + Get Info +**************************************************************************/ +/** Get iEQ current status info */ +bool get_ieqpro_status(int fd, IEQInfo *info); +/** Get All firmware informatin in addition to mount model */ +bool get_ieqpro_firmware(int fd, FirmwareInfo *info); +/** Get mainboard and controller firmware only */ +bool get_ieqpro_main_firmware(int fd, FirmwareInfo *info); +/** Get RA and DEC firmware info */ +bool get_ieqpro_radec_firmware(int fd, FirmwareInfo *info); +/** Get Mount model */ +bool get_ieqpro_model(int fd, FirmwareInfo *info); +/** Get RA/DEC */ +bool get_ieqpro_coords(int fd, double *ra, double *dec); +/** Get UTC/Date/Time */ +bool get_ieqpro_utc_date_time(int fd, double *utc_hours, int *yy, int *mm, int *dd, int *hh, int *minute, int *ss); + +/************************************************************************** + Motion +**************************************************************************/ +bool start_ieqpro_motion(int fd, IEQ_DIRECTION dir); +bool stop_ieqpro_motion(int fd, IEQ_DIRECTION dir); +bool set_ieqpro_slew_rate(int fd, IEQ_SLEW_RATE rate); +bool set_ieqpro_custom_track_rate(int fd, double rate); +bool set_ieqpro_track_mode(int fd, IEQ_TRACK_RATE rate); +bool abort_ieqpro(int fd); +bool slew_ieqpro(int fd); +bool sync_ieqpro(int fd); +bool set_ieqpro_ra(int fd, double ra); +bool set_ieqpro_dec(int fd, double dec); + +/************************************************************************** + Home +**************************************************************************/ +bool find_ieqpro_home(int fd); +bool goto_ieqpro_home(int fd); +bool set_ieqpro_current_home(int fd); + +/************************************************************************** + Park +**************************************************************************/ +bool park_ieqpro(int fd); +bool unpark_ieqpro(int fd); + +/************************************************************************** + Guide +**************************************************************************/ +bool set_ieqpro_guide_rate(int fd, double rate); +bool get_ieqpro_guide_rate(int fd, double *rate); +bool start_ieqpro_guide(int fd, IEQ_DIRECTION dir, int ms); + +/************************************************************************** + Time & Location +**************************************************************************/ +bool set_ieqpro_longitude(int fd, double longitude); +bool set_ieqpro_latitude(int fd, double latitude); +bool set_ieqpro_local_date(int fd, int yy, int mm, int dd); +bool set_ieqpro_local_time(int fd, int hh, int mm, int ss); +bool set_ieqpro_utc_offset(int fd, double offset_hours); +bool set_ieqpro_daylight_saving(int fd, bool enabled); + +#endif diff -Nru libindi-1.0.0/drivers/telescope/ieqpro.h libindi-1.1.0/drivers/telescope/ieqpro.h --- libindi-1.0.0/drivers/telescope/ieqpro.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/ieqpro.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,136 @@ +/* + INDI IEQ Pro driver + + Copyright (C) 2015 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 +*/ + +#ifndef IEQPRO_H +#define IEQPRO_H + +#include "inditelescope.h" +#include "indiguiderinterface.h" +#include "indicontroller.h" +#include "ieqprodriver.h" + +class IEQPro : public INDI::Telescope, public INDI::GuiderInterface +{ + public: + IEQPro(); + ~IEQPro(); + + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + +protected: + + virtual const char *getDefaultName(); + + virtual bool initProperties(); + virtual bool updateProperties(); + + virtual bool Connect(const char *port, uint16_t baud); + virtual bool Disconnect(); + + virtual bool ReadScopeStatus(); + + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); + + virtual bool saveConfigItems(FILE *fp); + + virtual bool Park(); + virtual bool UnPark(); + + virtual bool Sync(double ra, double dec); + virtual bool Goto(double, double); + virtual bool Abort(); + + virtual bool updateTime(ln_date * utc, double utc_offset); + virtual bool updateLocation(double latitude, double longitude, double elevation); + + virtual void debugTriggered(bool enable); + virtual void simulationTriggered(bool enable); + + // Parking + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); + + // Slew Rate + bool SetSlewRate(int index); + + // Sim + void mountSim(); + + // Guide + virtual IPState GuideNorth(float ms); + virtual IPState GuideSouth(float ms); + virtual IPState GuideEast(float ms); + virtual IPState GuideWest(float ms); + +private: + + /** + * @brief getStartupData Get initial mount info on startup. + */ + void getStartupData(); + + /* Firmware */ + IText FirmwareT[5]; + ITextVectorProperty FirmwareTP; + + /* Tracking Mode */ + ISwitchVectorProperty TrackModeSP; + ISwitch TrackModeS[4]; + + /* Custom Tracking Rate */ + INumber CustomTrackRateN[1]; + INumberVectorProperty CustomTrackRateNP; + + /* GPS Status */ + ISwitch GPSStatusS[3]; + ISwitchVectorProperty GPSStatusSP; + + /* Time Source */ + ISwitch TimeSourceS[3]; + ISwitchVectorProperty TimeSourceSP; + + /* Hemisphere */ + ISwitch HemisphereS[2]; + ISwitchVectorProperty HemisphereSP; + + /* Home Control */ + ISwitch HomeS[3]; + ISwitchVectorProperty HomeSP; + + /* Guide Rate */ + INumber GuideRateN[1]; + INumberVectorProperty GuideRateNP; + + unsigned int DBG_SCOPE; + bool sim; + bool timeUpdated, locationUpdated; + double currentRA, currentDEC; + double targetRA,targetDEC; + double parkRA, parkDEC; + + IEQInfo scopeInfo; + FirmwareInfo firmwareInfo; + +}; + +#endif + diff -Nru libindi-1.0.0/drivers/telescope/intelliscope.c libindi-1.1.0/drivers/telescope/intelliscope.c --- libindi-1.0.0/drivers/telescope/intelliscope.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/intelliscope.c 2015-09-06 13:17:35.000000000 +0000 @@ -30,15 +30,19 @@ #include #include +#ifndef _WIN32 +#include +#endif + #include "indidevapi.h" #include "indicom.h" -#include "lx200driver.h" #define mydev "Intelliscope" #define BASIC_GROUP "Main Control" #define POLLMS 1000 #define currentRA eq[0].value #define currentDEC eq[1].value +#define INTELLISCOPE_TIMEOUT 5 static void ISPoll(void *); static void ISInit(void); @@ -139,6 +143,50 @@ INDI_UNUSED(root); } +int updateIntelliscopeCoord (int fd, double *ra, double *dec) +{ + char coords[16]; + char CR[1] = { (char) 0x51 }; /* "Q" */ + float RA = 0.0, DEC = 0.0; + int error_type; + int nbytes_read=0; + + /*IDLog ("Sending a Q\n");*/ + error_type = write (fd, CR, 1); + /* We start at 14 bytes in case its a Sky Wizard, + but read one more later it if it's a intelliscope */ + /*read_ret = portRead (coords, 14, LX200_TIMEOUT);*/ + error_type = tty_read(fd, coords, 14, INTELLISCOPE_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + /*IDLog ("portRead() = [%s]\n", coords);*/ + + /* Remove the Q in the response from the Intelliscope but not the Sky Wizard */ + if (coords[0] == 'Q') { + coords[0] = ' '; + /* Read one more byte if Intelliscope to get the "CR" */ + error_type = tty_read(fd, coords, 1, INTELLISCOPE_TIMEOUT, &nbytes_read); + /*read_ret = portRead (coords, 1, LX200_TIMEOUT);*/ + } + nbytes_read = sscanf (coords, " %g %g", &RA, &DEC); + /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/ + /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/ + + /*IDLog ("Intelliscope output [%s]", coords);*/ + if (nbytes_read < 2) + { + #ifdef INDI_DEBUG + IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords); + #endif + return -1; + } + + *ra = RA * 0.0390625; + *dec = DEC * 0.0390625; + + return 0; + +} + void ISPoll (void *p) { p=p; diff -Nru libindi-1.0.0/drivers/telescope/lx200_16.cpp libindi-1.1.0/drivers/telescope/lx200_16.cpp --- libindi-1.0.0/drivers/telescope/lx200_16.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200_16.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -61,6 +61,7 @@ IUFillNumber(&HorizontalCoordsN[1], "AZ", "Az D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0); IUFillNumberVector(&HorizontalCoordsNP, HorizontalCoordsN, 2, getDeviceName(), "HORIZONTAL_COORD", "Horizontal Coord", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); + return true; } void LX200_16::ISGetProperties (const char *dev) @@ -100,6 +101,7 @@ deleteProperty(FieldDeRotatorSP.name); } + return true; } @@ -150,6 +152,7 @@ } LX200GPS::ISNewNumber (dev, name, values, names, n); + return true; } bool LX200_16::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) diff -Nru libindi-1.0.0/drivers/telescope/lx200ap.cpp libindi-1.1.0/drivers/telescope/lx200ap.cpp --- libindi-1.0.0/drivers/telescope/lx200ap.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200ap.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -40,6 +40,12 @@ { timeUpdated = locationUpdated = false; + DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); + + //ctor + currentRA=get_local_sideral_time(0); + currentDEC=90; + } const char *LX200AstroPhysics::getDefaultName() @@ -50,7 +56,6 @@ bool LX200AstroPhysics::initProperties() { - LX200Generic::initProperties(); IUFillSwitch(&StartUpS[0], "COLD", "Cold", ISS_OFF); @@ -65,16 +70,15 @@ IUFillNumber(&HorizontalCoordsN[1], "ALT", "Alt D:M:S", "%10.6m", -90., 90., 0., 0. ); IUFillNumberVector(&HorizontalCoordsNP,HorizontalCoordsN, 2, getDeviceName(), "HORIZONTAL_COORD", "Horizontal Coords", MAIN_CONTROL_TAB, IP_RW, 120, IPS_IDLE); - IUFillSwitch(&MoveToRateS[0], "1200" , "1200x" , ISS_OFF); - IUFillSwitch(&MoveToRateS[1], "600" , "600x" , ISS_OFF); - IUFillSwitch(&MoveToRateS[2], "64" , "64x" , ISS_ON); - IUFillSwitch(&MoveToRateS[3], "12" , "12x" , ISS_OFF); - IUFillSwitchVector(&MoveToRateSP, MoveToRateS, 4, getDeviceName(), "MOVETORATE", "Move to rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - IUFillSwitch(&SlewRateS[0], "1200" , "1200x" , ISS_OFF); - IUFillSwitch(&SlewRateS[1], "900" , "900x" , ISS_OFF); - IUFillSwitch(&SlewRateS[2], "600" , "600x" , ISS_ON); - IUFillSwitchVector(&SlewRateSP, SlewRateS, 3, getDeviceName(), "SLEWRATE", "Slew rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + IUFillSwitch(&SlewRateS[0], "12" , "12x" , ISS_OFF); + IUFillSwitch(&SlewRateS[1], "64" , "64x" , ISS_ON); + IUFillSwitch(&SlewRateS[2], "600" , "600x" , ISS_OFF); + IUFillSwitch(&SlewRateS[3], "1200" , "1200x" , ISS_OFF); + + IUFillSwitch(&SlewSpeedS[0], "1200" , "1200x" , ISS_ON); + IUFillSwitch(&SlewSpeedS[1], "900" , "900x" , ISS_OFF); + IUFillSwitch(&SlewSpeedS[2], "600" , "600x" , ISS_OFF); + IUFillSwitchVector(&SlewSpeedSP, SlewSpeedS, 3, getDeviceName(), "Slew Speed", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SwapS[0], "NS" , "North/South" , ISS_OFF); IUFillSwitch(&SwapS[1], "EW" , "East/West" , ISS_OFF); @@ -90,8 +94,12 @@ IUFillText(&DeclinationAxisT[0], "RELHA", "rel. to HA", "undefined"); IUFillTextVector(&DeclinationAxisTP, DeclinationAxisT, 1, getDeviceName(), "DECLINATIONAXIS", "Declination axis", MOUNT_TAB, IP_RO, 0, IPS_IDLE); - IUFillNumber(&APSiderealTimeN[0], "VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0.); - IUFillNumberVector(&APSiderealTimeNP, APSiderealTimeN, 1, getDeviceName(), "APSIDEREALTIME", "AP sidereal time", MOUNT_TAB, IP_RO, 0, IPS_IDLE); + // Slew threshold + IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, 2, getDeviceName(), "Slew Accuracy", "", MOUNT_TAB, IP_RW, 0, IPS_IDLE); + + SetParkDataType(PARK_AZ_ALT); return true; } @@ -104,19 +112,15 @@ { defineSwitch(&StartUpSP); defineText(&VersionInfo); - defineNumber(&HourangleCoordsNP) ; defineText(&DeclinationAxisTP); - defineNumber(&APSiderealTimeNP); /* Motion group */ defineSwitch (&TrackModeSP); - defineSwitch (&MoveToRateSP); - defineSwitch (&SlewRateSP); + defineSwitch (&SlewSpeedSP); defineSwitch (&SwapSP); defineSwitch (&SyncCMRSP); - - loadConfig(true); + defineNumber(&SlewAccuracyNP); DEBUG(INDI::Logger::DBG_SESSION, "Please initialize the mount before issuing any command."); } @@ -131,142 +135,31 @@ { defineSwitch(&StartUpSP); defineText(&VersionInfo); - defineNumber(&HourangleCoordsNP) ; defineText(&DeclinationAxisTP); - defineNumber(&APSiderealTimeNP); /* Motion group */ defineSwitch (&TrackModeSP); - defineSwitch (&MoveToRateSP); - defineSwitch (&SlewRateSP); + defineSwitch (&SlewSpeedSP); defineSwitch (&SwapSP); defineSwitch (&SyncCMRSP); + defineNumber(&SlewAccuracyNP); - loadConfig(true); - - DEBUG(INDI::Logger::DBG_SESSION, "Please initialize the mount before issuing any command."); + DEBUG(INDI::Logger::DBG_SESSION, "Please initialize the mount before issuing any command."); } else { deleteProperty(StartUpSP.name); deleteProperty(VersionInfo.name); - deleteProperty(HourangleCoordsNP.name); deleteProperty(DeclinationAxisTP.name); - deleteProperty(APSiderealTimeNP.name); deleteProperty(TrackModeSP.name); - deleteProperty(MoveToRateSP.name); - deleteProperty(SlewRateSP.name); + deleteProperty(SlewSpeedSP.name); deleteProperty(SwapSP.name); deleteProperty(SyncCMRSP.name); + deleteProperty(SlewAccuracyNP.name); } - controller->updateProperties(); -} - -bool LX200AstroPhysics::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - // ignore if not ours // - if (strcmp (dev, getDeviceName())) - return false; - - return LX200Generic::ISNewText (dev, name, texts, names, n); -} - - -bool LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - INumber *np=NULL; - - if (strcmp (dev, getDeviceName())) - return false; - - /* - // =================================== - // AP UTC Offset - // =================================== - if ( !strcmp (name, APUTCOffsetNP.name) ) - { - int ret ; - if (checkPower(&APUTCOffsetNP)) - return; - - if (values[0] <= 0.0 || values[0] > 24.0) - { - APUTCOffsetNP.s = IPS_IDLE; - IDSetNumber(&APUTCOffsetNP , "UTC offset invalid"); - return; - } - - if(( ret = setAPUTCOffset(fd, values[0]) < 0) ) - { - DEBUGF(INDI::Logger::DBG_ERROR, APUTCOffsetNP, ret, "Setting AP UTC offset"); - return; - } - - APUTCOffsetN[0].value = values[0]; - APUTCOffsetNP.s = IPS_OK; - - IDSetNumber(&APUTCOffsetNP, NULL); - - return; - } - */ - - // ======================================= - // Horizontal Coords - SET - // ======================================= -#if 0 - if ( !strcmp (name, HorizontalCoordsNP.name) ) - { - int i=0, nset=0; - double newAz, newAlt ; - int ret ; - char altStr[64], azStr[64]; - - for (nset = i = 0; i < n; i++) - { - np = IUFindNumber (&HorizontalCoordsNP, names[i]); - if (np == &HorizontalCoordsRN[0]) - { - newAz = values[i]; - nset += newAz >= 0. && newAz <= 360.0; - } - else if (np == &HorizontalCoordsRN[1]) - { - newAlt = values[i]; - nset += newAlt >= -90. && newAlt <= 90.0; - } - } - if (nset == 2) - { - if ( (ret = setAPObjectAZ(fd, newAz)) < 0 || (ret = setAPObjectAlt(fd, newAlt)) < 0) - { - DEBUGF(INDI::Logger::DBG_ERROR, HorizontalCoordsNP, ret, "Setting Alt/Az"); - return; - } - targetAZ= newAz; - targetALT= newAlt; - HorizontalCoordsNP.s = IPS_OK; - IDSetNumber(&HorizontalCoordsNP, NULL) ; - - fs_sexa(azStr, targetAZ, 2, 3600); - fs_sexa(altStr, targetALT, 2, 3600); - - handleAltAzSlew(); - } - else - { - HorizontalCoordsNP.s = IPS_ALERT; - IDSetNumber(&HorizontalCoordsNP, "Altitude or Azimuth missing or invalid"); - } - - return; - } -#endif - - - return LX200Generic::ISNewNumber (dev, name, values, names, n); + return true; } bool LX200AstroPhysics::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) @@ -297,17 +190,8 @@ return false; } - mount_status=MOUNTINITIALIZED; - - /*if( setBasicDataPart0() == false) - { - StartUpSP.s = IPS_ALERT ; - IDSetSwitch(&StartUpSP, "Mount initialization failed") ; - return false ; - }*/ - - if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start) - { + if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start) + { if( setBasicDataPart1() == false) { @@ -315,7 +199,9 @@ IDSetSwitch(&StartUpSP, "Cold mount initialization failed.") ; return false ; } - } + } + + mount_status=MOUNTINITIALIZED; // Make sure that the mount is setup according to the properties switch_nr = IUFindOnSwitchIndex(&TrackModeSP); @@ -329,28 +215,27 @@ TrackModeSP.s = IPS_OK; IDSetSwitch(&TrackModeSP, NULL); - //ToDo set button swapping acording telescope east west - // ... some code here + switch_nr = IUFindOnSwitchIndex(&SlewRateSP); - switch_nr = IUFindOnSwitchIndex(&MoveToRateSP); + switch_nr = 3 - switch_nr; if (isSimulation() == false && ( err = selectAPMoveToRate(PortFD, switch_nr) < 0) ) { DEBUGF(INDI::Logger::DBG_ERROR, "StartUpSP: Error setting move to rate (%d).", err); return false; } - MoveToRateSP.s = IPS_OK; + SlewRateSP.s = IPS_OK; - IDSetSwitch(&MoveToRateSP, NULL); - switch_nr = IUFindOnSwitchIndex(&SlewRateSP); - + IDSetSwitch(&SlewRateSP, NULL); + + switch_nr = IUFindOnSwitchIndex(&SlewSpeedSP); if (isSimulation() == false && ( err = selectAPSlewRate(PortFD, switch_nr) < 0) ) { DEBUGF(INDI::Logger::DBG_ERROR, "StartUpSP: Error setting slew rate (%d).", err); return false; } - SlewRateSP.s = IPS_OK; - IDSetSwitch(&SlewRateSP, NULL); + SlewSpeedSP.s = IPS_OK; + IDSetSwitch(&SlewSpeedSP, NULL); StartUpSP.s = IPS_OK ; IDSetSwitch(&StartUpSP, "Mount initialized.") ; @@ -373,16 +258,7 @@ NewRaDec(currentRA, currentDEC); - // sleep for 100 mseconds - //usleep(100000); - - //getLX200Az(fd, ¤tAZ); - //getLX200Alt(fd, ¤tALT); - - //HorizontalCoordsNP.s = IPS_OK ; - //IDSetNumber (&HorizontalCoordsNP, NULL); - - VersionInfo.tp[0].text = new char[64]; + VersionInfo.tp[0].text = new char[64]; if (isSimulation()) IUSaveText(&VersionT[0], "1.0"); @@ -401,52 +277,6 @@ } // ======================================= - // Park - // ======================================= - /* - if (!strcmp(name, ParkSP.name)) - { - if (checkPower(&ParkSP)) - return; - - if (EquatorialCoordsRNP.s == IPS_BUSY) - { - // ToDo handle return value - abortSlew(fd); - // sleep for 200 mseconds - usleep(200000); - AbortSlewSP.s = IPS_OK; - IDSetSwitch(&AbortSlewSP, NULL); - - } - - if (setAPPark(fd) < 0) - { - ParkSP.s = IPS_ALERT; - IDSetSwitch(&ParkSP, "Parking Failed."); - return; - } - - ParkSP.s = IPS_OK; - IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting..."); - // avoid sending anything to the mount controller - tty_disconnect( fd); - ConnectSP.s = IPS_IDLE; - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - - IDSetSwitch(&ConnectSP, NULL); - - StartUpSP.s = IPS_IDLE ; - IDSetSwitch(&StartUpSP, NULL) ; - - // ToDo reset all values - - return; - } - */ - - // ======================================= // Tracking Mode // ======================================= if (!strcmp (name, TrackModeSP.name)) @@ -501,36 +331,15 @@ } // ======================================= - // Swap to rate + // Slew Mode // ======================================= - if (!strcmp (name, MoveToRateSP.name)) - { - int moveToRate ; - - IUResetSwitch(&MoveToRateSP); - IUUpdateSwitch(&MoveToRateSP, states, names, n); - moveToRate = IUFindOnSwitchIndex(&MoveToRateSP); - - if (isSimulation() == false && ( err = selectAPMoveToRate(PortFD, moveToRate) < 0) ) - { - DEBUGF(INDI::Logger::DBG_ERROR, "Error setting move to rate (%d).", err); - return false; - } - MoveToRateSP.s = IPS_OK; - IDSetSwitch(&MoveToRateSP, NULL); - return true; - } - - // ======================================= - // Slew Rate - // ======================================= - if (!strcmp (name, SlewRateSP.name)) + if (!strcmp (name, SlewSpeedSP.name)) { int slewRate ; - IUResetSwitch(&SlewRateSP); - IUUpdateSwitch(&SlewRateSP, states, names, n); - slewRate = IUFindOnSwitchIndex(&SlewRateSP); + IUResetSwitch(&SlewSpeedSP); + IUUpdateSwitch(&SlewSpeedSP, states, names, n); + slewRate = IUFindOnSwitchIndex(&SlewSpeedSP); if (isSimulation() == false && ( err = selectAPSlewRate(PortFD, slewRate) < 0) ) { @@ -538,8 +347,8 @@ return false; } - SlewRateSP.s = IPS_OK; - IDSetSwitch(&SlewRateSP, NULL); + SlewSpeedSP.s = IPS_OK; + IDSetSwitch(&SlewSpeedSP, NULL); return true; } @@ -562,6 +371,36 @@ return LX200Generic::ISNewSwitch (dev, name, states, names, n); } +/************************************************************************************** +** +***************************************************************************************/ +bool LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + if (strcmp (getDeviceName(), dev)) + return false; + + + // Update slew precision limit + if (!strcmp(name, SlewAccuracyNP.name)) + { + if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) + return false; + + SlewAccuracyNP.s = IPS_OK; + + if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) + IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); + + IDSetNumber(&SlewAccuracyNP, NULL); + return true; + + + } + + return LX200Generic::ISNewNumber(dev, name, values, names, n); +} + + bool LX200AstroPhysics::isMountInit(void) { return (StartUpSP.s != IPS_IDLE); @@ -569,61 +408,55 @@ bool LX200AstroPhysics::ReadScopeStatus() { - int ret ; if (!isMountInit()) return false; - //============================================================ - // #1 Call LX200Generic ReadScopeStatus - //============================================================ - bool rc = LX200Generic::ReadScopeStatus(); - - - //============================================================ - // #2 Get Sidereal Time - //============================================================ - if (isSimulation() == false) + if (isSimulation()) { - if(( ret= getSDTime( PortFD, &APSiderealTimeN[0].value)) == 0) - { - APSiderealTimeNP.s = IPS_OK ; - } - else - { - APSiderealTimeNP.s = IPS_ALERT ; - } - IDSetNumber(&APSiderealTimeNP, NULL); + mountSim(); + return true; } + if ( getLX200RA(PortFD, ¤tRA) < 0 || getLX200DEC(PortFD, ¤tDEC) < 0) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP, "Error reading RA/DEC."); + return false; + } - //============================================================ - // #3 - //============================================================ - if (isSimulation() == false) + if (TrackState == SCOPE_SLEWING || TrackState == SCOPE_PARKING) { - if(( ret= getAPDeclinationAxis( PortFD, DeclinationAxisT[0].text)) == 0) - { - DeclinationAxisTP.s = IPS_OK ; - } - else + double dx = targetRA - currentRA; + double dy = targetDEC - currentDEC; + + // Wait until acknowledged or within threshold + if ( fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0)) { - DeclinationAxisTP.s = IPS_ALERT ; + if (TrackState == SCOPE_SLEWING) + { + TrackState=SCOPE_TRACKING; + DEBUG(INDI::Logger::DBG_SESSION, "Slew is complete. Tracking..."); + } + else + { + DEBUG(INDI::Logger::DBG_DEBUG, "Parking slew is complete. Asking astrophysics mount to park..."); + if (isSimulation() == false) + { + if (setAPPark(PortFD) < 0) + { + DEBUG(INDI::Logger::DBG_ERROR, "Parking Failed."); + return false; + } + } + + SetParked(true); + } } - IDSetText(&DeclinationAxisTP, NULL) ; } - - /* Calculate the hour angle */ - HourangleCoordsNP.np[0].value= 180. /M_PI/15. * LDRAtoHA( 15.* currentRA /180. *M_PI, -LocationNP.np[1].value/180. *M_PI); - HourangleCoordsNP.np[1].value= currentDEC; - - HourangleCoordsNP.s = IPS_OK; - IDSetNumber(&HourangleCoordsNP, NULL); - - /*getLX200Az(fd, ¤tAZ); - getLX200Alt(fd, ¤tALT); - IDSetNumber(&HorizontalCoordsNP, NULL);*/ - return rc; + NewRaDec(currentRA, currentDEC); + + return true; } bool LX200AstroPhysics::setBasicDataPart0() @@ -640,461 +473,57 @@ if( (err = setAPClearBuffer( PortFD)) < 0) { - DEBUGF(INDI::Logger::DBG_ERROR, "Error clearing the buffer (%d).", err); + DEBUGF(INDI::Logger::DBG_ERROR, "Error clearing the buffer (%d): %s", err, strerror(err)); return false; } if( (err = setAPLongFormat( PortFD)) < 0) { - DEBUGF(INDI::Logger::DBG_ERROR, "Error setting long format failed (%d).", err); + DEBUGF(INDI::Logger::DBG_ERROR, "Error setting long format failed (%d): %s", err, strerror(err)); return false; } if( (err = setAPBackLashCompensation(PortFD, 0,0,0)) < 0) { - DEBUGF(INDI::Logger::DBG_ERROR, "Error setting back lash compensation (%d).", err); + DEBUGF(INDI::Logger::DBG_ERROR, "Error setting back lash compensation (%d): %s.", err, strerror(err)); return false; } - /* - ln_get_date_from_sys( &utm) ; - ln_date_to_zonedate(&utm, <m, 3600); - - if(( err = setLocalTime(PortFD, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0)) - { - DEBUGF(INDI::Logger::DBG_ERROR, "Error setting local time (%d).", err); - return -1; - } - if ( ( err = setCalenderDate(PortFD, ltm.days, ltm.months, ltm.years) < 0) ) - { - DEBUGF(INDI::Logger::DBG_ERROR, "Error setting local date (%d).", err); - return -1; - } - - DEBUGF(INDI::Logger::DBG_DEBUG, "UT time is: %04d/%02d/%02d T %02d:%02d:%02d", utm.years, utm.months, utm.days, utm.hours, utm.minutes, (int)utm.seconds); - DEBUGF(INDI::Logger::DBG_DEBUG, "Local time is: %04d/%02d/%02d T %02d:%02d:%02d", ltm.years, ltm.months, ltm.days, ltm.hours, ltm.minutes, (int)ltm.seconds); - */ - return true; } bool LX200AstroPhysics::setBasicDataPart1() { - int err ; + int err=0; - if (isSimulation() == true) + if (InitPark()) { - DEBUG(INDI::Logger::DBG_SESSION, "setBasicDataPart1 simulation complete."); - return true; + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); } - - if((err = setAPUnPark( PortFD)) < 0) + else { - DEBUGF(INDI::Logger::DBG_ERROR, "Error unparking failed (%d).", err) ; - return -1; + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(0); + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); } - DEBUG(INDI::Logger::DBG_DEBUG, "Unparking successful"); - - if((err = setAPMotionStop( PortFD)) < 0) - { - DEBUGF(INDI::Logger::DBG_ERROR, "Stop motion (:Q#) failed, check the mount (%d).", err) ; - return -1; - } + // Unpark + UnPark(); + + // Stop + if(isSimulation() == false && (err = setAPMotionStop( PortFD)) < 0) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Stop motion (:Q#) failed, check the mount (%d): %s", strerror(err)) ; + return false; + } return true ; } -#if 0 -void LX200AstroPhysics::connectTelescope() -{ - static int established= NOTESTABLISHED ; - - switch (ConnectSP.sp[0].s) - { - case ISS_ON: - - if( ! established) - { - if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) - { - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text); - established= NOTESTABLISHED ; - return; - } - if (check_lx200ap_connection(fd)) - { - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); - established= NOTESTABLISHED ; - return; - } - established= ESTABLISHED ; - #ifdef INDI_DEBUG - IDLog("Telescope test successful\n"); - #endif - // At this point e.g. no GEOGRAPHIC_COORD are available after the first client connects. - // Postpone set up of the telescope - // NO setBasicData() ; - - // ToDo what is that *((int *) UTCOffsetN[0].aux0) = 0; - // Jasem: This is just a way to know if the client has init UTC Offset, and if he did, then we set aux0 to 1, otherwise it stays at 0. When - // the client tries to change UTC, but has not set UTFOffset yet (that is, aux0 = 0) then we can tell him to set the UTCOffset first. Btw, - // the UTF & UTFOffset will be merged in one property for INDI v0.6 - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Telescope is online"); - } - else - { - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Connection already established."); - } - break; - - case ISS_OFF: - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - ConnectSP.s = IPS_IDLE; - IDSetSwitch (&ConnectSP, "Telescope is offline."); - if (setAPPark(fd) < 0) - { - ParkSP.s = IPS_ALERT; - IDSetSwitch(&ParkSP, "Parking Failed."); - return; - } - - ParkSP.s = IPS_OK; - IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting..."); - - tty_disconnect(fd); - established= NOTESTABLISHED ; -#ifdef INDI_DEBUG - IDLog("The telescope is parked. Turn off the telescope. Disconnected.\n"); -#endif - break; - } -} -#endif - -#if 0 -// taken from lx200_16 -void LX200AstroPhysics::handleAltAzSlew() -{ - int i=0; - char altStr[64], azStr[64]; - - if (HorizontalCoordsNP.s == IPS_BUSY) - { - abortSlew(fd); - AbortSlewSP.s = IPS_OK; - IDSetSwitch(&AbortSlewSP, NULL); - - // sleep for 100 mseconds - usleep(100000); - } - - // ToDo is it ok ? - // if ((i = slewToAltAz(fd))) - if ((i = Slew(fd))) - { - HorizontalCoordsNP.s = IPS_ALERT; - IDSetNumber(&HorizontalCoordsNP, "Slew is not possible."); - return; - } - - HorizontalCoordsNP.s = IPS_OK; - fs_sexa(azStr, targetAZ, 2, 3600); - fs_sexa(altStr, targetALT, 2, 3600); - - IDSetNumber(&HorizontalCoordsNP, "Slewing to Alt %s - Az %s", altStr, azStr); - - TrackState = SCOPE_SLEWING; - - return; -} -#endif - -#if 0 -void LX200AstroPhysics::handleEqCoordSet() -{ - - int sync ; - int err; - char syncString[256]; - char RAStr[32], DecStr[32]; - double dx, dy; - int syncOK= 0 ; - double targetHA ; - -#ifdef INDI_DEBUG - IDLog("In Handle AP EQ Coord Set(), switch %d\n", getOnSwitch(&OnCoordSetSP)); -#endif - switch (getOnSwitch(&OnCoordSetSP)) - { - // Slew - case LX200_TRACK: - lastSet = LX200_TRACK; - if (EquatorialCoordsRNP.s == IPS_BUSY) - { -#ifdef INDI_DEBUG - IDLog("Aborting Track\n"); -#endif - // ToDo - abortSlew(fd); - AbortSlewSP.s = IPS_OK; - IDSetSwitch(&AbortSlewSP, NULL); - - // sleep for 100 mseconds - usleep(100000); - } - if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */ - { - slewError(err); - // ToDo handle that with the handleError function - return ; - } - EquatorialCoordsRNP.s = IPS_BUSY; - fs_sexa(RAStr, targetRA, 2, 3600); - fs_sexa(DecStr, targetDEC, 2, 3600); - IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); -#ifdef INDI_DEBUG - IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); -#endif - break; - - - // Sync - case LX200_SYNC: - - lastSet = LX200_SYNC; - -/* Astro-Physics has two sync options. In order that no collision occurs, the SYNCCMR */ -/* variant behaves for now identical like SYNCCM. Later this feature will be enabled.*/ -/* Calculate the hour angle of the target */ - - targetHA= 180. /M_PI/15. * LDRAtoHA( 15.* targetRA/180. *M_PI, -geoNP.np[1].value/180. *M_PI); - - if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR) - { - if (!strcmp("West", DeclinationAxisT[0].text)) - { - if(( targetHA > 12.0) && ( targetHA <= 24.0)) - { - syncOK= 1 ; - } - else - { - syncOK= 0 ; - } - } - else if (!strcmp("East", DeclinationAxisT[0].text)) - { - if(( targetHA >= 0.0) && ( targetHA <= 12.0)) - { - syncOK= 1 ; - } - else - { - syncOK= 0 ; - } - } - else - { -#ifdef INDI_DEBUG - IDLog("handleEqCoordSet(): SYNC NOK not East or West\n") ; -#endif - return ; - } - } - else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCM) - { - syncOK = 1 ; - } - else - { -#ifdef INDI_DEBUG - IDLog("handleEqCoordSet(): SYNC NOK not SYNCCM or SYNCCMR\n") ; -#endif - return ; - } - if( syncOK == 1) - { - if( (sync=getOnSwitch(&SyncCMRSP))==SYNCCM) - { - if ( ( err = APSyncCM(fd, syncString) < 0) ) - { - EquatorialCoordsRNP.s = IPS_ALERT ; - IDSetNumber( &EquatorialCoordsRNP , "Synchronization failed."); - // ToDo handle with handleError function - return ; - } - } - else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR) - { - if ( ( err = APSyncCMR(fd, syncString) < 0) ) - { - EquatorialCoordsRNP.s = IPS_ALERT ; - IDSetNumber( &EquatorialCoordsRNP, "Synchronization failed."); - // ToDo handle with handleError function - return ; - } - } - else - { - EquatorialCoordsRNP.s = IPS_ALERT ; - IDSetNumber( &EquatorialCoordsRNP , "SYNC NOK no valid SYNCCM, SYNCCMR"); -#ifdef INDI_DEBUG - IDLog("SYNC NOK no valid SYNCCM, SYNCCMR\n") ; -#endif - return ; - } -/* get the property DeclinationAxisTP first */ - if(( err = getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) < 0) - { - //ToDo handleErr - DeclinationAxisTP.s = IPS_ALERT ; - IDSetText(&DeclinationAxisTP, "Declination axis undefined") ; - return ; - } - - DeclinationAxisTP.s = IPS_OK ; -#ifdef INDI_DEBUG - IDLog("Declination axis is on the %s side\n", DeclinationAxisT[0].text) ; -#endif - IDSetText(&DeclinationAxisTP, NULL) ; - - getLX200RA( fd, ¤tRA); - getLX200DEC(fd, ¤tDEC); -// The mount executed the sync command, now read back the values, make a IDSet in order the dome controller -// is aware of the new target - targetRA= currentRA ; - targetDEC= currentDEC ; - EquatorialCoordsRNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */ - IDSetNumber(&EquatorialCoordsRNP, "EquatorialCoordsWNP.s = IPS_BUSY after SYNC"); - } - else - { -#ifdef INDI_DEBUG - IDLog("Synchronization not allowed\n") ; -#endif - - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP, "Synchronization not allowed" ); - -#ifdef INDI_DEBUG - IDLog("Telescope is on the wrong side targetHA was %f\n", targetHA) ; -#endif - DeclinationAxisTP.s = IPS_ALERT ; - IDSetText(&DeclinationAxisTP, "Telescope is on the wrong side targetHA was %f", targetHA) ; - - return ; - } -#ifdef INDI_DEBUG - IDLog("Synchronization successful >%s<\n", syncString); -#endif - EquatorialCoordsRNP.s = IPS_OK; /* see above for dome controller dc */ - IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful, EquatorialCoordsWNP.s = IPS_OK after SYNC"); - break; - } - return ; - -} -#endif - -#if 0 -// ToDo Not yet used -void LX200AstroPhysics::handleAZCoordSet() -{ - int err; - char AZStr[32], AltStr[32]; - - switch (getOnSwitch(&OnCoordSetSP)) - { - // Slew - case LX200_TRACK: - lastSet = LX200_TRACK; - if (HorizontalCoordsNP.s == IPS_BUSY) - { -#ifdef INDI_DEBUG - IDLog("Aborting Slew\n"); -#endif - // ToDo - abortSlew(fd); - AbortSlewSP.s = IPS_OK; - IDSetSwitch(&AbortSlewSP, NULL); - // sleep for 100 mseconds - usleep(100000); - } - - if ((err = Slew(fd))) - { - slewError(err); - //ToDo handle it - - return ; - } - - HorizontalCoordsNP.s = IPS_BUSY; - fs_sexa(AZStr, targetAZ, 2, 3600); - fs_sexa(AltStr, targetALT, 2, 3600); - IDSetNumber(&HorizontalCoordsNP, "Slewing to AZ %s - Alt %s", AZStr, AltStr); -#ifdef INDI_DEBUG - IDLog("Slewing to AZ %s - Alt %s\n", AZStr, AltStr); -#endif - break; - - // Sync - /* ToDo DO SYNC */ - case LX200_SYNC: - IDMessage( myapdev, "Sync not supported in ALT/AZ mode") ; - - break; - } -} -#endif - -/*********Library Section**************/ -/*********Library Section**************/ -/*********Library Section**************/ -/*********Library Section**************/ - -double LDRAtoHA( double RA, double longitude) -{ -#ifdef HAVE_NOVA_H - double HA ; - double JD ; - double theta_0= 0. ; - JD= ln_get_julian_from_sys() ; - -// #ifdef INDI_DEBUG -// IDLog("LDRAtoHA: JD %f\n", JD); -// #endif - - theta_0= 15. * ln_get_mean_sidereal_time( JD) ; -// #ifdef INDI_DEBUG -// IDLog("LDRAtoHA:1 theta_0 %f\n", theta_0); -// #endif - theta_0= fmod( theta_0, 360.) ; - - theta_0= theta_0 /180. * M_PI ; - - HA = fmod(theta_0 - longitude - RA, 2. * M_PI) ; - - if( HA < 0.) - { - HA += 2. * M_PI ; - } - return HA ; -#else - IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ; - return 0 ; -#endif - -} - bool LX200AstroPhysics::Goto(double r,double d) { targetRA=r; @@ -1160,56 +589,7 @@ return true; } -bool LX200AstroPhysics::Park() -{ - if (isSimulation() == false) - { - // If scope is moving, let's stop it first. - if (EqNP.s == IPS_BUSY) - { - if (abortSlew(PortFD) < 0) - { - AbortSP.s = IPS_ALERT; - IDSetSwitch(&AbortSP, "Abort slew failed."); - return false; - } - - AbortSP.s = IPS_OK; - EqNP.s = IPS_IDLE; - IDSetSwitch(&AbortSP, "Slew aborted."); - IDSetNumber(&EqNP, NULL); - - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - { - MovementNSSP.s = MovementWESP.s = IPS_IDLE; - EqNP.s = IPS_IDLE; - IUResetSwitch(&MovementNSSP); - IUResetSwitch(&MovementWESP); - - IDSetSwitch(&MovementNSSP, NULL); - IDSetSwitch(&MovementWESP, NULL); - } - - // sleep for 100 msec - usleep(100000); - } - - if (setAPPark(PortFD) < 0) - { - ParkSP.s = IPS_ALERT; - IDSetSwitch(&ParkSP, "Parking Failed."); - return false; - } - - } - - ParkSP.s = IPS_OK; - TrackState = SCOPE_PARKING; - DEBUG(INDI::Logger::DBG_SESSION, "Telescope parking in progress..."); - return true; -} - -bool LX200AstroPhysics::Connect(char *port) +bool LX200AstroPhysics::Connect(const char *port, uint16_t baud) { if (isSimulation()) { @@ -1217,21 +597,27 @@ return true; } - if (tty_connect(port, 9600, 8, 0, 1, &PortFD) != TTY_OK) + if (tty_connect(port, baud, 8, 0, 1, &PortFD) != TTY_OK) { DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); return false; } - if (check_lx200ap_connection(PortFD)) + /* if (check_lx200ap_connection(PortFD)) { DEBUG(INDI::Logger::DBG_ERROR, "Error connecting to Telescope. Telescope is offline."); return false; - } + }*/ - DEBUG(INDI::Logger::DBG_SESSION, "Telescope is online."); + //DEBUG(INDI::Logger::DBG_SESSION, "Telescope is online."); - setBasicDataPart0(); + if (setBasicDataPart0()) + DEBUG(INDI::Logger::DBG_SESSION, "Telescope is online."); + else + { + DEBUGF(INDI::Logger::DBG_SESSION, "Error connecting to Telescope. Telescope initilization sequence failed. Please check power and ensure port %s is the correct telescope port.", port); + return false; + } return true; } @@ -1288,7 +674,10 @@ struct ln_zonedate ltm; if (isSimulation()) + { + timeUpdated = true; return true; + } ln_date_to_zonedate(utc, <m, utc_offset*3600.0); @@ -1297,24 +686,30 @@ DEBUGF(INDI::Logger::DBG_DEBUG, "New JD is %f", (float) JD); // Set Local Time - if (setLocalTime(PortFD, ltm.hours, ltm.minutes, ltm.seconds) < 0) + if (setLocalTime(PortFD, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting local time."); return false; } + DEBUGF(INDI::Logger::DBG_DEBUG, "Set Local Time %02d:%02d:%02d is successful.", ltm.hours, ltm.minutes, (int) ltm.seconds); + if (setCalenderDate(PortFD, ltm.days, ltm.months, ltm.years) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting local date."); return false; } - if (setAPUTCOffset(PortFD, (utc_offset * -1)) < 0) + DEBUGF(INDI::Logger::DBG_DEBUG, "Set Local Date %02d/%02d/%02d is successful.", ltm.days, ltm.months, ltm.years); + + if (setAPUTCOffset(PortFD, fabs(utc_offset)) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting UTC Offset."); return false; } + DEBUGF(INDI::Logger::DBG_DEBUG, "Set UTC Offset %g (always positive for AP) is successful.", fabs(utc_offset)); + DEBUG(INDI::Logger::DBG_SESSION, "Time updated."); timeUpdated = true; @@ -1327,7 +722,10 @@ INDI_UNUSED(elevation); if (isSimulation()) + { + locationUpdated = true; return true; + } if (isSimulation() == false && setAPSiteLongitude(PortFD, 360.0 - longitude) < 0) { @@ -1354,63 +752,175 @@ void LX200AstroPhysics::debugTriggered(bool enable) { - setLX200Debug(enable ? 1 : 0); - set_lx200ap_debug(enable ? 1 : 0); + INDI_UNUSED(enable); + setLX200Debug(getDeviceName(), DBG_SCOPE); + set_lx200ap_name(getDeviceName(), DBG_SCOPE); } -void LX200AstroPhysics::processButton(const char * button_n, ISState state) +bool LX200AstroPhysics::SetSlewRate(int index) { - //ignore OFF - if (state == ISS_OFF) - return; + // Convert index to AP format + index = 3 - index; - // Max Slew speed - if (!strcmp(button_n, "Slew Max")) + if (isSimulation() == false && selectAPMoveToRate(PortFD, index) < 0) + { + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return false; + } + + SlewRateSP.s = IPS_OK; + IDSetSwitch(&SlewRateSP, NULL); + return true; +} + + +bool LX200AstroPhysics::Park() +{ + double parkAZ = GetAxis1Park(); + double parkAlt = GetAxis2Park(); + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Parking to Az (%s) Alt (%s)...", AzStr, AltStr); + + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = parkAZ + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = parkAlt; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + char RAStr[16], DEStr[16]; + fs_sexa(RAStr, equatorialPos.ra/15.0, 2, 3600); + fs_sexa(DEStr, equatorialPos.dec, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Parking to RA (%s) DEC (%s)...", RAStr, DEStr); + + if (Goto(equatorialPos.ra/15.0, equatorialPos.dec)) { - selectAPMoveToRate(PortFD, 0); - IUResetSwitch(&MoveToRateSP); - MoveToRateS[0].s = ISS_ON; - IDSetSwitch(&MoveToRateSP, NULL); + TrackState = SCOPE_PARKING; + DEBUG(INDI::Logger::DBG_SESSION, "Parking is in progress..."); + + return true; } - // Find Slew speed - else if (!strcmp(button_n, "Slew Find")) + else + return false; +} + +bool LX200AstroPhysics::UnPark() +{ + // First we unpark astrophysics + if (isSimulation() == false) { - selectAPMoveToRate(PortFD, 1); - IUResetSwitch(&MoveToRateSP); - MoveToRateS[1].s = ISS_ON; - IDSetSwitch(&MoveToRateSP, NULL); + if (setAPUnPark(PortFD) < 0) + { + DEBUG(INDI::Logger::DBG_ERROR, "UnParking Failed."); + return false; + } } - // Centering Slew - else if (!strcmp(button_n, "Slew Centering")) - { - selectAPMoveToRate(PortFD, 2); - IUResetSwitch(&MoveToRateSP); - MoveToRateS[2].s = ISS_ON; - IDSetSwitch(&MoveToRateSP, NULL); - } - // Guide Slew - else if (!strcmp(button_n, "Slew Guide")) + return true; + + // TODO need testing. If we unpark, do we get last parking position back? or we need to sync explicitly? + + /* + + // Then we sync with to our last stored position + double parkAZ = GetAxis1Park(); + double parkAlt = GetAxis2Park(); + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Unparking from Az (%s) Alt (%s)...", AzStr, AltStr); + + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = parkAZ + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = parkAlt; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + char RAStr[16], DEStr[16]; + fs_sexa(RAStr, equatorialPos.ra/15.0, 2, 3600); + fs_sexa(DEStr, equatorialPos.dec, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Syncing to parked coordinates RA (%s) DEC (%s)...", RAStr, DEStr); + + if (Sync(equatorialPos.ra/15.0, equatorialPos.dec)) { - selectAPMoveToRate(PortFD, 3); - IUResetSwitch(&MoveToRateSP); - MoveToRateS[3].s = ISS_ON; - IDSetSwitch(&MoveToRateSP, NULL); + SetParked(false); + return true; } - // Abort - else if (!strcmp(button_n, "Abort Motion")) - { - // Only abort if we have some sort of motion going on - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY - || GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) - { + else + return false; - Abort(); - } - } + */ + +} + +void LX200AstroPhysics::SetCurrentPark() +{ + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + + ln_lnlat_posn observer; + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + equatorialPos.ra = currentRA * 15; + equatorialPos.dec = currentDEC; + ln_get_hrz_from_equ(&equatorialPos, &observer, ln_get_julian_from_sys(), &horizontalPos); + double parkAZ = horizontalPos.az - 180; + if (parkAZ < 0) + parkAZ += 360; + double parkAlt = horizontalPos.alt; + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + + DEBUGF(INDI::Logger::DBG_DEBUG, "Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr, AltStr); + + SetAxis1Park(parkAZ); + SetAxis2Park(parkAlt); } +void LX200AstroPhysics::SetDefaultPark() +{ + // By defualt azimuth 0 + SetAxis1Park(0); + // Altitude = latitude of observer + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); +} diff -Nru libindi-1.0.0/drivers/telescope/lx200apdriver.c libindi-1.1.0/drivers/telescope/lx200apdriver.c --- libindi-1.0.0/drivers/telescope/lx200apdriver.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200apdriver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,548 +0,0 @@ -#if 0 - LX200 Astro-Physics Driver - Copyright (C) 2007 Markus Wildi - - 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 - -#endif - -/*ToDo: compare the routes with the new ones from lx200driver.c r111 */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "indicom.h" -#include "indidevapi.h" -#include "lx200driver.h" -#include "lx200apdriver.h" - -#ifndef _WIN32 -#include -#endif - -#define LX200_TIMEOUT 5 /* FD timeout in seconds */ - -int lx200ap_debug = 0; - -void set_lx200ap_debug(int value) -{ - lx200ap_debug = value; -} - -int check_lx200ap_connection(int fd) -{ - - int i=0; -/* char ack[1] = { (char) 0x06 }; does not work for AP moung */ - char temp_string[64]; - int error_type; - int nbytes_write=0; - int nbytes_read=0; - - if (lx200ap_debug) - IDLog("Testing telescope's connection using #:GG#...\n"); - - if (fd <= 0) - { - if (lx200ap_debug) - IDLog("check_lx200ap_connection: not a valid file descriptor received\n"); - - return -1; - } - for (i=0; i < 2; i++) - { - if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) - { - if (lx200ap_debug) - IDLog("check_lx200ap_connection: unsuccessful write to telescope, %d\n", nbytes_write); - - - return error_type; - } - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read) ; - tcflush(fd, TCIFLUSH); - if (nbytes_read > 1) - { - temp_string[ nbytes_read -1] = '\0'; - if (lx200ap_debug) - IDLog("check_lx200ap_connection: received bytes %d, [%s]\n", nbytes_write, temp_string); - - return 0; - } - usleep(50000); - } - - if (lx200ap_debug) - IDLog("check_lx200ap_connection: wrote, but nothing received\n"); - - return -1; -} -int getAPUTCOffset(int fd, double *value) -{ - int error_type; - int nbytes_write=0; - int nbytes_read=0; - - char temp_string[16]; - - if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) - return error_type; - - if(( error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) - { - if (lx200ap_debug) - IDLog("getAPUTCOffset: saying good bye %d, %d\n", error_type, nbytes_read); - - - return error_type ; - } - tcflush(fd, TCIFLUSH); - -/* Negative offsets, see AP keypad manual p. 77 */ - if((temp_string[0]== 'A') || ((temp_string[0]== '0')&&(temp_string[1]== '0')) ||(temp_string[0]== '@')) - { - int i ; - for( i=nbytes_read; i > 0; i--) - { - temp_string[i]= temp_string[i-1] ; - } - temp_string[0] = '-' ; - temp_string[nbytes_read + 1] = '\0' ; - - if( temp_string[1]== 'A') - { - temp_string[1]= '0' ; - switch (temp_string[2]) - { - case '5': - - temp_string[2]= '1' ; - break ; - case '4': - - temp_string[2]= '2' ; - break ; - case '3': - - temp_string[2]= '3' ; - break ; - case '2': - - temp_string[2]= '4' ; - break ; - case '1': - - temp_string[2]= '5' ; - break ; - default: - if (lx200ap_debug) - IDLog("getAPUTCOffset: string not handled %s\n", temp_string); - return -1 ; - break ; - } - } - else if( temp_string[1]== '0') - { - temp_string[1]= '0' ; - temp_string[2]= '6' ; - if (lx200ap_debug) - IDLog("getAPUTCOffset: done here %s\n", temp_string); - - } - else if( temp_string[1]== '@') - { - temp_string[1]= '0' ; - switch (temp_string[2]) - { - case '9': - - temp_string[2]= '7' ; - break ; - case '8': - - temp_string[2]= '8' ; - break ; - case '7': - - temp_string[2]= '9' ; - break ; - case '6': - - temp_string[2]= '0' ; - break ; - case '5': - temp_string[1]= '1' ; - temp_string[2]= '1' ; - break ; - case '4': - - temp_string[1]= '1' ; - temp_string[2]= '2' ; - break ; - default: - if (lx200ap_debug) - IDLog("getAPUTCOffset: string not handled %s\n", temp_string); - return -1 ; - break; - } - } - else - { - if (lx200ap_debug) - IDLog("getAPUTCOffset: string not handled %s\n", temp_string); - } - } - else - { - temp_string[nbytes_read - 1] = '\0' ; - } -/* #ifdef INDI_DEBUG - IDLog("getAPUTCOffset: received string %s\n", temp_string); - #endif -*/ - if (f_scansexa(temp_string, value)) - { - fprintf(stderr, "getAPUTCOffset: unable to process [%s]\n", temp_string); - return -1; - } - return 0; -} -int setAPObjectAZ(int fd, double az) -{ - int h, m, s; - char temp_string[16]; - - getSexComponents(az, &h, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:Sz %03d*%02d:%02d#", h, m, s); - if (lx200ap_debug) - IDLog("setAPObjectAZ: Set Object AZ String %s\n", temp_string); - - return (setStandardProcedure(fd, temp_string)); -} - -/* wildi Valid set Values are positive, add error condition */ - -int setAPObjectAlt(int fd, double alt) -{ - int d, m, s; - char temp_string[16]; - - getSexComponents(alt, &d, &m, &s); - - /* case with negative zero */ - if (!d && alt < 0) - { - snprintf(temp_string, sizeof( temp_string ), "#:Sa -%02d*%02d:%02d#", d, m, s) ; - } - else - { - snprintf(temp_string, sizeof( temp_string ), "#:Sa %+02d*%02d:%02d#", d, m, s) ; - } - - if (lx200ap_debug) - IDLog("setAPObjectAlt: Set Object Alt String %s\n", temp_string); - - return (setStandardProcedure(fd, temp_string)); -} -int setAPUTCOffset(int fd, double hours) -{ - int h, m, s ; - - char temp_string[16]; -/* To avoid the peculiar output format of AP controller, see p. 77 key pad manual */ - if( hours < 0.) - { - hours += 24. ; - } - - getSexComponents(hours, &h, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d:%02d:%02d#", h, m, s); - if (lx200ap_debug) - IDLog("setAPUTCOffset: %s\n", temp_string); - - - return (setStandardProcedure(fd, temp_string)); -} -int APSyncCM(int fd, char *matchedObject) -{ - int error_type; - int nbytes_write=0; - int nbytes_read=0; - - if (lx200ap_debug) - IDLog("APSyncCM\n"); - - if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) - return error_type ; - - if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) - return error_type ; - - matchedObject[nbytes_read-1] = '\0'; - - /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ - usleep(10000); - - tcflush(fd, TCIFLUSH); - - return 0; -} -int APSyncCMR(int fd, char *matchedObject) -{ - int error_type; - int nbytes_write=0; - int nbytes_read=0; - - if (lx200ap_debug) - IDLog("APSyncCMR\n"); - - if ( (error_type = tty_write_string(fd, "#:CMR#", &nbytes_write)) != TTY_OK) - return error_type; - - /* read_ret = portRead(matchedObject, -1, LX200_TIMEOUT); */ - if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) - return error_type ; - - matchedObject[nbytes_read-1] = '\0'; - - /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ - usleep(10000); - - tcflush(fd, TCIFLUSH); - - return 0; -} -int selectAPMoveToRate(int fd, int moveToRate) -{ - int error_type; - int nbytes_write=0; - - switch (moveToRate) - { - /* 1200x */ - case 0: - if (lx200ap_debug) - IDLog("selectAPMoveToRate: Setting move to rate to 1200x.\n"); - - if ( (error_type = tty_write_string(fd, "#:RC3#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* 600x */ - case 1: - if (lx200ap_debug) - IDLog("selectAPMoveToRate: Setting move to rate to 600x.\n"); - if ( (error_type = tty_write_string(fd, "#:RC2#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* 64x */ - case 2: - if (lx200ap_debug) - IDLog("selectAPMoveToRate: Setting move to rate to 64x.\n"); - - if ( (error_type = tty_write_string(fd, "#:RC1#", &nbytes_write)) != TTY_OK) - return error_type; - break; - /* 12x*/ - case 3: - if (lx200ap_debug) - IDLog("selectAPMoveToRate: Setting move to rate to 12x.\n"); - if ( (error_type = tty_write_string(fd, "#:RC0#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - default: - return -1; - break; - } - return 0; -} -int selectAPSlewRate(int fd, int slewRate) -{ - int error_type; - int nbytes_write=0; - switch (slewRate) - { - /* 1200x */ - case 0: - if (lx200ap_debug) - IDLog("selectAPSlewRate: Setting slew rate to 1200x.\n"); - - if ( (error_type = tty_write_string(fd, "#:RS2#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* 900x */ - case 1: - if (lx200ap_debug) - IDLog("selectAPSlewRate: Setting slew rate to 900x.\n"); - - if ( (error_type = tty_write_string(fd, "#:RS1#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* 600x */ - case 2: - if (lx200ap_debug) - IDLog("selectAPSlewRate: Setting slew rate to 600x.\n"); - if ( (error_type = tty_write_string(fd, "#:RS0#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - default: - return -1; - break; - } - return 0; -} -int selectAPTrackingMode(int fd, int trackMode) -{ - int error_type; - int nbytes_write=0; - - switch (trackMode) - { - /* Lunar */ - case 0: - if (lx200ap_debug) - IDLog("selectAPTrackingMode: Setting tracking mode to lunar.\n"); - if ( (error_type = tty_write_string(fd, "#:RT0#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* Solar */ - case 1: - if (lx200ap_debug) - IDLog("selectAPTrackingMode: Setting tracking mode to solar.\n"); - if ( (error_type = tty_write_string(fd, "#:RT1#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* Sidereal */ - case 2: - if (lx200ap_debug) - IDLog("selectAPTrackingMode: Setting tracking mode to sidereal.\n"); - if ( (error_type = tty_write_string(fd, "#:RT2#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - /* Zero */ - case 3: - if (lx200ap_debug) - IDLog("selectAPTrackingMode: Setting tracking mode to zero.\n"); - - if ( (error_type = tty_write_string(fd, "#:RT9#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - default: - return -1; - break; - } - return 0; -} -int swapAPButtons(int fd, int currentSwap) -{ - int error_type; - int nbytes_write=0; - - switch (currentSwap) - { - case 0: - if (lx200ap_debug) - IDLog("#:NS#\n"); - if ( (error_type = tty_write_string(fd, "#:NS#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - case 1: - if (lx200ap_debug) - IDLog("#:EW#\n"); - if ( (error_type = tty_write_string(fd, "#:EW#", &nbytes_write)) != TTY_OK) - return error_type; - break; - - default: - return -1; - break; - } - return 0; -} -int setAPObjectRA(int fd, double ra) -{ -/*ToDo AP accepts "#:Sr %02d:%02d:%02d.%1d#"*/ - int h, m, s; - char temp_string[16]; - - getSexComponents(ra, &h, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); - - if (lx200ap_debug) - IDLog("setAPObjectRA: Set Object RA String %s, %f\n", temp_string, ra); - - return (setStandardProcedure(fd, temp_string)); -} - -int setAPObjectDEC(int fd, double dec) -{ - int d, m, s; - char temp_string[16]; - - getSexComponents(dec, &d, &m, &s); - /* case with negative zero */ - if (!d && dec < 0) - { - snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d:%02d#", d, m, s); - } - else - { - snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d:%02d#", d, m, s); - } - if (lx200ap_debug) - IDLog("setAPObjectDEC: Set Object DEC String %s\n", temp_string) ; - - return (setStandardProcedure(fd, temp_string)); -} -int setAPSiteLongitude(int fd, double Long) -{ - int d, m, s; - char temp_string[32]; - - getSexComponents(Long, &d, &m, &s); - snprintf(temp_string, sizeof( temp_string ), "#:Sg %03d*%02d:%02d#", d, m, s); - return (setStandardProcedure(fd, temp_string)); -} - -int setAPSiteLatitude(int fd, double Lat) -{ - int d, m, s; - char temp_string[32]; - - getSexComponents(Lat, &d, &m, &s); - snprintf(temp_string, sizeof( temp_string ), "#:St %+03d*%02d:%02d#", d, m, s); - return (setStandardProcedure(fd, temp_string)); -} diff -Nru libindi-1.0.0/drivers/telescope/lx200apdriver.cpp libindi-1.1.0/drivers/telescope/lx200apdriver.cpp --- libindi-1.0.0/drivers/telescope/lx200apdriver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200apdriver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,556 @@ +#if 0 + LX200 Astro-Physics Driver + Copyright (C) 2007 Markus Wildi + + 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 + +#endif + +/*ToDo: compare the routes with the new ones from lx200driver.c r111 */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "indicom.h" +#include "indilogger.h" +#include "indidevapi.h" +#include "lx200driver.h" +#include "lx200apdriver.h" + +#ifndef _WIN32 +#include +#endif + +#define LX200_TIMEOUT 5 /* FD timeout in seconds */ + +char lx200ap_name[MAXINDIDEVICE]; +unsigned int AP_DBG_SCOPE; + +void set_lx200ap_name(const char *deviceName, unsigned int debug_level) +{ + strncpy(lx200ap_name, deviceName, MAXINDIDEVICE); + AP_DBG_SCOPE = debug_level; +} + +int check_lx200ap_connection(int fd) +{ + int i=0; + char temp_string[64]; + int error_type; + int nbytes_write=0; + int nbytes_read=0; + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "Testing telescope's connection using #:GG#..."); + + if (fd <= 0) + { + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: not a valid file descriptor received"); + + return -1; + } + for (i=0; i < 2; i++) + { + if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) + { + + DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: unsuccessful write to telescope, %d", nbytes_write); + + return error_type; + } + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read) ; + tcflush(fd, TCIFLUSH); + if (nbytes_read > 1) + { + temp_string[ nbytes_read -1] = '\0'; + + DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: received bytes %d, [%s]", nbytes_write, temp_string); + + return 0; + } + usleep(50000); + } + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "check_lx200ap_connection: wrote, but nothing received."); + + return -1; +} +int getAPUTCOffset(int fd, double *value) +{ + int error_type; + int nbytes_write=0; + int nbytes_read=0; + + char temp_string[16]; + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:GG#"); + + if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) + return error_type; + + if(( error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) + { + DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: saying good bye %d, %d", error_type, nbytes_read); + return error_type ; + } + + tcflush(fd, TCIFLUSH); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES (%s)", temp_string); + +/* Negative offsets, see AP keypad manual p. 77 */ + if((temp_string[0]== 'A') || ((temp_string[0]== '0')&&(temp_string[1]== '0')) ||(temp_string[0]== '@')) + { + int i ; + for( i=nbytes_read; i > 0; i--) + { + temp_string[i]= temp_string[i-1] ; + } + temp_string[0] = '-' ; + temp_string[nbytes_read + 1] = '\0' ; + + if( temp_string[1]== 'A') + { + temp_string[1]= '0' ; + switch (temp_string[2]) + { + case '5': + + temp_string[2]= '1' ; + break ; + case '4': + + temp_string[2]= '2' ; + break ; + case '3': + + temp_string[2]= '3' ; + break ; + case '2': + + temp_string[2]= '4' ; + break ; + case '1': + + temp_string[2]= '5' ; + break ; + default: + DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s", temp_string); + return -1 ; + break ; + } + } + else if( temp_string[1]== '0') + { + temp_string[1]= '0' ; + temp_string[2]= '6' ; + } + else if( temp_string[1]== '@') + { + temp_string[1]= '0' ; + switch (temp_string[2]) + { + case '9': + + temp_string[2]= '7' ; + break ; + case '8': + + temp_string[2]= '8' ; + break ; + case '7': + + temp_string[2]= '9' ; + break ; + case '6': + + temp_string[2]= '0' ; + break ; + case '5': + temp_string[1]= '1' ; + temp_string[2]= '1' ; + break ; + case '4': + + temp_string[1]= '1' ; + temp_string[2]= '2' ; + break ; + default: + DEBUGFDEVICE(lx200ap_name, INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s", temp_string); + return -1 ; + break; + } + } + else + { + DEBUGFDEVICE(lx200ap_name , INDI::Logger::DBG_ERROR, "getAPUTCOffset: string not handled %s", temp_string); + } + } + else + { + temp_string[nbytes_read - 1] = '\0' ; + } + + if (f_scansexa(temp_string, value)) + { + DEBUGFDEVICE(lx200ap_name , INDI::Logger::DBG_ERROR, "getAPUTCOffset: unable to process %s", temp_string); + return -1; + } + return 0; +} + +int setAPObjectAZ(int fd, double az) +{ + int h, m, s; + char temp_string[16]; + + getSexComponents(az, &h, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:Sz %03d*%02d:%02d#", h, m, s); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} + +/* wildi Valid set Values are positive, add error condition */ + +int setAPObjectAlt(int fd, double alt) +{ + int d, m, s; + char temp_string[16]; + + getSexComponents(alt, &d, &m, &s); + + /* case with negative zero */ + if (!d && alt < 0) + { + snprintf(temp_string, sizeof( temp_string ), "#:Sa -%02d*%02d:%02d#", d, m, s) ; + } + else + { + snprintf(temp_string, sizeof( temp_string ), "#:Sa %+02d*%02d:%02d#", d, m, s) ; + } + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} +int setAPUTCOffset(int fd, double hours) +{ + int h, m, s ; + + char temp_string[16]; + + getSexComponents(hours, &h, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d:%02d:%02d#", h, m, s); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} +int APSyncCM(int fd, char *matchedObject) +{ + int error_type; + int nbytes_write=0; + int nbytes_read=0; + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:CM#"); + + if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) + return error_type ; + + if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) + return error_type ; + + matchedObject[nbytes_read-1] = '\0'; + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES (%s)", matchedObject); + + /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ + usleep(10000); + + tcflush(fd, TCIFLUSH); + + return 0; +} + +int APSyncCMR(int fd, char *matchedObject) +{ + int error_type; + int nbytes_write=0; + int nbytes_read=0; + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:CMR#"); + + if ( (error_type = tty_write_string(fd, "#:CMR#", &nbytes_write)) != TTY_OK) + return error_type; + + /* read_ret = portRead(matchedObject, -1, LX200_TIMEOUT); */ + if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) + return error_type ; + + matchedObject[nbytes_read-1] = '\0'; + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "RES (%s)", matchedObject); + + /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ + usleep(10000); + + tcflush(fd, TCIFLUSH); + + return 0; +} + +int selectAPMoveToRate(int fd, int moveToRate) +{ + int error_type; + int nbytes_write=0; + + switch (moveToRate) + { + /* 1200x */ + case 0: + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 1200x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RC3#"); + + if ( (error_type = tty_write_string(fd, "#:RC3#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* 600x */ + case 1: + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 600x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RC2#"); + if ( (error_type = tty_write_string(fd, "#:RC2#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* 64x */ + case 2: + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 64x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RC1#"); + + if ( (error_type = tty_write_string(fd, "#:RC1#", &nbytes_write)) != TTY_OK) + return error_type; + break; + /* 12x*/ + case 3: + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPMoveToRate: Setting move to rate to 12x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RC0#"); + + if ( (error_type = tty_write_string(fd, "#:RC0#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + default: + return -1; + break; + } + return 0; +} +int selectAPSlewRate(int fd, int slewRate) +{ + int error_type; + int nbytes_write=0; + switch (slewRate) + { + /* 1200x */ + case 0: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 1200x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RS2#"); + + if ( (error_type = tty_write_string(fd, "#:RS2#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* 900x */ + case 1: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 900x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RS1#"); + + if ( (error_type = tty_write_string(fd, "#:RS1#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* 600x */ + case 2: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPSlewRate: Setting slew to rate to 600x"); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RS0#"); + + if ( (error_type = tty_write_string(fd, "#:RS0#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + default: + return -1; + break; + } + return 0; +} +int selectAPTrackingMode(int fd, int trackMode) +{ + int error_type; + int nbytes_write=0; + + switch (trackMode) + { + /* Sidereal */ + case 0: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to sidereal."); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RT2#"); + + if ( (error_type = tty_write_string(fd, "#:RT2#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* Solar */ + case 1: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to solar."); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RT1#"); + + if ( (error_type = tty_write_string(fd, "#:RT1#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* Lunar */ + case 2: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to lunar."); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RT0#"); + + if ( (error_type = tty_write_string(fd, "#:RT0#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + /* Zero */ + case 3: + + DEBUGDEVICE(lx200ap_name, INDI::Logger::DBG_DEBUG, "selectAPTrackingMode: Setting tracking mode to Zero."); + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:RT9#"); + + if ( (error_type = tty_write_string(fd, "#:RT9#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + default: + return -1; + break; + } + return 0; +} + +int swapAPButtons(int fd, int currentSwap) +{ + int error_type; + int nbytes_write=0; + + switch (currentSwap) + { + case 0: + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:NS#"); + if ( (error_type = tty_write_string(fd, "#:NS#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + case 1: + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", "#:EW#"); + if ( (error_type = tty_write_string(fd, "#:EW#", &nbytes_write)) != TTY_OK) + return error_type; + break; + + default: + return -1; + break; + } + return 0; +} + +int setAPObjectRA(int fd, double ra) +{ +/*ToDo AP accepts "#:Sr %02d:%02d:%02d.%1d#"*/ + int h, m, s; + char temp_string[16]; + + getSexComponents(ra, &h, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} + +int setAPObjectDEC(int fd, double dec) +{ + int d, m, s; + char temp_string[16]; + + getSexComponents(dec, &d, &m, &s); + /* case with negative zero */ + if (!d && dec < 0) + { + snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d:%02d#", d, m, s); + } + else + { + snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d:%02d#", d, m, s); + } + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + + return (setStandardProcedure(fd, temp_string)); +} + +int setAPSiteLongitude(int fd, double Long) +{ + int d, m, s; + char temp_string[32]; + + getSexComponents(Long, &d, &m, &s); + snprintf(temp_string, sizeof( temp_string ), "#:Sg %03d*%02d:%02d#", d, m, s); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} + +int setAPSiteLatitude(int fd, double Lat) +{ + int d, m, s; + char temp_string[32]; + + getSexComponents(Lat, &d, &m, &s); + snprintf(temp_string, sizeof( temp_string ), "#:St %+03d*%02d:%02d#", d, m, s); + + DEBUGFDEVICE(lx200ap_name, AP_DBG_SCOPE, "CMD (%s)", temp_string); + + return (setStandardProcedure(fd, temp_string)); +} diff -Nru libindi-1.0.0/drivers/telescope/lx200apdriver.h libindi-1.1.0/drivers/telescope/lx200apdriver.h --- libindi-1.0.0/drivers/telescope/lx200apdriver.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200apdriver.h 2015-09-06 13:17:35.000000000 +0000 @@ -35,9 +35,8 @@ extern "C" { #endif -void set_lx200ap_debug(int value); +void set_lx200ap_name(const char *deviceName, unsigned int debug_level); int check_lx200ap_connection(int fd) ; -int initializeAPmount(int fd) ; int getAPUTCOffset (int fd, double *value) ; int setAPObjectAZ(int fd, double az); int setAPObjectAlt(int fd, double alt); diff -Nru libindi-1.0.0/drivers/telescope/lx200ap.h libindi-1.1.0/drivers/telescope/lx200ap.h --- libindi-1.0.0/drivers/telescope/lx200ap.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200ap.h 2015-09-06 13:17:35.000000000 +0000 @@ -39,10 +39,8 @@ LX200AstroPhysics(); ~LX200AstroPhysics() {} - - virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual void ISGetProperties(const char *dev); void setupTelescope(); @@ -57,19 +55,26 @@ virtual bool ReadScopeStatus(); + // Parking + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); virtual bool Park(); + virtual bool UnPark(); + virtual bool Sync(double ra, double dec); virtual bool Goto(double, double); - virtual bool Connect(char *); + virtual bool Connect(const char *port, uint16_t baud); virtual bool Disconnect(); virtual bool updateTime(ln_date * utc, double utc_offset); virtual bool updateLocation(double latitude, double longitude, double elevation); + virtual bool SetSlewRate(int index); virtual void debugTriggered(bool enable); - virtual void processButton(const char * button_n, ISState state); bool setBasicDataPart0(); bool setBasicDataPart1(); + unsigned int DBG_SCOPE; + ISwitch StartUpS[2]; ISwitchVectorProperty StartUpSP; @@ -79,11 +84,8 @@ INumber HorizontalCoordsN[2]; INumberVectorProperty HorizontalCoordsNP; - ISwitch MoveToRateS[4]; - ISwitchVectorProperty MoveToRateSP; - - ISwitch SlewRateS[3]; - ISwitchVectorProperty SlewRateSP; + ISwitch SlewSpeedS[3]; + ISwitchVectorProperty SlewSpeedSP; ISwitch SwapS[2]; ISwitchVectorProperty SwapSP; @@ -97,8 +99,11 @@ IText DeclinationAxisT[1]; ITextVectorProperty DeclinationAxisTP; - INumber APSiderealTimeN[1]; - INumberVectorProperty APSiderealTimeNP; + //INumber APSiderealTimeN[1]; + //INumberVectorProperty APSiderealTimeNP; + + INumber SlewAccuracyN[2]; + INumberVectorProperty SlewAccuracyNP; bool timeUpdated, locationUpdated; diff -Nru libindi-1.0.0/drivers/telescope/lx200autostar.cpp libindi-1.1.0/drivers/telescope/lx200autostar.cpp --- libindi-1.0.0/drivers/telescope/lx200autostar.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200autostar.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -96,12 +96,14 @@ // For Autostar, we have a different focus speed method // Therefore, we don't need the classical one deleteProperty(FocusModeSP.name); + return true; } else { deleteProperty(VersionTP.name); deleteProperty(FocusSpeedNP.name); + return true; } } diff -Nru libindi-1.0.0/drivers/telescope/lx200basic.cpp libindi-1.1.0/drivers/telescope/lx200basic.cpp --- libindi-1.0.0/drivers/telescope/lx200basic.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200basic.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -1,6 +1,6 @@ #if 0 LX200 Basic Driver - Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) + Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -29,33 +29,22 @@ #include -/* INDI Common Library Routines */ +#include "lx200driver.h" +#include "lx200basic.h" #include "indicom.h" -/* LX200 Command Set */ -#include "lx200driver.h" +#define POLLMS 1000 + +/* Simulation Parameters */ +#define SLEWRATE 1 /* slew rate, degrees/s */ +#define SIDRATE 0.004178 /* sidereal rate, degrees/s */ -/* Our driver header */ -#include "lx200basic.h" using namespace std; /* Our telescope auto pointer */ auto_ptr telescope(0); -const int POLLMS = 1000; // Period of update, 1 second. -char *mydev; // Name of our device. - -const char *BASIC_GROUP = "Main Control"; // Main Group -const char *OPTIONS_GROUP = "Options"; // Options Group - -/* Handy Macros */ -#define currentRA EquatorialCoordsN[0].value -#define currentDEC EquatorialCoordsN[1].value - -static void ISPoll(void *); -static void retry_connection(void *); - /************************************************************************************** ** Send client definitions of all properties. ***************************************************************************************/ @@ -69,8 +58,7 @@ if (telescope.get() == 0) telescope.reset(new LX200Basic()); isInit = 1; - - IEAddTimer (POLLMS, ISPoll, NULL); + } /************************************************************************************** @@ -112,17 +100,6 @@ /************************************************************************************** ** ***************************************************************************************/ -void ISPoll (void *p) -{ - INDI_UNUSED(p); - - telescope->ISPoll(); - IEAddTimer (POLLMS, ISPoll, NULL); -} - -/************************************************************************************** -** -***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); @@ -147,29 +124,25 @@ ** LX200 Basic constructor ***************************************************************************************/ LX200Basic::LX200Basic() -{ - mydev = new char[MAXINDIDEVICE]; +{ + setVersion(2, 0); - char *envDev = getenv("INDIDEV"); + DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); - if (envDev != NULL) - strncpy(mydev, envDev, MAXINDIDEVICE); - else - strncpy(mydev, "LX200 Basic", MAXINDIDEVICE); + currentRA=ln_get_apparent_sidereal_time(ln_get_julian_from_sys()); + currentDEC=90; - init_properties(); + TelescopeCapability cap; - lastSet = -1; - fd = -1; - simulation = false; - lastRA = 0; - lastDEC = 0; - currentSet = 0; - - IDLog("Initializing from LX200 Basic device...\n"); - IDLog("Driver Version: 2014-12-31\n"); - - enable_simulation(false); + cap.canPark = false; + cap.canSync = true; + cap.canAbort = true; + cap.hasTime = false; + cap.hasLocation = false; + cap.nSlewRate=0; + SetTelescopeCapability(&cap); + + DEBUG(INDI::Logger::DBG_DEBUG, "Initializing from LX200 Basic device..."); } @@ -182,47 +155,38 @@ } /************************************************************************************** -** Initialize all properties & set default values. +** ***************************************************************************************/ -void LX200Basic::init_properties() +void LX200Basic::debugTriggered(bool enable) { - // Connection - IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF); - IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON); - IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); - - // Coord Set - IUFillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON); - IUFillSwitch(&OnCoordSetS[1], "TRACK", "Track", ISS_OFF); - IUFillSwitch(&OnCoordSetS[2], "SYNC", "Sync", ISS_OFF); - IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - // Abort - IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF); - IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); - - // Port - IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyS0"); - IUFillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE); - - // Object Name - IUFillText(&ObjectT[0], "OBJECT_NAME", "Name", "--"); - IUFillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE); - - // Equatorial Coords - IUFillNumber(&EquatorialCoordsN[0], "RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0.); - IUFillNumber(&EquatorialCoordsN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.); - IUFillNumberVector(&EquatorialCoordsNP, EquatorialCoordsN, NARRAY(EquatorialCoordsN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE); + INDI_UNUSED(enable); + setLX200Debug(getDeviceName(), DBG_SCOPE); +} + +/************************************************************************************** +** +***************************************************************************************/ +const char * LX200Basic::getDefaultName() +{ + return (char *)"LX200 Basic"; +} + +/************************************************************************************** +** +***************************************************************************************/ +bool LX200Basic::initProperties() +{ + /* Make sure to init parent properties first */ + INDI::Telescope::initProperties(); // Slew threshold IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); - IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), mydev, "Slew Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE); + IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), getDeviceName(), "Slew Accuracy", "", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); + + addAuxControls(); - // Track threshold - IUFillNumber(&TrackAccuracyN[0], "TrackRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); - IUFillNumber(&TrackAccuracyN[1], "TrackDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); - IUFillNumberVector(&TrackAccuracyNP, TrackAccuracyN, NARRAY(TrackAccuracyN), mydev, "Tracking Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE); + return true; } /************************************************************************************** @@ -230,668 +194,385 @@ ***************************************************************************************/ void LX200Basic::ISGetProperties(const char *dev) { + if(dev && strcmp(dev,getDeviceName())) + return; - if (dev && strcmp (mydev, dev)) - return; + INDI::Telescope::ISGetProperties(dev); - // Main Control - IDDefSwitch(&ConnectSP, NULL); - IDDefText(&PortTP, NULL); - IDDefText(&ObjectTP, NULL); - IDDefNumber(&EquatorialCoordsNP, NULL); - IDDefSwitch(&OnCoordSetSP, NULL); - IDDefSwitch(&AbortSlewSP, NULL); - - // Options - IDDefNumber(&SlewAccuracyNP, NULL); - IDDefNumber(&TrackAccuracyNP, NULL); - + if (isConnected()) + defineNumber(&SlewAccuracyNP); } /************************************************************************************** -** Process Text properties +** ***************************************************************************************/ -void LX200Basic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) +bool LX200Basic::updateProperties() { - // Ignore if not ours - if (strcmp (dev, mydev)) - return; - - // =================================== - // Port Name - // =================================== - if (!strcmp(name, PortTP.name) ) - { - if (IUUpdateText(&PortTP, texts, names, n) < 0) - return; - - PortTP.s = IPS_OK; - IDSetText (&PortTP, NULL); - return; - } + INDI::Telescope::updateProperties(); - if (is_connected() == false) - { - IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); - reset_all_properties(); - return; - } + if (isConnected()) + { + defineNumber(&SlewAccuracyNP); - // =================================== - // Object Name - // =================================== - if (!strcmp (name, ObjectTP.name)) - { + // We don't support NSWE controls + deleteProperty(MovementNSSP.name); + deleteProperty(MovementWESP.name); - if (IUUpdateText(&ObjectTP, texts, names, n) < 0) - return; + getBasicData(); + } + else + { + deleteProperty(SlewAccuracyNP.name); + } - ObjectTP.s = IPS_OK; - IDSetText(&ObjectTP, NULL); - return; - } + return true; } /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +bool LX200Basic::Connect() { - - // Ignore if not ours - if (strcmp (dev, mydev)) - return; + bool rc=false; - if (is_connected() == false) - { - IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); - reset_all_properties(); - return; - } - - // =================================== - // Equatorial Coords - // =================================== - if (!strcmp (name, EquatorialCoordsNP.name)) - { - int i=0, nset=0, error_code=0; - double newRA =0, newDEC =0; - - for (nset = i = 0; i < n; i++) - { - INumber *eqp = IUFindNumber (&EquatorialCoordsNP, names[i]); - if (eqp == &EquatorialCoordsN[0]) - { - newRA = values[i]; - nset += newRA >= 0 && newRA <= 24.0; - } else if (eqp == &EquatorialCoordsN[1]) - { - newDEC = values[i]; - nset += newDEC >= -90.0 && newDEC <= 90.0; - } - } - - if (nset == 2) - { - char RAStr[32], DecStr[32]; - - fs_sexa(RAStr, newRA, 2, 3600); - fs_sexa(DecStr, newDEC, 2, 3600); - - #ifdef INDI_DEBUG - IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC); - IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr); - #endif - - if (!simulation && ( (error_code = setObjectRA(fd, newRA)) < 0 || ( error_code = setObjectDEC(fd, newDEC)) < 0)) - { - handle_error(&EquatorialCoordsNP, error_code, "Setting RA/DEC"); - return; - } - - targetRA = newRA; - targetDEC = newDEC; - - if (process_coords() == false) - { - EquatorialCoordsNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsNP, NULL); - - } - } // end nset - else - { - EquatorialCoordsNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsNP, "RA or Dec missing or invalid"); - } - - return; - } /* end EquatorialCoordsWNP */ - - // =================================== - // Update tracking precision limits - // =================================== - if (!strcmp (name, TrackAccuracyNP.name)) - { - if (IUUpdateNumber(&TrackAccuracyNP, values, names, n) < 0) - return; - - TrackAccuracyNP.s = IPS_OK; - - if (TrackAccuracyN[0].value < 3 || TrackAccuracyN[1].value < 3) - IDSetNumber(&TrackAccuracyNP, "Warning: Setting the tracking accuracy too low may result in a dead lock"); - else - IDSetNumber(&TrackAccuracyNP, NULL); - return; - } - - // =================================== - // Update slew precision limit - // =================================== - if (!strcmp(name, SlewAccuracyNP.name)) - { - if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) - return; - - SlewAccuracyNP.s = IPS_OK; - - if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) - IDSetNumber(&TrackAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); - - IDSetNumber(&SlewAccuracyNP, NULL); - return; - - - } -} - -/************************************************************************************** -** -***************************************************************************************/ -void LX200Basic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - // ignore if not ours // - if (strcmp (mydev, dev)) - return; - - // =================================== - // Connect Switch - // =================================== - if (!strcmp (name, ConnectSP.name)) - { - if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) - return; - - connect_telescope(); - return; - } + if(isConnected()) return true; - if (is_connected() == false) - { - IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); - reset_all_properties(); - return; - } - - // =================================== - // Coordinate Set - // =================================== - if (!strcmp(name, OnCoordSetSP.name)) - { - if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) - return; - - currentSet = get_switch_index(&OnCoordSetSP); - OnCoordSetSP.s = IPS_OK; - IDSetSwitch(&OnCoordSetSP, NULL); - } - - // =================================== - // Abort slew - // =================================== - if (!strcmp (name, AbortSlewSP.name)) - { - - IUResetSwitch(&AbortSlewSP); - abortSlew(fd); - - if (EquatorialCoordsNP.s == IPS_BUSY) - { - AbortSlewSP.s = IPS_OK; - EquatorialCoordsNP.s = IPS_IDLE; - IDSetSwitch(&AbortSlewSP, "Slew aborted."); - IDSetNumber(&EquatorialCoordsNP, NULL); - } + rc=Connect(PortT[0].text, atoi(IUFindOnSwitch(&BaudRateSP)->name)); - return; - } + if(rc) + SetTimer(POLLMS); + return rc; } /************************************************************************************** -** Retry connecting to the telescope on error. Give up if there is no hope. +** ***************************************************************************************/ -void LX200Basic::handle_error(INumberVectorProperty *nvp, int err, const char *msg) +bool LX200Basic::Connect(const char *port, uint16_t baud) { - - nvp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_lx200_connection(fd)) + if (isSimulation()) { - /* The telescope is off locally */ - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetNumber(nvp, NULL); - IEAddTimer(10000, retry_connection, &fd); - return; + DEBUGF (INDI::Logger::DBG_SESSION, "Simulated %s is online.", getDeviceName()); + return true; } - - /* If the error is a time out, then the device doesn't support this property */ - if (err == -2) - { - nvp->s = IPS_ALERT; - IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - else - /* Changing property failed, user should retry. */ - IDSetNumber( nvp , "%s failed.", msg); - - fault = true; -} -/************************************************************************************** -** Set all properties to idle and reset most switches to clean state. -***************************************************************************************/ -void LX200Basic::reset_all_properties() -{ - ConnectSP.s = IPS_IDLE; - OnCoordSetSP.s = IPS_IDLE; - AbortSlewSP.s = IPS_IDLE; - PortTP.s = IPS_IDLE; - ObjectTP.s = IPS_IDLE; - EquatorialCoordsNP.s = IPS_IDLE; - SlewAccuracyNP.s = IPS_IDLE; - TrackAccuracyNP.s = IPS_IDLE; + if (tty_connect(port, baud, 8, 0, 1, &PortFD) != TTY_OK) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); + return false; + } - IUResetSwitch(&OnCoordSetSP); - IUResetSwitch(&AbortSlewSP); - OnCoordSetS[0].s = ISS_ON; - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; + if (check_lx200_connection(PortFD)) + { + DEBUG(INDI::Logger::DBG_ERROR, "Error connecting to Telescope. Telescope is offline."); + return false; + } + + DEBUGF (INDI::Logger::DBG_SESSION, "%s is online. Retrieving basic data...", getDeviceName()); - IDSetSwitch(&ConnectSP, NULL); - IDSetSwitch(&OnCoordSetSP, NULL); - IDSetSwitch(&AbortSlewSP, NULL); - IDSetText(&PortTP, NULL); - IDSetText(&ObjectTP, NULL); - IDSetNumber(&EquatorialCoordsNP, NULL); - IDSetNumber(&SlewAccuracyNP, NULL); - IDSetNumber(&TrackAccuracyNP, NULL); + return true; } + /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::correct_fault() +bool LX200Basic::Disconnect() { - fault = false; - IDMessage(mydev, "Telescope is online."); + if (isSimulation() == false) + tty_disconnect(PortFD); + return true; } /************************************************************************************** ** ***************************************************************************************/ -bool LX200Basic::is_connected() +bool LX200Basic::isSlewComplete() { - if (simulation) return true; - - return (ConnectSP.sp[0].s == ISS_ON); + const double dx = targetRA - currentRA; + const double dy = targetDEC - currentDEC; + return fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0); } /************************************************************************************** ** ***************************************************************************************/ -static void retry_connection(void * p) +bool LX200Basic::ReadScopeStatus() { - int fd = *((int *) p); + if (isConnected() == false) + return false; + + if (isSimulation()) + { + mountSim(); + return true; + } + + if ( getLX200RA(PortFD, ¤tRA) < 0 || getLX200DEC(PortFD, ¤tDEC) < 0) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP, "Error reading RA/DEC."); + return false; + } - if (check_lx200_connection(fd)) - telescope->connection_lost(); - else - telescope->connection_resumed(); + if (TrackState == SCOPE_SLEWING) + { + // Check if LX200 is done slewing + if (isSlewComplete()) + { + TrackState=SCOPE_TRACKING; + IDMessage(getDeviceName(),"Slew is complete. Tracking..."); + + } + } + + NewRaDec(currentRA, currentDEC); + + return true; } /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::ISPoll() -{ - if (is_connected() == false || simulation) - return; +bool LX200Basic::Goto(double r,double d) +{ + targetRA=r; + targetDEC=d; + char RAStr[64], DecStr[64]; - double dx, dy; - int error_code=0; + fs_sexa(RAStr, targetRA, 2, 3600); + fs_sexa(DecStr, targetDEC, 2, 3600); - switch (EquatorialCoordsNP.s) - { - case IPS_IDLE: - getLX200RA(fd, ¤tRA); - getLX200DEC(fd, ¤tDEC); - - // Only update values if there are some interesting changes - if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01) - { - lastRA = currentRA; - lastDEC = currentDEC; - IDSetNumber (&EquatorialCoordsNP, NULL); - } - break; - - case IPS_BUSY: - getLX200RA(fd, ¤tRA); - getLX200DEC(fd, ¤tDEC); - dx = targetRA - currentRA; - dy = targetDEC - currentDEC; - - // Wait until acknowledged or within threshold - if ( fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0)) - { - lastRA = currentRA; - lastDEC = currentDEC; - IUResetSwitch(&OnCoordSetSP); - OnCoordSetSP.s = IPS_OK; - EquatorialCoordsNP.s = IPS_OK; - IDSetNumber (&EquatorialCoordsNP, NULL); - - switch (currentSet) - { - case LX200_SLEW: - OnCoordSetSP.sp[LX200_SLEW].s = ISS_ON; - IDSetSwitch (&OnCoordSetSP, "Slew is complete."); - break; - - case LX200_TRACK: - OnCoordSetSP.sp[LX200_TRACK].s = ISS_ON; - IDSetSwitch (&OnCoordSetSP, "Slew is complete. Tracking..."); - break; - - case LX200_SYNC: - break; - } - - } - else - IDSetNumber (&EquatorialCoordsNP, NULL); - break; - - case IPS_OK: - - if ( (error_code = getLX200RA(fd, ¤tRA)) < 0 || (error_code = getLX200DEC(fd, ¤tDEC)) < 0) - { - handle_error(&EquatorialCoordsNP, error_code, "Getting RA/DEC"); - return; - } - - if (fault == true) - correct_fault(); - - if ( (currentRA != lastRA) || (currentDEC != lastDEC)) - { - lastRA = currentRA; - lastDEC = currentDEC; - IDSetNumber (&EquatorialCoordsNP, NULL); - } - break; - - case IPS_ALERT: - break; - } + // If moving, let's stop it first. + if (EqNP.s == IPS_BUSY) + { + if (!isSimulation() && abortSlew(PortFD) < 0) + { + AbortSP.s = IPS_ALERT; + IDSetSwitch(&AbortSP, "Abort slew failed."); + return false; + } + + AbortSP.s = IPS_OK; + EqNP.s = IPS_IDLE; + IDSetSwitch(&AbortSP, "Slew aborted."); + IDSetNumber(&EqNP, NULL); + + // sleep for 100 mseconds + usleep(100000); + } + + if (isSimulation() == false) + { + if (setObjectRA(PortFD, targetRA) < 0 || (setObjectDEC(PortFD, targetDEC)) < 0) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP, "Error setting RA/DEC."); + return false; + } + + int err=0; + /* Slew reads the '0', that is not the end of the slew */ + if (err = Slew(PortFD)) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); + slewError(err); + return false; + } + } + + TrackState = SCOPE_SLEWING; + EqNP.s = IPS_BUSY; + + IDMessage(getDeviceName(), "Slewing to RA: %s - DEC: %s", RAStr, DecStr); + return true; } /************************************************************************************** ** ***************************************************************************************/ -bool LX200Basic::process_coords() -{ - - int error_code; - char syncString[256]; - char RAStr[32], DecStr[32]; - double dx, dy; - - switch (currentSet) - { +bool LX200Basic::Sync(double ra, double dec) +{ + char syncString[256]; - // Slew - case LX200_SLEW: - lastSet = LX200_SLEW; - if (EquatorialCoordsNP.s == IPS_BUSY) - { - IDLog("Aborting Slew\n"); - abortSlew(fd); - - // sleep for 100 mseconds - usleep(100000); - } - - if ( !simulation && (error_code = Slew(fd))) - { - slew_error(error_code); - return false; - } - - EquatorialCoordsNP.s = IPS_BUSY; - fs_sexa(RAStr, targetRA, 2, 3600); - fs_sexa(DecStr, targetDEC, 2, 3600); - IDSetNumber(&EquatorialCoordsNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); - IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); - break; - - // Track - case LX200_TRACK: - //IDLog("We're in LX200_TRACK\n"); - if (EquatorialCoordsNP.s == IPS_BUSY) - { - IDLog("Aborting Slew\n"); - abortSlew(fd); - - // sleep for 200 mseconds - usleep(200000); - } - - dx = fabs ( targetRA - currentRA ); - dy = fabs (targetDEC - currentDEC); - - if (dx >= (TrackAccuracyN[0].value/(60.0*15.0)) || (dy >= TrackAccuracyN[1].value/60.0)) - { - if ( !simulation && (error_code = Slew(fd))) - { - slew_error(error_code); - return false; - } - - fs_sexa(RAStr, targetRA, 2, 3600); - fs_sexa(DecStr, targetDEC, 2, 3600); - EquatorialCoordsNP.s = IPS_BUSY; - IDSetNumber(&EquatorialCoordsNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); - IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); - } - else - { - //IDLog("Tracking called, but tracking threshold not reached yet.\n"); - EquatorialCoordsNP.s = IPS_OK; - - if (lastSet != LX200_TRACK) - IDSetNumber(&EquatorialCoordsNP, "Tracking..."); - else - IDSetNumber(&EquatorialCoordsNP, NULL); - - } - lastSet = LX200_TRACK; - break; - - // Sync - case LX200_SYNC: - - lastSet = LX200_SYNC; - EquatorialCoordsNP.s = IPS_IDLE; - - if ( !simulation && ( error_code = Sync(fd, syncString) < 0) ) - { - IDSetNumber( &EquatorialCoordsNP , "Synchronization failed."); - return false; - } - - if (simulation) - { - EquatorialCoordsN[0].value = targetRA; - EquatorialCoordsN[1].value = targetDEC; - } - - EquatorialCoordsNP.s = IPS_OK; - IDLog("Synchronization successful %s\n", syncString); - IDSetNumber(&EquatorialCoordsNP, "Synchronization successful."); - break; + if (isSimulation() == false && + (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0)) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync."); + return false; } - return true; + if (isSimulation() == false && ::Sync(PortFD, syncString) < 0) + { + EqNP.s = IPS_ALERT; + IDSetNumber(&EqNP , "Synchronization failed."); + return false; + } + + currentRA = ra; + currentDEC = dec; + + DEBUG(INDI::Logger::DBG_SESSION, "Synchronization successful."); + + TrackState = SCOPE_IDLE; + EqNP.s = IPS_OK; + + NewRaDec(currentRA, currentDEC); + return true; } + /************************************************************************************** ** ***************************************************************************************/ -int LX200Basic::get_switch_index(ISwitchVectorProperty *sp) -{ - for (int i=0; i < sp->nsp ; i++) - if (sp->sp[i].s == ISS_ON) - return i; +bool LX200Basic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) + { + if (!strcmp(name, SlewAccuracyNP.name)) + { + if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) + return false; - return -1; + SlewAccuracyNP.s = IPS_OK; + + if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) + IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); + + IDSetNumber(&SlewAccuracyNP, NULL); + return true; + } + } + + return INDI::Telescope::ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::connect_telescope() +bool LX200Basic::Abort() { - switch (ConnectSP.sp[0].s) + if (isSimulation() == false && abortSlew(PortFD) < 0) { - case ISS_ON: - - if (simulation) - { - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Simulated telescope is online."); - return; - } - - if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) - { - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortT[0].text); - return; - } - - if (check_lx200_connection(fd)) - { - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); - return; - } - - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); - get_initial_data(); - break; - - case ISS_OFF: - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_IDLE; - if (simulation) - { - IDSetSwitch (&ConnectSP, "Simulated Telescope is offline."); - return; - } - IDSetSwitch (&ConnectSP, "Telescope is offline."); - IDLog("Telescope is offline."); - - tty_disconnect(fd); - break; - } + DEBUG(INDI::Logger::DBG_ERROR, "Failed to abort slew."); + return false; + } + + EqNP.s = IPS_IDLE; + TrackState = SCOPE_IDLE; + IDSetNumber(&EqNP, NULL); + + DEBUG(INDI::Logger::DBG_SESSION, "Slew aborted."); + return true; } + + /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::get_initial_data() +void LX200Basic::getBasicData() { // Make sure short - checkLX200Format(fd); + checkLX200Format(PortFD); // Get current RA/DEC - getLX200RA(fd, ¤tRA); - getLX200DEC(fd, ¤tDEC); + getLX200RA(PortFD, ¤tRA); + getLX200DEC(PortFD, ¤tDEC); - IDSetNumber (&EquatorialCoordsNP, NULL); + IDSetNumber (&EqNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::slew_error(int slewCode) +void LX200Basic::mountSim () { - OnCoordSetSP.s = IPS_IDLE; + static struct timeval ltv; + struct timeval tv; + double dt, da, dx; + int nlocked; - if (slewCode == 1) - IDSetSwitch (&OnCoordSetSP, "Object below horizon."); - else if (slewCode == 2) - IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit."); - else - IDSetSwitch (&OnCoordSetSP, "Slew failed."); -} + /* update elapsed time since last poll, don't presume exactly POLLMS */ + gettimeofday (&tv, NULL); + + if (ltv.tv_sec == 0 && ltv.tv_usec == 0) + ltv = tv; + + dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; + ltv = tv; + da = SLEWRATE*dt; + + /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ + switch (TrackState) + { + + case SCOPE_TRACKING: + /* RA moves at sidereal, Dec stands still */ + currentRA += (SIDRATE*dt/15.); + break; + + case SCOPE_SLEWING: + /* slewing - nail it when both within one pulse @ SLEWRATE */ + nlocked = 0; + + dx = targetRA - currentRA; + + if (fabs(dx) <= da) + { + currentRA = targetRA; + nlocked++; + } + else if (dx > 0) + currentRA += da/15.; + else + currentRA -= da/15.; + + dx = targetDEC - currentDEC; + if (fabs(dx) <= da) + { + currentDEC = targetDEC; + nlocked++; + } + else if (dx > 0) + currentDEC += da; + else + currentDEC -= da; + + if (nlocked == 2) + { + TrackState = SCOPE_TRACKING; + + } + + break; + + default: + break; + } + + NewRaDec(currentRA, currentDEC); -/************************************************************************************** -** -***************************************************************************************/ -void LX200Basic::enable_simulation(bool enable) -{ - simulation = enable; - - if (simulation) - IDLog("Warning: Simulation is activated.\n"); - else - IDLog("Simulation is disabled.\n"); -} -/************************************************************************************** -** -***************************************************************************************/ -void LX200Basic::connection_lost() -{ - ConnectSP.s = IPS_IDLE; - IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); - return; - } /************************************************************************************** ** ***************************************************************************************/ -void LX200Basic::connection_resumed() +void LX200Basic::slewError(int slewCode) { - ConnectS[0].s = ISS_ON; - ConnectS[1].s = ISS_OFF; - ConnectSP.s = IPS_OK; - - IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); + EqNP.s = IPS_ALERT; + + if (slewCode == 1) + IDSetNumber(&EqNP, "Object below horizon."); + else if (slewCode == 2) + IDSetNumber(&EqNP, "Object below the minimum elevation limit."); + else + IDSetNumber(&EqNP, "Slew failed."); + } diff -Nru libindi-1.0.0/drivers/telescope/lx200basic.h libindi-1.1.0/drivers/telescope/lx200basic.h --- libindi-1.0.0/drivers/telescope/lx200basic.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200basic.h 2015-09-06 13:17:35.000000000 +0000 @@ -21,95 +21,48 @@ #ifndef LX200BASIC_H #define LX200BASIC_H -#include "indidevapi.h" -#include "indicom.h" +#include "inditelescope.h" -class LX200Basic +class LX200Basic : public INDI::Telescope { public: LX200Basic(); ~LX200Basic(); - void ISGetProperties (const char *dev); - void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - void ISPoll (); + virtual const char *getDefaultName(); + virtual bool Connect(); + virtual bool Connect(const char *port, uint16_t baud); + virtual bool Disconnect(); + virtual bool ReadScopeStatus(); + virtual void ISGetProperties(const char *dev); + virtual bool initProperties(); + virtual bool updateProperties(); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + +protected: + + virtual bool Abort(); + virtual bool Goto(double,double); + virtual bool Sync(double ra, double dec); - void connection_lost(); - void connection_resumed(); + virtual void debugTriggered(bool enable); + + virtual void getBasicData(); -private: - enum LX200_STATUS { LX200_SLEW, LX200_TRACK, LX200_SYNC, LX200_PARK }; +private: - /* Switches */ - ISwitch ConnectS[2]; - ISwitch OnCoordSetS[3]; - ISwitch AbortSlewS[1]; - - /* Texts */ - IText PortT[1]; - IText ObjectT[1]; + bool isSlewComplete(); + void slewError(int slewCode); + void mountSim(); - /* Numbers */ - INumber EquatorialCoordsN[2]; INumber SlewAccuracyN[2]; - INumber TrackAccuracyN[2]; - - /* Switch Vectors */ - ISwitchVectorProperty ConnectSP; - ISwitchVectorProperty OnCoordSetSP; - ISwitchVectorProperty AbortSlewSP; - - /* Number Vectors */ - INumberVectorProperty EquatorialCoordsNP; INumberVectorProperty SlewAccuracyNP; - INumberVectorProperty TrackAccuracyNP; - - /* Text Vectors */ - ITextVectorProperty PortTP; - ITextVectorProperty ObjectTP; - - /*******************************************************/ - /* Connection Routines - ********************************************************/ - void init_properties(); - void get_initial_data(); - void connect_telescope(); - bool is_connected(void); - - /*******************************************************/ - /* Misc routines - ********************************************************/ - bool process_coords(); - int get_switch_index(ISwitchVectorProperty *sp); - - /*******************************************************/ - /* Simulation Routines - ********************************************************/ - void enable_simulation(bool enable); - - /*******************************************************/ - /* Error handling routines - ********************************************************/ - void slew_error(int slewCode); - void reset_all_properties(); - void handle_error(INumberVectorProperty *nvp, int err, const char *msg); - void correct_fault(); - - protected: - - double JD; /* Julian Date */ - double lastRA; - double lastDEC; - bool simulation; - bool fault; - int fd; /* Telescope tty file descriptor */ - int currentSet; - int lastSet; + bool simulation; double targetRA, targetDEC; + double currentRA, currentDEC; + unsigned int DBG_SCOPE; }; diff -Nru libindi-1.0.0/drivers/telescope/lx200classic.cpp libindi-1.1.0/drivers/telescope/lx200classic.cpp --- libindi-1.0.0/drivers/telescope/lx200classic.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200classic.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -83,6 +83,7 @@ IUFillNumber(&ElevationLimitN[0], "minAlt", "Speed", "%%+03f", -90.0, 90.0, 0.0, 0.0); IUFillNumber(&ElevationLimitN[1], "maxAlt", "Speed", "%+03f", -90.0, 90.0, 0.0, 0.0); IUFillNumberVector(&ElevationLimitNP, ElevationLimitN, 1, getDeviceName(), "Slew elevation Limit", "", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); + return true; } void LX200Classic::ISGetProperties (const char *dev) @@ -118,6 +119,7 @@ defineSwitch(&DeepSkyCatalogSP); defineNumber(&ObjectNoNP); defineNumber(&MaxSlewRateNP); + return true; } else { @@ -128,6 +130,7 @@ deleteProperty(DeepSkyCatalogSP.name); deleteProperty(ObjectNoNP.name); deleteProperty(MaxSlewRateNP.name); + return true; } } diff -Nru libindi-1.0.0/drivers/telescope/lx200driver.c libindi-1.1.0/drivers/telescope/lx200driver.c --- libindi-1.0.0/drivers/telescope/lx200driver.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200driver.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1609 +0,0 @@ -#if 0 - LX200 Driver - Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "indicom.h" -#include "indidevapi.h" -#include "lx200driver.h" - -#ifndef _WIN32 -#include -#endif - -#define LX200_TIMEOUT 5 /* FD timeout in seconds */ - -int controller_format; -int lx200_debug = 0; - -/************************************************************************** - Diagnostics - **************************************************************************/ -char ACK(int fd); -/*int testTelescope(void); -int testAP(void);*/ -int check_lx200_connection(int fd); - -/************************************************************************** - Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure - **************************************************************************/ - -/* Get Double from Sexagisemal */ -int getCommandSexa(int fd, double *value, const char *cmd); -/* Get String */ -int getCommandString(int fd, char *data, const char* cmd); -/* Get Int */ -int getCommandInt(int fd, int *value, const char* cmd); -/* Get tracking frequency */ -int getTrackFreq(int fd, double * value); -/* Get site Latitude */ -int getSiteLatitude(int fd, int *dd, int *mm); -/* Get site Longitude */ -int getSiteLongitude(int fd, int *ddd, int *mm); -/* Get Calender data */ -int getCalenderDate(int fd, char *date); -/* Get site Name */ -int getSiteName(int fd, char *siteName, int siteNum); -/* Get Number of Bars */ -int getNumberOfBars(int fd, int *value); -/* Get Home Search Status */ -int getHomeSearchStatus(int fd, int *status); -/* Get OTA Temperature */ -int getOTATemp(int fd, double * value); -/* Get time format: 12 or 24 */ -int getTimeFormat(int fd, int *format); - - -/************************************************************************** - Set Commands - **************************************************************************/ - -/* Set Int */ -int setCommandInt(int fd, int data, const char *cmd); -/* Set Sexigesimal */ -int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); -/* Common routine for Set commands */ -int setStandardProcedure(int fd, const char * writeData); -/* Set Slew Mode */ -int setSlewMode(int fd, int slewMode); -/* Set Alignment mode */ -int setAlignmentMode(int fd, unsigned int alignMode); -/* Set Object RA */ -int setObjectRA(int fd, double ra); -/* set Object DEC */ -int setObjectDEC(int fd, double dec); -/* Set Calender date */ -int setCalenderDate(int fd, int dd, int mm, int yy); -/* Set UTC offset */ -int setUTCOffset(int fd, double hours); -/* Set Track Freq */ -int setTrackFreq(int fd, double trackF); -/* Set current site longitude */ -int setSiteLongitude(int fd, double Long); -/* Set current site latitude */ -int setSiteLatitude(int fd, double Lat); -/* Set Object Azimuth */ -int setObjAz(int fd, double az); -/* Set Object Altitude */ -int setObjAlt(int fd, double alt); -/* Set site name */ -int setSiteName(int fd, char * siteName, int siteNum); -/* Set maximum slew rate */ -int setMaxSlewRate(int fd, int slewRate); -/* Set focuser motion */ -int setFocuserMotion(int fd, int motionType); -/* Set focuser speed mode */ -int setFocuserSpeedMode (int fd, int speedMode); -/* Set minimum elevation limit */ -int setMinElevationLimit(int fd, int min); -/* Set maximum elevation limit */ -int setMaxElevationLimit(int fd, int max); - -/************************************************************************** - Motion Commands - **************************************************************************/ -/* Slew to the selected coordinates */ -int Slew(int fd); -/* Synchronize to the selected coordinates and return the matching object if any */ -int Sync(int fd, char *matchedObject); -/* Abort slew in all axes */ -int abortSlew(int fd); -/* Move into one direction, two valid directions can be stacked */ -int MoveTo(int fd, int direction); -/* Half movement in a particular direction */ -int HaltMovement(int fd, int direction); -/* Select the tracking mode */ -int selectTrackingMode(int fd, int trackMode); -/* Select Astro-Physics tracking mode */ -int selectAPTrackingMode(int fd, int trackMode); -/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */ -int SendPulseCmd(int fd, int direction, int duration_msec); - -/************************************************************************** - Other Commands - **************************************************************************/ - /* Ensures LX200 RA/DEC format is long */ -int checkLX200Format(int fd); -/* Select a site from the LX200 controller */ -int selectSite(int fd, int siteNum); -/* Select a catalog object */ -int selectCatalogObject(int fd, int catalog, int NNNN); -/* Select a sub catalog */ -int selectSubCatalog(int fd, int catalog, int subCatalog); - -void setLX200Debug(int value) -{ - lx200_debug = value; -} - -int check_lx200_connection(int in_fd) -{ - - int i=0; - char ack[1] = { (char) 0x06 }; - char MountAlign[64]; - int nbytes_read=0; - - if (lx200_debug) - IDLog("%s Testing telescope's connection using ACK...\n", __FUNCTION__); - - if (in_fd <= 0) return -1; - - for (i=0; i < 2; i++) - { - if (write(in_fd, ack, 1) < 0) return -1; - tty_read(in_fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); - if (nbytes_read == 1) - return 0; - usleep(50000); - } - - return -1; -} - - -/********************************************************************** -* GET -**********************************************************************/ - -char ACK(int fd) -{ - char ack[1] = { (char) 0x06 }; - char MountAlign[2]; - int nbytes_write=0, nbytes_read=0, error_type; - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, ack); - - nbytes_write = write(fd, ack, 1); - - if (nbytes_write < 0) - return -1; - - error_type = tty_read(fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, MountAlign); - - if (nbytes_read == 1) - return MountAlign[0]; - else - return error_type; -} - -int getCommandSexa(int fd, double *value, const char * cmd) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - tcflush(fd, TCIFLUSH); - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, cmd); - - if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - if (error_type != TTY_OK) - return error_type; - - temp_string[nbytes_read - 1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (f_scansexa(temp_string, value)) - { - if (lx200_debug) - IDLog("%s unable to process response\n", __FUNCTION__); - return -1; - } - - if (lx200_debug) - IDLog("%s Sexa Response <%g>\n", __FUNCTION__, *value); - - tcflush(fd, TCIFLUSH); - return 0; -} - -int getCommandInt(int fd, int *value, const char* cmd) -{ - char temp_string[16]; - float temp_number; - int error_type; - int nbytes_write=0, nbytes_read=0; - - tcflush(fd, TCIFLUSH); - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, cmd); - - if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - if (error_type != TTY_OK) - return error_type; - - temp_string[nbytes_read - 1] = '\0'; - - /* Float */ - if (strchr(temp_string, '.')) - { - if (sscanf(temp_string, "%f", &temp_number) != 1) - return -1; - - *value = (int) temp_number; - } - /* Int */ - else if (sscanf(temp_string, "%d", value) != 1) - return -1; - - if (lx200_debug) - IDLog("%s Response <%d>\n", __FUNCTION__, *value); - - return 0; -} - - -int getCommandString(int fd, char *data, const char* cmd) -{ - char * term; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, cmd); - - if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (error_type != TTY_OK) - return error_type; - - term = strchr (data, '#'); - if (term) - *term = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, data); - - return 0; -} - -int isSlewComplete(int fd) -{ - char data[8]; - int error_type; - int nbytes_write=0, nbytes_read=0; - char *cmd = "#:D#"; - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, cmd); - - if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIOFLUSH); - - if (error_type != TTY_OK) - return error_type; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, data); - - if (data[0] == '#') - return 0; - else - return 1; - -} - -int getCalenderDate(int fd, char *date) -{ - - int dd, mm, yy; - int error_type; - int nbytes_read=0; - char mell_prefix[3]; - - if (lx200_debug) - IDLog("%s Command [#:GC#]\n", __FUNCTION__); - - if ( (error_type = getCommandString(fd, date, "#:GC#")) ) - return error_type; - - /* Meade format is MM/DD/YY */ - nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy); - if (nbytes_read < 3) - return -1; - - /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/ - if (yy > 50) - strncpy(mell_prefix, "19", 3); - else - strncpy(mell_prefix, "20", 3); - - /* We need to have in in YYYY/MM/DD format */ - snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd); - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, date); - - return (0); - -} - -int getTimeFormat(int fd, int *format) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - int tMode; - - if (lx200_debug) - IDLog("%s Command [#:Gc#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:Gc#", &nbytes_write)) != TTY_OK) - return error_type; - - /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ - if ( (error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) - return error_type; - - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - temp_string[nbytes_read-1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - nbytes_read = sscanf(temp_string, "(%d)", &tMode); - - if (nbytes_read < 1) - return -1; - else - *format = tMode; - - return 0; - -} - -int getSiteName(int fd, char *siteName, int siteNum) -{ - char * term; - int error_type; - int nbytes_write=0, nbytes_read=0; - - switch (siteNum) - { - case 1: - if (lx200_debug) - IDLog("%s Command [#:GM#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:GM#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case 2: - if (lx200_debug) - IDLog("%s Command [#:GN#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:GN#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case 3: - if (lx200_debug) - IDLog("%s Command [#:GO#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:GO#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case 4: - if (lx200_debug) - IDLog("%s Command [#:GP#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:GP#", &nbytes_write)) != TTY_OK) - return error_type; - break; - default: - return -1; - } - - error_type = tty_read_section(fd, siteName, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - siteName[nbytes_read - 1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, siteName); - - term = strchr (siteName, ' '); - if (term) - *term = '\0'; - - term = strchr (siteName, '<'); - if (term) - strcpy(siteName, "unused site"); - - if (lx200_debug) - IDLog("%s Final Site Name <%s>\n", __FUNCTION__, siteName); - - return 0; -} - -int getSiteLatitude(int fd, int *dd, int *mm) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:Gt#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:Gt#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - temp_string[nbytes_read -1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2) - { - if (lx200_debug) - IDLog("%s Processing response failed\n", __FUNCTION__); - return -1; - } - - if (lx200_debug) - IDLog("%s Processed response <%d:%d>\n", __FUNCTION__, *dd, *mm); - - return 0; -} - -int getSiteLongitude(int fd, int *ddd, int *mm) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:Gg#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:Gg#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - temp_string[nbytes_read -1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2) - { - if (lx200_debug) - IDLog("%s Processing response failed\n", __FUNCTION__); - - return -1; - } - - if (lx200_debug) - IDLog("%s Processed response <%d:%d>\n", __FUNCTION__, *ddd, *mm); - - return 0; -} - -int getTrackFreq(int fd, double *value) -{ - float Freq; - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:GT#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:GT#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - temp_string[nbytes_read] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (sscanf(temp_string, "%f#", &Freq) < 1) - { - if (lx200_debug) - IDLog("%s Processing response failed\n", __FUNCTION__); - - return -1; - } - - *value = (double) Freq; - - - if (lx200_debug) - IDLog("%s Processed response <%g>\n", __FUNCTION__, *value); - - return 0; -} - -int getNumberOfBars(int fd, int *value) -{ - char temp_string[128]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if ( (error_type = tty_write_string(fd, "#:D#", &nbytes_write)) != TTY_OK) - return error_type; - /*if (portWrite("#:D#") < 0) - return -1;*/ - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 0) - return error_type; - - *value = nbytes_read -1; - - return 0; -} - -int getHomeSearchStatus(int fd, int *status) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:h?#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:h?#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - temp_string[1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (temp_string[0] == '0') - *status = 0; - else if (temp_string[0] == '1') - *status = 1; - else if (temp_string[0] == '2') - *status = 1; - - return 0; -} - -int getOTATemp(int fd, double *value) -{ - - char temp_string[16]; - int error_type; - int nbytes_write=0, nbytes_read=0; - float temp; - - if (lx200_debug) - IDLog("%s Command [#:fT#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:fT#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - - if (nbytes_read < 1) - return error_type; - - temp_string[nbytes_read - 1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - if (sscanf(temp_string, "%f", &temp) < 1) - { - if (lx200_debug) - IDLog("%s Processing response failed\n", __FUNCTION__); - - return -1; - } - - *value = (double) temp; - - if (lx200_debug) - IDLog("%s Processed response <%g>\n", __FUNCTION__, *value); - - return 0; - -} - -int updateSkyCommanderCoord(int fd, double *ra, double *dec) -{ - char coords[16]; - char CR[1] = { (char) 0x0D }; - float RA=0.0, DEC=0.0; - int error_type; - int nbytes_read=0; - - error_type = write(fd, CR, 1); - - error_type = tty_read(fd, coords, 16, LX200_TIMEOUT, &nbytes_read); - /*read_ret = portRead(coords, 16, LX200_TIMEOUT);*/ - tcflush(fd, TCIFLUSH); - - nbytes_read = sscanf(coords, " %g %g", &RA, &DEC); - - if (nbytes_read < 2) - { - #ifdef INDI_DEBUG - IDLog("Error in Sky commander number format [%s], exiting.\n", coords); - #endif - return error_type; - } - - *ra = RA; - *dec = DEC; - - return 0; - -} - -int updateIntelliscopeCoord (int fd, double *ra, double *dec) -{ - char coords[16]; - char CR[1] = { (char) 0x51 }; /* "Q" */ - float RA = 0.0, DEC = 0.0; - int error_type; - int nbytes_read=0; - - /*IDLog ("Sending a Q\n");*/ - error_type = write (fd, CR, 1); - /* We start at 14 bytes in case its a Sky Wizard, - but read one more later it if it's a intelliscope */ - /*read_ret = portRead (coords, 14, LX200_TIMEOUT);*/ - error_type = tty_read(fd, coords, 14, LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - /*IDLog ("portRead() = [%s]\n", coords);*/ - - /* Remove the Q in the response from the Intelliscope but not the Sky Wizard */ - if (coords[0] == 'Q') { - coords[0] = ' '; - /* Read one more byte if Intelliscope to get the "CR" */ - error_type = tty_read(fd, coords, 1, LX200_TIMEOUT, &nbytes_read); - /*read_ret = portRead (coords, 1, LX200_TIMEOUT);*/ - } - nbytes_read = sscanf (coords, " %g %g", &RA, &DEC); - /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/ - /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/ - - /*IDLog ("Intelliscope output [%s]", coords);*/ - if (nbytes_read < 2) - { - #ifdef INDI_DEBUG - IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords); - #endif - return -1; - } - - *ra = RA * 0.0390625; - *dec = DEC * 0.0390625; - - return 0; - -} - - -/********************************************************************** -* SET -**********************************************************************/ - -int setStandardProcedure(int fd, const char * data) -{ - char bool_return[2]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, data); - - if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - return error_type; - - if (bool_return[0] == '0') - { - if (lx200_debug) - IDLog("%s %s Failed.\n", __FUNCTION__, data); - return -1; - } - - if (lx200_debug) - IDLog("%s %s Successful\n", __FUNCTION__, data); - - return 0; - -} - -int setCommandInt(int fd, int data, const char *cmd) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0; - - snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data); - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, temp_string); - - if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) - { - if (lx200_debug) - IDLog("%s %s Failed.\n", __FUNCTION__, temp_string); - - return error_type; - } - - if (lx200_debug) - IDLog("%s %s Successful\n", __FUNCTION__, temp_string); - - return 0; -} - -int setMinElevationLimit(int fd, int min) -{ - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - char temp_string[16]; - - snprintf(temp_string, sizeof( temp_string ), "#:Sh%02d#", min); - - return (setStandardProcedure(fd, temp_string)); -} - -int setMaxElevationLimit(int fd, int max) -{ - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - char temp_string[16]; - - snprintf(temp_string, sizeof( temp_string ), "#:So%02d*#", max); - - return (setStandardProcedure(fd, temp_string)); - -} - -int setMaxSlewRate(int fd, int slewRate) -{ - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - char temp_string[16]; - - if (slewRate < 2 || slewRate > 8) - return -1; - - snprintf(temp_string, sizeof( temp_string ), "#:Sw%d#", slewRate); - - return (setStandardProcedure(fd, temp_string)); - -} - -int setObjectRA(int fd, double ra) -{ - - int h, m, s, frac_m; - char temp_string[16]; - - getSexComponents(ra, &h, &m, &s); - - frac_m = (s / 60.0) * 10.; - - if (controller_format == LX200_LONG_FORMAT) - snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); - else - snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d.%01d#", h, m, frac_m); - - if (lx200_debug) - IDLog("%s Set Object RA String %s\n", __FUNCTION__, temp_string); - - return (setStandardProcedure(fd, temp_string)); -} - - -int setObjectDEC(int fd, double dec) -{ - int d, m, s; - char temp_string[16]; - - getSexComponents(dec, &d, &m, &s); - - switch(controller_format) - { - - case LX200_SHORT_FORMAT: - /* case with negative zero */ - if (!d && dec < 0) - snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d#", d, m); - else - snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d#", d, m); - break; - - case LX200_LONG_FORMAT: - /* case with negative zero */ - if (!d && dec < 0) - snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d:%02d:%02d#", d, m, s); - else - snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d:%02d:%02d#", d, m, s); - break; - } - - if (lx200_debug) - IDLog("%s Set Object DEC String %s\n", __FUNCTION__, temp_string); - - return (setStandardProcedure(fd, temp_string)); - -} - -int setCommandXYZ(int fd, int x, int y, int z, const char *cmd) -{ - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - char temp_string[16]; - - snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z); - - return (setStandardProcedure(fd, temp_string)); -} - -int setAlignmentMode(int fd, unsigned int alignMode) -{ - /*fprintf(stderr , "Set alignment mode %d\n", alignMode);*/ - int error_type; - int nbytes_write=0; - - switch (alignMode) - { - case LX200_ALIGN_POLAR: - if (lx200_debug) - IDLog("%s Command [#:AP#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:AP#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_ALIGN_ALTAZ: - if (lx200_debug) - IDLog("%s Command [#:AA#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:AA#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_ALIGN_LAND: - if (lx200_debug) - IDLog("%s Command [#:AL#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:AL#", &nbytes_write)) != TTY_OK) - return error_type; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; -} - -int setCalenderDate(int fd, int dd, int mm, int yy) -{ - char temp_string[32]; - char dumpPlanetaryUpdateString[64]; - char bool_return[2]; - int error_type; - int nbytes_write=0, nbytes_read=0; - yy = yy % 100; - - snprintf(temp_string, sizeof( temp_string ), "#:SC %02d/%02d/%02d#", mm, dd, yy); - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, temp_string); - - if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); - tcflush(fd, TCIFLUSH); - - if (nbytes_read < 1) - { - if (lx200_debug) - IDLog("%s Error reading response (%d)\n", __FUNCTION__, error_type); - return error_type; - } - - bool_return[1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, bool_return); - - if (bool_return[0] == '0') - return -1; - - /* Read dumped data */ - error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', LX200_TIMEOUT, &nbytes_read); - error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 5, &nbytes_read); - - return 0; -} - -int setUTCOffset(int fd, double hours) -{ - char temp_string[16]; - - snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d#", (int) hours); - - if (lx200_debug) - IDLog("%s UTC string is %s\n", __FUNCTION__, temp_string); - - return (setStandardProcedure(fd, temp_string)); - -} - -int setSiteLongitude(int fd, double Long) -{ - int d, m, s; - char temp_string[32]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - getSexComponents(Long, &d, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:Sg%03d:%02d#", d, m); - - return (setStandardProcedure(fd, temp_string)); -} - -int setSiteLatitude(int fd, double Lat) -{ - int d, m, s; - char temp_string[32]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - getSexComponents(Lat, &d, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:St%+03d:%02d:%02d#", d, m, s); - - return (setStandardProcedure(fd, temp_string)); -} - -int setObjAz(int fd, double az) -{ - int d,m,s; - char temp_string[16]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - getSexComponents(az, &d, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:Sz%03d:%02d#", d, m); - - return (setStandardProcedure(fd, temp_string)); - -} - -int setObjAlt(int fd, double alt) -{ - int d, m, s; - char temp_string[16]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - getSexComponents(alt, &d, &m, &s); - - snprintf(temp_string, sizeof( temp_string ), "#:Sa%+02d*%02d#", d, m); - - return (setStandardProcedure(fd, temp_string)); -} - - -int setSiteName(int fd, char * siteName, int siteNum) -{ - char temp_string[16]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - switch (siteNum) - { - case 1: - snprintf(temp_string, sizeof( temp_string ), "#:SM %s#", siteName); - break; - case 2: - snprintf(temp_string, sizeof( temp_string ), "#:SN %s#", siteName); - break; - case 3: - snprintf(temp_string, sizeof( temp_string ), "#:SO %s#", siteName); - break; - case 4: - snprintf(temp_string, sizeof( temp_string ), "#:SP %s#", siteName); - break; - default: - return -1; - } - - return (setStandardProcedure(fd, temp_string)); -} - -int setSlewMode(int fd, int slewMode) -{ - int error_type; - int nbytes_write=0; - - switch (slewMode) - { - case LX200_SLEW_MAX: - if (lx200_debug) - IDLog("%s Command [#:RS#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:RS#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_SLEW_FIND: - if (lx200_debug) - IDLog("%s Command [#:RM#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:RM#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_SLEW_CENTER: - if (lx200_debug) - IDLog("%s Command [#:RC#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:RC#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_SLEW_GUIDE: - if (lx200_debug) - IDLog("%s Command [#:RG#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:RG#", &nbytes_write)) != TTY_OK) - return error_type; - break; - default: - break; - } - - tcflush(fd, TCIFLUSH); - return 0; - -} - -int setFocuserMotion(int fd, int motionType) -{ - int error_type; - int nbytes_write=0; - - switch (motionType) - { - case LX200_FOCUSIN: - if (lx200_debug) - IDLog("%s Focus In Command [#:F+#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:F+#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_FOCUSOUT: - if (lx200_debug) - IDLog("%s Focus Out Command [#:F-#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:F-#", &nbytes_write)) != TTY_OK) - return error_type; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; -} - -int setFocuserSpeedMode (int fd, int speedMode) -{ - int error_type; - int nbytes_write=0; - - switch (speedMode) - { - case LX200_HALTFOCUS: - if (lx200_debug) - IDLog("%s Halt Focus Command [#:FQ#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_FOCUSSLOW: - if (lx200_debug) - IDLog("%s Focus Slow Command [#:FS#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:FS#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_FOCUSFAST: - if (lx200_debug) - IDLog("%s Focus Fast Command [#:FF#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:FF#", &nbytes_write)) != TTY_OK) - return error_type; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; -} - -int setGPSFocuserSpeed (int fd, int speed) -{ - char speed_str[8]; - int error_type; - int nbytes_write=0; - - if (speed == 0) - { - if (lx200_debug) - IDLog("%s Command [#:FQ#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) - return error_type; - - return 0; - } - - snprintf(speed_str, 8, "#:F%d#", speed); - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, speed_str); - - if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK) - return error_type; - - tcflush(fd, TCIFLUSH); - return 0; -} - -int setTrackFreq(int fd, double trackF) -{ - char temp_string[16]; - - if (lx200_debug) - IDLog("%s\n", __FUNCTION__); - - snprintf(temp_string, sizeof( temp_string ), "#:ST %04.1f#", trackF); - - return (setStandardProcedure(fd, temp_string)); - -} - -/********************************************************************** -* Misc -*********************************************************************/ - -int Slew(int fd) -{ - char slewNum[2]; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Slew Command [#:MS#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:MS#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read(fd, slewNum, 1, LX200_TIMEOUT, &nbytes_read); - - if (nbytes_read < 1) - { - if (lx200_debug) - IDLog("%s Response error (%d)\n", __FUNCTION__, error_type); - return error_type; - } - - /* We don't need to read the string message, just return corresponding error code */ - tcflush(fd, TCIFLUSH); - - if (lx200_debug) - IDLog("%s Response <%c>\n", __FUNCTION__, slewNum[0]); - - if (slewNum[0] == '0') - return 0; - else if (slewNum[0] == '1') - return 1; - else return 2; - -} - -int MoveTo(int fd, int direction) -{ - int nbytes_write=0; - - switch (direction) - { - case LX200_NORTH: - if (lx200_debug) - IDLog("%s Motion Command [#:Mn#]\n", __FUNCTION__); - tty_write_string(fd, "#:Mn#", &nbytes_write); - break; - case LX200_WEST: - if (lx200_debug) - IDLog("%s Motion Command [#:Mw#]\n", __FUNCTION__); - tty_write_string(fd, "#:Mw#", &nbytes_write); - break; - case LX200_EAST: - if (lx200_debug) - IDLog("%s Motion Command [#:Me#]\n", __FUNCTION__); - tty_write_string(fd, "#:Me#", &nbytes_write); - break; - case LX200_SOUTH: - if (lx200_debug) - IDLog("%s Motion Command [#:Ms#]\n", __FUNCTION__); - tty_write_string(fd, "#:Ms#", &nbytes_write); - break; - default: - break; - } - - tcflush(fd, TCIFLUSH); - return 0; -} - -int SendPulseCmd(int fd, int direction, int duration_msec) -{ - int nbytes_write=0; - char cmd[20]; - switch (direction) - { - case LX200_NORTH: sprintf(cmd, "#:Mgn%04d#", duration_msec); break; - case LX200_SOUTH: sprintf(cmd, "#:Mgs%04d#", duration_msec); break; - case LX200_EAST: sprintf(cmd, "#:Mge%04d#", duration_msec); break; - case LX200_WEST: sprintf(cmd, "#:Mgw%04d#", duration_msec); break; - default: return 1; - } - - if (lx200_debug) - IDLog("%s Command [%s]\n", __FUNCTION__, cmd); - - tty_write_string(fd, cmd, &nbytes_write); - - tcflush(fd, TCIFLUSH); - return 0; -} - -int HaltMovement(int fd, int direction) -{ - int error_type; - int nbytes_write=0; - - switch (direction) - { - case LX200_NORTH: - if (lx200_debug) - IDLog("%s Stop Motion Command [#:Qn#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:Qn#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_WEST: - if (lx200_debug) - IDLog("%s Stop Motion Command [#:Qw#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:Qw#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_EAST: - if (lx200_debug) - IDLog("%s Stop Motion Command [#:Qe#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:Qe#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_SOUTH: - if (lx200_debug) - IDLog("%s Stop Motion Command [#:Qs#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:Qs#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_ALL: - if (lx200_debug) - IDLog("%s Stop Motion Command [#:Q#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) - return error_type; - break; - default: - return -1; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; - -} - -int abortSlew(int fd) -{ - int error_type; - int nbytes_write=0; - - if (lx200_debug) - IDLog("%s Command [#:Q#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) - return error_type; - - tcflush(fd, TCIFLUSH); - return 0; -} - -int Sync(int fd, char *matchedObject) -{ - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:CM#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read); - - if (nbytes_read < 1) - return error_type; - - matchedObject[nbytes_read-1] = '\0'; - - if (lx200_debug) - IDLog("%s Matched Object: %s\n", __FUNCTION__, matchedObject); - - /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ - usleep(10000); - tcflush(fd, TCIFLUSH); - - return 0; -} - -int selectSite(int fd, int siteNum) -{ - int error_type; - int nbytes_write=0; - - switch (siteNum) - { - case 1: - if (lx200_debug) - IDLog("%s Command [#:W1#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:W1#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case 2: - if (lx200_debug) - IDLog("%s Motion Command [#:W2#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:W2#", &nbytes_write)) != TTY_OK) - return error_type; - /*if (portWrite("#:W2#") < 0) - return -1;*/ - break; - case 3: - if (lx200_debug) - IDLog("%s Motion Command [#:W3#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:W3#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case 4: - if (lx200_debug) - IDLog("%s Motion Command [#:W4#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:W4#", &nbytes_write)) != TTY_OK) - return error_type; - break; - default: - return -1; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; - -} - -int selectCatalogObject(int fd, int catalog, int NNNN) -{ - char temp_string[16]; - int error_type; - int nbytes_write=0; - - switch (catalog) - { - case LX200_STAR_C: - snprintf(temp_string, sizeof( temp_string ), "#:LS%d#", NNNN); - break; - case LX200_DEEPSKY_C: - snprintf(temp_string, sizeof( temp_string ), "#:LC%d#", NNNN); - break; - case LX200_MESSIER_C: - snprintf(temp_string, sizeof( temp_string ), "#:LM%d#", NNNN); - break; - default: - return -1; - } - - if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) - return error_type; - /*if (portWrite(temp_string) < 0) - return -1;*/ - - tcflush(fd, TCIFLUSH); - return 0; -} - -int selectSubCatalog(int fd, int catalog, int subCatalog) -{ - char temp_string[16]; - switch (catalog) - { - case LX200_STAR_C: - snprintf(temp_string, sizeof( temp_string ), "#:LsD%d#", subCatalog); - break; - case LX200_DEEPSKY_C: - snprintf(temp_string, sizeof( temp_string ), "#:LoD%d#", subCatalog); - break; - case LX200_MESSIER_C: - return 1; - default: - return 0; - } - - return (setStandardProcedure(fd, temp_string)); -} - -int checkLX200Format(int fd) -{ - char temp_string[16]; - controller_format = LX200_LONG_FORMAT; - int error_type; - int nbytes_write=0, nbytes_read=0; - - if (lx200_debug) - IDLog("%s Command [#:GR#]\n", __FUNCTION__); - - if ( (error_type = tty_write_string(fd, "#:GR#", &nbytes_write)) != TTY_OK) - return error_type; - - error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); - - if (nbytes_read < 1) - { - if (lx200_debug) - IDLog("%s Response error (%d)\n", __FUNCTION__, error_type); - return error_type; - } - - temp_string[nbytes_read - 1] = '\0'; - - if (lx200_debug) - IDLog("%s Response <%s>\n", __FUNCTION__, temp_string); - - /* Check whether it's short or long */ - if (temp_string[5] == '.') - { - controller_format = LX200_SHORT_FORMAT; - return 0; - } - else - return 0; -} - -int selectTrackingMode(int fd, int trackMode) -{ - int error_type; - int nbytes_write=0; - - switch (trackMode) - { - case LX200_TRACK_DEFAULT: - if (lx200_debug) - IDLog("%s Sidereal Track Command [#:TQ#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:TQ#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_TRACK_LUNAR: - if (lx200_debug) - IDLog("%s Lunar Track Command [#:TL#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:TL#", &nbytes_write)) != TTY_OK) - return error_type; - break; - case LX200_TRACK_MANUAL: - if (lx200_debug) - IDLog("%s Manual Track Command [#:TM#]\n", __FUNCTION__); - if ( (error_type = tty_write_string(fd, "#:TM#", &nbytes_write)) != TTY_OK) - return error_type; - break; - default: - return -1; - break; - } - - tcflush(fd, TCIFLUSH); - return 0; - -} - diff -Nru libindi-1.0.0/drivers/telescope/lx200driver.cpp libindi-1.1.0/drivers/telescope/lx200driver.cpp --- libindi-1.0.0/drivers/telescope/lx200driver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200driver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,1423 @@ +#if 0 + LX200 Driver + Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) + + 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 + +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "indicom.h" +#include "indidevapi.h" +#include "lx200driver.h" +#include "indilogger.h" + +#ifndef _WIN32 +#include +#endif + +#define LX200_TIMEOUT 5 /* FD timeout in seconds */ + +int controller_format; +char lx200Name[MAXINDIDEVICE]; +unsigned int DBG_SCOPE; + +void setLX200Debug(const char *deviceName, unsigned int debug_level) +{ + strncpy(lx200Name, deviceName, MAXINDIDEVICE); + DBG_SCOPE = debug_level; +} + +/************************************************************************** + Diagnostics + **************************************************************************/ +char ACK(int fd); +int check_lx200_connection(int fd); + +/************************************************************************** + Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure + **************************************************************************/ + +/* Get Double from Sexagisemal */ +int getCommandSexa(int fd, double *value, const char *cmd); +/* Get String */ +int getCommandString(int fd, char *data, const char* cmd); +/* Get Int */ +int getCommandInt(int fd, int *value, const char* cmd); +/* Get tracking frequency */ +int getTrackFreq(int fd, double * value); +/* Get site Latitude */ +int getSiteLatitude(int fd, int *dd, int *mm); +/* Get site Longitude */ +int getSiteLongitude(int fd, int *ddd, int *mm); +/* Get Calender data */ +int getCalenderDate(int fd, char *date); +/* Get site Name */ +int getSiteName(int fd, char *siteName, int siteNum); +/* Get Home Search Status */ +int getHomeSearchStatus(int fd, int *status); +/* Get OTA Temperature */ +int getOTATemp(int fd, double * value); +/* Get time format: 12 or 24 */ +int getTimeFormat(int fd, int *format); + + +/************************************************************************** + Set Commands + **************************************************************************/ + +/* Set Int */ +int setCommandInt(int fd, int data, const char *cmd); +/* Set Sexigesimal */ +int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); +/* Common routine for Set commands */ +int setStandardProcedure(int fd, const char * writeData); +/* Set Slew Mode */ +int setSlewMode(int fd, int slewMode); +/* Set Alignment mode */ +int setAlignmentMode(int fd, unsigned int alignMode); +/* Set Object RA */ +int setObjectRA(int fd, double ra); +/* set Object DEC */ +int setObjectDEC(int fd, double dec); +/* Set Calender date */ +int setCalenderDate(int fd, int dd, int mm, int yy); +/* Set UTC offset */ +int setUTCOffset(int fd, double hours); +/* Set Track Freq */ +int setTrackFreq(int fd, double trackF); +/* Set current site longitude */ +int setSiteLongitude(int fd, double Long); +/* Set current site latitude */ +int setSiteLatitude(int fd, double Lat); +/* Set Object Azimuth */ +int setObjAz(int fd, double az); +/* Set Object Altitude */ +int setObjAlt(int fd, double alt); +/* Set site name */ +int setSiteName(int fd, char * siteName, int siteNum); +/* Set maximum slew rate */ +int setMaxSlewRate(int fd, int slewRate); +/* Set focuser motion */ +int setFocuserMotion(int fd, int motionType); +/* Set focuser speed mode */ +int setFocuserSpeedMode (int fd, int speedMode); +/* Set minimum elevation limit */ +int setMinElevationLimit(int fd, int min); +/* Set maximum elevation limit */ +int setMaxElevationLimit(int fd, int max); + +/************************************************************************** + Motion Commands + **************************************************************************/ +/* Slew to the selected coordinates */ +int Slew(int fd); +/* Synchronize to the selected coordinates and return the matching object if any */ +int Sync(int fd, char *matchedObject); +/* Abort slew in all axes */ +int abortSlew(int fd); +/* Move into one direction, two valid directions can be stacked */ +int MoveTo(int fd, int direction); +/* Half movement in a particular direction */ +int HaltMovement(int fd, int direction); +/* Select the tracking mode */ +int selectTrackingMode(int fd, int trackMode); +/* Select Astro-Physics tracking mode */ +int selectAPTrackingMode(int fd, int trackMode); +/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */ +int SendPulseCmd(int fd, int direction, int duration_msec); + +/************************************************************************** + Other Commands + **************************************************************************/ + /* Ensures LX200 RA/DEC format is long */ +int checkLX200Format(int fd); +/* Select a site from the LX200 controller */ +int selectSite(int fd, int siteNum); +/* Select a catalog object */ +int selectCatalogObject(int fd, int catalog, int NNNN); +/* Select a sub catalog */ +int selectSubCatalog(int fd, int catalog, int subCatalog); + +int check_lx200_connection(int in_fd) +{ + + int i=0; + char ack[1] = { (char) 0x06 }; + char MountAlign[64]; + int nbytes_read=0; + + DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Testing telescope's connection using ACK..."); + + if (in_fd <= 0) return -1; + + for (i=0; i < 2; i++) + { + if (write(in_fd, ack, 1) < 0) return -1; + tty_read(in_fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); + if (nbytes_read == 1) + { + DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Testing successful!"); + return 0; + } + usleep(50000); + } + + DEBUGDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Failure. Telescope is not responding to ACK!"); + return -1; +} + + +/********************************************************************** +* GET +**********************************************************************/ + +char ACK(int fd) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + + char ack[1] = { (char) 0x06 }; + char MountAlign[2]; + int nbytes_write=0, nbytes_read=0, error_type; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%02X>", ack); + + nbytes_write = write(fd, ack, 1); + + if (nbytes_write < 0) + return -1; + + error_type = tty_read(fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", MountAlign[0]); + + if (nbytes_read == 1) + return MountAlign[0]; + else + return error_type; +} + +int getCommandSexa(int fd, double *value, const char * cmd) +{ + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + tcflush(fd, TCIFLUSH); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd); + + if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + if (error_type != TTY_OK) + return error_type; + + temp_string[nbytes_read - 1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", temp_string); + + if (f_scansexa(temp_string, value)) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return -1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value); + + tcflush(fd, TCIFLUSH); + return 0; +} + +int getCommandInt(int fd, int *value, const char* cmd) +{ + char temp_string[16]; + float temp_number; + int error_type; + int nbytes_write=0, nbytes_read=0; + + tcflush(fd, TCIFLUSH); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd); + + if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + if (error_type != TTY_OK) + return error_type; + + temp_string[nbytes_read - 1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", temp_string); + + /* Float */ + if (strchr(temp_string, '.')) + { + if (sscanf(temp_string, "%f", &temp_number) != 1) + return -1; + + *value = (int) temp_number; + } + /* Int */ + else if (sscanf(temp_string, "%d", value) != 1) + return -1; + + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d]", *value); + + return 0; +} + +int getCommandString(int fd, char *data, const char* cmd) +{ + char * term; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd); + + if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (error_type != TTY_OK) + return error_type; + + term = strchr (data, '#'); + if (term) + *term = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", data); + + return 0; +} + +int isSlewComplete(int fd) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char data[8]; + int error_type; + int nbytes_write=0, nbytes_read=0; + const char *cmd = "#:D#"; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd); + + if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIOFLUSH); + + if (error_type != TTY_OK) + return error_type; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", data); + + if (data[0] == '#') + return 0; + else + return 1; + +} + +int getCalenderDate(int fd, char *date) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int dd, mm, yy; + int error_type; + int nbytes_read=0; + char mell_prefix[3]; + + if ( (error_type = getCommandString(fd, date, "#:GC#")) ) + return error_type; + + /* Meade format is MM/DD/YY */ + nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy); + if (nbytes_read < 3) + return -1; + + /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/ + if (yy > 50) + strncpy(mell_prefix, "19", 3); + else + strncpy(mell_prefix, "20", 3); + + /* We need to have in in YYYY/MM/DD format */ + snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd); + + return (0); + +} + +int getTimeFormat(int fd, int *format) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + int tMode; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Gc#"); + + if ( (error_type = tty_write_string(fd, "#:Gc#", &nbytes_write)) != TTY_OK) + return error_type; + + if ( (error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) + return error_type; + + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + temp_string[nbytes_read-1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + nbytes_read = sscanf(temp_string, "(%d)", &tMode); + + if (nbytes_read < 1) + return -1; + else + *format = tMode; + + return 0; + +} + +int getSiteName(int fd, char *siteName, int siteNum) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char * term; + int error_type; + int nbytes_write=0, nbytes_read=0; + + switch (siteNum) + { + case 1: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GM#"); + if ( (error_type = tty_write_string(fd, "#:GM#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 2: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GN#"); + if ( (error_type = tty_write_string(fd, "#:GN#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 3: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GO#"); + if ( (error_type = tty_write_string(fd, "#:GO#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 4: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GP#"); + if ( (error_type = tty_write_string(fd, "#:GP#", &nbytes_write)) != TTY_OK) + return error_type; + break; + default: + return -1; + } + + error_type = tty_read_section(fd, siteName, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + siteName[nbytes_read - 1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", siteName); + + term = strchr (siteName, ' '); + if (term) + *term = '\0'; + + term = strchr (siteName, '<'); + if (term) + strcpy(siteName, "unused site"); + + DEBUGFDEVICE(lx200Name, INDI::Logger::DBG_DEBUG, "Site Name <%s>", siteName); + + return 0; +} + +int getSiteLatitude(int fd, int *dd, int *mm) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Gt#"); + + if ( (error_type = tty_write_string(fd, "#:Gt#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + temp_string[nbytes_read -1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return -1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d,%d]", *dd, *mm); + + return 0; +} + +int getSiteLongitude(int fd, int *ddd, int *mm) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Gg#"); + + if ( (error_type = tty_write_string(fd, "#:Gg#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + temp_string[nbytes_read -1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return -1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d,%d]", *ddd, *mm); + + return 0; +} + +int getTrackFreq(int fd, double *value) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + float Freq; + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GT#"); + + if ( (error_type = tty_write_string(fd, "#:GT#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + temp_string[nbytes_read] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + if (sscanf(temp_string, "%f#", &Freq) < 1) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return -1; + } + + *value = (double) Freq; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value); + + return 0; +} + +int getHomeSearchStatus(int fd, int *status) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:h?#"); + + if ( (error_type = tty_write_string(fd, "#:h?#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + temp_string[1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + if (temp_string[0] == '0') + *status = 0; + else if (temp_string[0] == '1') + *status = 1; + else if (temp_string[0] == '2') + *status = 1; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%d]", *status); + + return 0; +} + +int getOTATemp(int fd, double *value) +{ + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0, nbytes_read=0; + float temp; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:fT#"); + + if ( (error_type = tty_write_string(fd, "#:fT#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + + if (nbytes_read < 1) + return error_type; + + temp_string[nbytes_read - 1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + if (sscanf(temp_string, "%f", &temp) < 1) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return -1; + } + + *value = (double) temp; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "VAL [%g]", *value); + + return 0; + +} + + +/********************************************************************** +* SET +**********************************************************************/ + +int setStandardProcedure(int fd, const char * data) +{ + char bool_return[2]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", data); + + if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + return error_type; + + if (bool_return[0] == '0') + { + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> failed.", data); + return -1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> successful.", data); + + return 0; + +} + +int setCommandInt(int fd, int data, const char *cmd) +{ + char temp_string[16]; + int error_type; + int nbytes_write=0; + + snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", temp_string); + + if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) + { + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> failed.", temp_string); + return error_type; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s> successful.", temp_string); + + return 0; +} + +int setMinElevationLimit(int fd, int min) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + + snprintf(temp_string, sizeof( temp_string ), "#:Sh%02d#", min); + + return (setStandardProcedure(fd, temp_string)); +} + +int setMaxElevationLimit(int fd, int max) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + + char temp_string[16]; + + snprintf(temp_string, sizeof( temp_string ), "#:So%02d*#", max); + + return (setStandardProcedure(fd, temp_string)); + +} + +int setMaxSlewRate(int fd, int slewRate) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + + char temp_string[16]; + + if (slewRate < 2 || slewRate > 8) + return -1; + + snprintf(temp_string, sizeof( temp_string ), "#:Sw%d#", slewRate); + + return (setStandardProcedure(fd, temp_string)); + +} + +int setObjectRA(int fd, double ra) +{ + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + + int h, m, s, frac_m; + char temp_string[16]; + + getSexComponents(ra, &h, &m, &s); + + frac_m = (s / 60.0) * 10.; + + if (controller_format == LX200_LONG_FORMAT) + snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); + else + snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d.%01d#", h, m, frac_m); + + return (setStandardProcedure(fd, temp_string)); +} + + +int setObjectDEC(int fd, double dec) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + + int d, m, s; + char temp_string[16]; + + getSexComponents(dec, &d, &m, &s); + + switch(controller_format) + { + + case LX200_SHORT_FORMAT: + /* case with negative zero */ + if (!d && dec < 0) + snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d#", d, m); + else + snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d#", d, m); + break; + + case LX200_LONG_FORMAT: + /* case with negative zero */ + if (!d && dec < 0) + snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d:%02d:%02d#", d, m, s); + else + snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d:%02d:%02d#", d, m, s); + break; + } + + return (setStandardProcedure(fd, temp_string)); + +} + +int setCommandXYZ(int fd, int x, int y, int z, const char *cmd) +{ + char temp_string[16]; + + snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z); + + return (setStandardProcedure(fd, temp_string)); +} + +int setAlignmentMode(int fd, unsigned int alignMode) +{ + int error_type; + int nbytes_write=0; + + switch (alignMode) + { + case LX200_ALIGN_POLAR: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:AP#"); + if ( (error_type = tty_write_string(fd, "#:AP#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_ALIGN_ALTAZ: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:AA#"); + if ( (error_type = tty_write_string(fd, "#:AA#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_ALIGN_LAND: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:AL#"); + if ( (error_type = tty_write_string(fd, "#:AL#", &nbytes_write)) != TTY_OK) + return error_type; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; +} + +int setCalenderDate(int fd, int dd, int mm, int yy) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[32]; + //char dumpPlanetaryUpdateString[64]; + char bool_return[2]; + int error_type; + int nbytes_write=0, nbytes_read=0; + yy = yy % 100; + + snprintf(temp_string, sizeof( temp_string ), "#:SC %02d/%02d/%02d#", mm, dd, yy); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", temp_string); + + if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); + tcflush(fd, TCIFLUSH); + + if (nbytes_read < 1) + { + DEBUGDEVICE(lx200Name, DBG_SCOPE, "Unable to parse response"); + return error_type; + } + + bool_return[1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", bool_return); + + if (bool_return[0] == '0') + return -1; + + /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ + usleep(10000); + tcflush(fd, TCIFLUSH); + /* Read dumped data */ + //error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 1, &nbytes_read); + //error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 1, &nbytes_read); + + return 0; +} + +int setUTCOffset(int fd, double hours) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + + snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d#", (int) hours); + + return (setStandardProcedure(fd, temp_string)); + +} + +int setSiteLongitude(int fd, double Long) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int d, m, s; + char temp_string[32]; + + getSexComponents(Long, &d, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:Sg%03d:%02d#", d, m); + + return (setStandardProcedure(fd, temp_string)); +} + +int setSiteLatitude(int fd, double Lat) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int d, m, s; + char temp_string[32]; + + getSexComponents(Lat, &d, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:St%+03d:%02d:%02d#", d, m, s); + + return (setStandardProcedure(fd, temp_string)); +} + +int setObjAz(int fd, double az) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int d,m,s; + char temp_string[16]; + + getSexComponents(az, &d, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:Sz%03d:%02d#", d, m); + + return (setStandardProcedure(fd, temp_string)); + +} + +int setObjAlt(int fd, double alt) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int d, m, s; + char temp_string[16]; + + getSexComponents(alt, &d, &m, &s); + + snprintf(temp_string, sizeof( temp_string ), "#:Sa%+02d*%02d#", d, m); + + return (setStandardProcedure(fd, temp_string)); +} + + +int setSiteName(int fd, char * siteName, int siteNum) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + + switch (siteNum) + { + case 1: + snprintf(temp_string, sizeof( temp_string ), "#:SM %s#", siteName); + break; + case 2: + snprintf(temp_string, sizeof( temp_string ), "#:SN %s#", siteName); + break; + case 3: + snprintf(temp_string, sizeof( temp_string ), "#:SO %s#", siteName); + break; + case 4: + snprintf(temp_string, sizeof( temp_string ), "#:SP %s#", siteName); + break; + default: + return -1; + } + + return (setStandardProcedure(fd, temp_string)); +} + +int setSlewMode(int fd, int slewMode) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (slewMode) + { + case LX200_SLEW_MAX: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:RS#"); + if ( (error_type = tty_write_string(fd, "#:RS#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_SLEW_FIND: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:RM#"); + if ( (error_type = tty_write_string(fd, "#:RM#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_SLEW_CENTER: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:RC#"); + if ( (error_type = tty_write_string(fd, "#:RC#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_SLEW_GUIDE: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:RG#"); + if ( (error_type = tty_write_string(fd, "#:RG#", &nbytes_write)) != TTY_OK) + return error_type; + break; + default: + break; + } + + tcflush(fd, TCIFLUSH); + return 0; + +} + +int setFocuserMotion(int fd, int motionType) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (motionType) + { + case LX200_FOCUSIN: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:F+#"); + if ( (error_type = tty_write_string(fd, "#:F+#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_FOCUSOUT: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:F-#"); + if ( (error_type = tty_write_string(fd, "#:F-#", &nbytes_write)) != TTY_OK) + return error_type; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; +} + +int setFocuserSpeedMode (int fd, int speedMode) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (speedMode) + { + case LX200_HALTFOCUS: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:FQ#"); + if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_FOCUSSLOW: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:FS#"); + if ( (error_type = tty_write_string(fd, "#:FS#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_FOCUSFAST: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:FF#"); + if ( (error_type = tty_write_string(fd, "#:FF#", &nbytes_write)) != TTY_OK) + return error_type; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; +} + +int setGPSFocuserSpeed (int fd, int speed) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char speed_str[8]; + int error_type; + int nbytes_write=0; + + if (speed == 0) + { + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:FQ#"); + if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) + return error_type; + + return 0; + } + + snprintf(speed_str, 8, "#:F%d#", speed); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", speed_str); + + if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK) + return error_type; + + tcflush(fd, TCIFLUSH); + return 0; +} + +int setTrackFreq(int fd, double trackF) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + + snprintf(temp_string, sizeof( temp_string ), "#:ST %04.1f#", trackF); + + return (setStandardProcedure(fd, temp_string)); + +} + +/********************************************************************** +* Misc +*********************************************************************/ + +int Slew(int fd) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char slewNum[2]; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:MS#"); + + if ( (error_type = tty_write_string(fd, "#:MS#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read(fd, slewNum, 1, LX200_TIMEOUT, &nbytes_read); + + if (nbytes_read < 1) + { + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES ERROR <%d>", error_type); + return error_type; + } + + /* We don't need to read the string message, just return corresponding error code */ + tcflush(fd, TCIFLUSH); + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%c>", slewNum[0]); + + if (slewNum[0] == '0') + return 0; + else if (slewNum[0] == '1') + return 1; + else return 2; + +} + +int MoveTo(int fd, int direction) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int nbytes_write=0; + + switch (direction) + { + case LX200_NORTH: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Mn#"); + tty_write_string(fd, "#:Mn#", &nbytes_write); + break; + case LX200_WEST: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Mw#"); + tty_write_string(fd, "#:Mw#", &nbytes_write); + break; + case LX200_EAST: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Me#"); + tty_write_string(fd, "#:Me#", &nbytes_write); + break; + case LX200_SOUTH: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Ms#"); + tty_write_string(fd, "#:Ms#", &nbytes_write); + break; + default: + break; + } + + tcflush(fd, TCIFLUSH); + return 0; +} + +int SendPulseCmd(int fd, int direction, int duration_msec) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int nbytes_write=0; + char cmd[20]; + switch (direction) + { + case LX200_NORTH: sprintf(cmd, "#:Mgn%04d#", duration_msec); break; + case LX200_SOUTH: sprintf(cmd, "#:Mgs%04d#", duration_msec); break; + case LX200_EAST: sprintf(cmd, "#:Mge%04d#", duration_msec); break; + case LX200_WEST: sprintf(cmd, "#:Mgw%04d#", duration_msec); break; + default: return 1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", cmd); + + tty_write_string(fd, cmd, &nbytes_write); + + tcflush(fd, TCIFLUSH); + return 0; +} + +int HaltMovement(int fd, int direction) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (direction) + { + case LX200_NORTH: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Qn#"); + if ( (error_type = tty_write_string(fd, "#:Qn#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_WEST: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Qw#"); + if ( (error_type = tty_write_string(fd, "#:Qw#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_EAST: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Qe#"); + if ( (error_type = tty_write_string(fd, "#:Qe#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_SOUTH: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Qs#"); + if ( (error_type = tty_write_string(fd, "#:Qs#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_ALL: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:Q#"); + if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) + return error_type; + break; + default: + return -1; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; + +} + +int abortSlew(int fd) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) + return error_type; + + tcflush(fd, TCIFLUSH); + return 0; +} + +int Sync(int fd, char *matchedObject) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:CM#"); + + if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read); + + if (nbytes_read < 1) + return error_type; + + matchedObject[nbytes_read-1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", matchedObject); + + /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ + usleep(10000); + tcflush(fd, TCIFLUSH); + + return 0; +} + +int selectSite(int fd, int siteNum) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (siteNum) + { + case 1: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:W1#"); + if ( (error_type = tty_write_string(fd, "#:W1#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 2: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:W2#"); + if ( (error_type = tty_write_string(fd, "#:W2#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 3: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:W3#"); + if ( (error_type = tty_write_string(fd, "#:W3#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case 4: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:W4#"); + if ( (error_type = tty_write_string(fd, "#:W4#", &nbytes_write)) != TTY_OK) + return error_type; + break; + default: + return -1; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; + +} + +int selectCatalogObject(int fd, int catalog, int NNNN) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + int error_type; + int nbytes_write=0; + + switch (catalog) + { + case LX200_STAR_C: + snprintf(temp_string, sizeof( temp_string ), "#:LS%d#", NNNN); + break; + case LX200_DEEPSKY_C: + snprintf(temp_string, sizeof( temp_string ), "#:LC%d#", NNNN); + break; + case LX200_MESSIER_C: + snprintf(temp_string, sizeof( temp_string ), "#:LM%d#", NNNN); + break; + default: + return -1; + } + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", temp_string); + + if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) + return error_type; + + tcflush(fd, TCIFLUSH); + return 0; +} + +int selectSubCatalog(int fd, int catalog, int subCatalog) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + char temp_string[16]; + switch (catalog) + { + case LX200_STAR_C: + snprintf(temp_string, sizeof( temp_string ), "#:LsD%d#", subCatalog); + break; + case LX200_DEEPSKY_C: + snprintf(temp_string, sizeof( temp_string ), "#:LoD%d#", subCatalog); + break; + case LX200_MESSIER_C: + return 1; + default: + return 0; + } + + return (setStandardProcedure(fd, temp_string)); +} + +int checkLX200Format(int fd) +{ + char temp_string[16]; + controller_format = LX200_LONG_FORMAT; + int error_type; + int nbytes_write=0, nbytes_read=0; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:GR#"); + + if ( (error_type = tty_write_string(fd, "#:GR#", &nbytes_write)) != TTY_OK) + return error_type; + + error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); + + if (nbytes_read < 1) + { + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES ERROR <%d>", error_type); + return error_type; + } + + temp_string[nbytes_read - 1] = '\0'; + + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "RES <%s>", temp_string); + + /* Check whether it's short or long */ + if (temp_string[5] == '.') + { + controller_format = LX200_SHORT_FORMAT; + return 0; + } + else + return 0; +} + +int selectTrackingMode(int fd, int trackMode) +{ + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "<%s>", __FUNCTION__); + int error_type; + int nbytes_write=0; + + switch (trackMode) + { + case LX200_TRACK_SIDEREAL: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:TQ#"); + if ( (error_type = tty_write_string(fd, "#:TQ#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_TRACK_SOLAR: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:TS#"); + if ( (error_type = tty_write_string(fd, "#:TS#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_TRACK_LUNAR: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:TL#"); + if ( (error_type = tty_write_string(fd, "#:TL#", &nbytes_write)) != TTY_OK) + return error_type; + break; + case LX200_TRACK_MANUAL: + DEBUGFDEVICE(lx200Name, DBG_SCOPE, "CMD <%s>", "#:TM#"); + if ( (error_type = tty_write_string(fd, "#:TM#", &nbytes_write)) != TTY_OK) + return error_type; + break; + default: + return -1; + break; + } + + tcflush(fd, TCIFLUSH); + return 0; + +} diff -Nru libindi-1.0.0/drivers/telescope/lx200driver.h libindi-1.1.0/drivers/telescope/lx200driver.h --- libindi-1.0.0/drivers/telescope/lx200driver.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200driver.h 2015-09-06 13:17:35.000000000 +0000 @@ -41,7 +41,7 @@ /* Deep Sky Catalogs */ enum DeepSkyCatalog { LX200_NGC, LX200_IC, LX200_UGC, LX200_CALDWELL, LX200_ARP, LX200_ABELL, LX200_MESSIER_C}; /* Mount tracking frequency, in Hz */ -enum TFreq { LX200_TRACK_DEFAULT, LX200_TRACK_LUNAR, LX200_TRACK_MANUAL}; +enum TFreq { LX200_TRACK_SIDEREAL, LX200_TRACK_SOLAR, LX200_TRACK_LUNAR, LX200_TRACK_MANUAL}; #define MaxReticleDutyCycle 15 #define MaxFocuserSpeed 4 @@ -108,10 +108,7 @@ #define turnFieldDeRotatorOn(fd) write(fd, "#:r+#", 5) #define turnFieldDeRotatorOff(fd) write(fd, "#:r-#", 5) #define slewToPark(fd) write(fd, "#:hP#", 5) - -#ifdef __cplusplus -extern "C" { -#endif +#define initTelescope(fd) write(fd, "#:I#", 4) /************************************************************************** Basic I/O - OBSELETE @@ -151,8 +148,6 @@ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); -/* Get Number of Bars */ -int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ @@ -228,8 +223,6 @@ int selectTrackingMode(int fd, int trackMode); /* Is Slew complete? 0 if complete, 1 if in progress, otherwise return an error */ int isSlewComplete(int fd); -/* Select Astro-Physics tracking mode */ -int selectAPTrackingMode(int fd, int trackMode); /* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */ int SendPulseCmd(int fd, int direction, int duration_msec); @@ -246,10 +239,6 @@ /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); /* Set Debug */ -void setLX200Debug(int value); - -#ifdef __cplusplus -} -#endif +void setLX200Debug(const char *deviceName, unsigned int debug_level); #endif diff -Nru libindi-1.0.0/drivers/telescope/lx200fs2.cpp libindi-1.1.0/drivers/telescope/lx200fs2.cpp --- libindi-1.0.0/drivers/telescope/lx200fs2.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200fs2.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,6 @@ -#if 0 - LX200 FS2 Driver - Copyright (C) 2009 Ferran Casarramona (ferran.casarramona@gmail.com) - Based on LX200 driver from: - Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) +/* + Astro-Electronic FS-2 Driver + Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,331 +15,262 @@ 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 +*/ -#endif +#include -#include +#include "lx200fs2.h" -/* LX200 Command Set */ -#include "lx200driver.h" +LX200FS2::LX200FS2() : LX200Generic() +{ + setVersion(2, 0); -/* Our driver header */ -#include "lx200fs2.h" + TelescopeCapability cap; + + cap.canPark = true; + cap.canSync = true; + cap.canAbort = true; + cap.hasLocation = true; + cap.hasTime = true; + cap.nSlewRate=4; + SetTelescopeCapability(&cap); +} + +bool LX200FS2::initProperties() +{ + LX200Generic::initProperties(); + + IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), getDeviceName(), "Slew Accuracy", "", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); + + SetParkDataType(PARK_AZ_ALT); + + return true; +} -using namespace std; +bool LX200FS2::updateProperties() +{ + INDI::Telescope::updateProperties(); -/* Our telescope auto pointer */ -extern LX200GenericLegacy *telescope; + if (isConnected()) + { + defineSwitch(&SlewRateSP); + defineNumber(&SlewAccuracyNP); -// Access to properties defined in LX200GenericLegacy -extern ISwitchVectorProperty ConnectSP; -extern ITextVectorProperty PortTP; - -const char *BASIC_GROUP = "Main Control"; // Main Group -const char *OPTIONS_GROUP = "Options"; // Options Group -const char *MOTION_GROUP = "Motion Control"; - -/* Handy Macros */ -#define currentRA EquatorialCoordsRN[0].value -#define currentDEC EquatorialCoordsRN[1].value - -static void retryConnection(void *); - -void changeLX200FS2DeviceName(const char *newName) -{ - -} - -/************************************************************************************** -** LX200 FS2 constructor -***************************************************************************************/ -LX200Fs2::LX200Fs2() : LX200GenericLegacy() -{ - DeviceName = "LX200 FS2"; - init_properties(); - - IDLog("Initializing from LX200 FS2 device...\n"); - IDLog("Driver Version: 2012-07-22\n"); - - //enableSimulation(true); -} - -/************************************************************************************** -** -***************************************************************************************/ -LX200Fs2::~LX200Fs2() -{ - -} - -/************************************************************************************** -** Initialize all properties & set default values. -***************************************************************************************/ -void LX200Fs2::init_properties() -{ - // Firmware Version - IUFillNumber(&FirmwareVerN[0], "FirmwareVer", "Firmware version", "%2.2f", 1.16, 1.25, 0.01, 1.18); - IUFillNumberVector(&FirmwareVerNP, FirmwareVerN, NARRAY(FirmwareVerN), DeviceName, "FIRMWARE_VER" , "Firmware", BASIC_GROUP, IP_RW, 0, IPS_IDLE); -} - -/************************************************************************************** -** Define LX200 FS2 properties to clients. -***************************************************************************************/ -void LX200Fs2::ISGetProperties(const char *dev) -{ - - if (dev && strcmp (DeviceName, dev)) - return; - - LX200GenericLegacy::ISGetProperties(dev); - // Delete not supported properties - IDDelete(DeviceName, "Alignment", NULL); - IDDelete(DeviceName, "Tracking Mode", NULL); - IDDelete(DeviceName, "Tracking Frequency", NULL); - // Focus - IDDelete(DeviceName, "FOCUS_MOTION", NULL); - IDDelete(DeviceName, "FOCUS_TIMER", NULL); - IDDelete(DeviceName, "FOCUS_MODE", NULL); - // Time - IDDelete(DeviceName, "TIME_UTC", NULL); - IDDelete(DeviceName, "TIME_UTC_OFFSET", NULL); - IDDelete(DeviceName, "TIME_LST", NULL); - // Sites - IDDelete(DeviceName, "Sites", NULL); - IDDelete(DeviceName, "Site Name", NULL); - - IDDefNumber(&FirmwareVerNP, NULL); -} - -/************************************************************************************** -** -***************************************************************************************/ -void LX200Fs2::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - - // Ignore if not ours - if (strcmp (dev, DeviceName)) - return; - - // =================================== - // Update Firmware version - // =================================== - if (!strcmp (name, FirmwareVerNP.name)) - { - if (IUUpdateNumber(&FirmwareVerNP, values, names, n) < 0) - return; - - FirmwareVerNP.s = IPS_OK; - - IDSetNumber(&FirmwareVerNP, NULL); - return; - } - - LX200GenericLegacy::ISNewNumber (dev, name, values, names, n); -} - -/************************************************************************************** -** -***************************************************************************************/ -int LX200Fs2::check_fs2_connection(int fd) -{ - double x; - - if (FirmwareVerNP.np[0].value < 1.19) - { - getLX200RA(fd, &x); - return getLX200DEC(fd, &x); // Version 1.18 and below don't support ACK command - } - else - return check_lx200_connection(fd); -} - -/************************************************************************************** -** -***************************************************************************************/ -void LX200Fs2::connectTelescope() -{ - switch (ConnectSP.sp[0].s) - { - case ISS_ON: - - fprintf (stderr, "Trace: LX200FS2 connectTelescope ON"); - if (simulation) - { - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Simulated telescope is online."); - return; - } - - if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) - { - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortTP.tp[0].text); - return; - } - - if (check_fs2_connection(fd)) - { - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); - return; - } - - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); - getBasicData(); - break; - - case ISS_OFF: - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - ConnectSP.s = IPS_IDLE; - if (simulation) - { - IDSetSwitch (&ConnectSP, "Simulated Telescope is offline."); - return; - } - IDSetSwitch (&ConnectSP, "Telescope is offline."); - IDLog("Telescope is offline."); - - tty_disconnect(fd); - break; + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(0); + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); + SetAxis1ParkDefault(0); + SetAxis2ParkDefault(LocationN[LOCATION_LATITUDE].value); + } + + } + else + { + deleteProperty(SlewRateSP.name); + deleteProperty(SlewAccuracyNP.name); } } -/************************************************************************************** -** -***************************************************************************************/ -void LX200Fs2::getBasicData() -{ - //LX200GenericLegacy::getBasicData() - // Make sure short - //checkLX200Format(fd); - - // Get current RA/DEC - //getLX200RA(fd, ¤tRA); - //getLX200DEC(fd, ¤tDEC); - - //IDSetNumber (&EquatorialCoordsRNP, NULL); -} - -/********************************************************************************** -** handleError functions. Redefined because they call check_lx200_connection and this -** driver needs to call check_fs2_connection -**************************************************************************************/ -static void retryConnection(void * p) -{ - int fd = *((int *) p); - - if (((LX200Fs2 *)telescope)->check_fs2_connection(fd)) - { - ConnectSP.s = IPS_IDLE; - IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); - return; - } - - ConnectSP.sp[0].s = ISS_ON; - ConnectSP.sp[1].s = ISS_OFF; - ConnectSP.s = IPS_OK; - - IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); -} - -void LX200Fs2::handleError(ISwitchVectorProperty *svp, int err, const char *msg) -{ - - svp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_fs2_connection(fd)) +bool LX200FS2::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) { - /* The telescope is off locally */ - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetSwitch(svp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; + if (!strcmp(name, SlewAccuracyNP.name)) + { + if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) + return false; + + SlewAccuracyNP.s = IPS_OK; + + if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) + IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); + + IDSetNumber(&SlewAccuracyNP, NULL); + return true; + } } - - /* If the error is a time out, then the device doesn't support this property or busy*/ - if (err == -2) - { - svp->s = IPS_ALERT; - IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - else - /* Changing property failed, user should retry. */ - IDSetSwitch( svp , "%s failed.", msg); - - fault = true; -} - -void LX200Fs2::handleError(INumberVectorProperty *nvp, int err, const char *msg) -{ - - nvp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_fs2_connection(fd)) + + return LX200Generic::ISNewNumber(dev, name, values, names, n); +} + + +const char * LX200FS2::getDefaultName() +{ + return (char *)"Astro-Electronic FS-2"; +} + + +bool LX200FS2::isSlewComplete() +{ + const double dx = targetRA - currentRA; + const double dy = targetDEC - currentDEC; + return fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0); +} + +bool LX200FS2::checkConnection() +{ + return true; +} + +bool LX200FS2::saveConfigItems(FILE *fp) +{ + INDI::Telescope::saveConfigItems(fp); + + IUSaveConfigNumber(fp, &SlewAccuracyNP); + + return true; +} + +bool LX200FS2::updateLocation(double latitude, double longitude, double elevation) +{ + INDI_UNUSED(elevation); + INDI_UNUSED(longitude); + INDI_UNUSED(latitude); + return true; +} + +bool LX200FS2::updateTime(ln_date *utc, double utc_offset) +{ + INDI_UNUSED(utc); + INDI_UNUSED(utc_offset); + return true; +} + +bool LX200FS2::Park() +{ + double parkAZ = GetAxis1Park(); + double parkAlt = GetAxis2Park(); + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Parking to Az (%s) Alt (%s)...", AzStr, AltStr); + + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = parkAZ + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = parkAlt; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + char RAStr[16], DEStr[16]; + fs_sexa(RAStr, equatorialPos.ra/15.0, 2, 3600); + fs_sexa(DEStr, equatorialPos.dec, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Parking to RA (%s) DEC (%s)...", RAStr, DEStr); + + if (Goto(equatorialPos.ra/15.0, equatorialPos.dec)) { - /* The telescope is off locally */ - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetNumber(nvp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; + TrackState = SCOPE_PARKING; + DEBUG(INDI::Logger::DBG_SESSION, "Parking is in progress..."); + + return true; } - - /* If the error is a time out, then the device doesn't support this property */ - if (err == -2) - { - nvp->s = IPS_ALERT; - IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - else - /* Changing property failed, user should retry. */ - IDSetNumber( nvp , "%s failed.", msg); - - fault = true; -} - -void LX200Fs2::handleError(ITextVectorProperty *tvp, int err, const char *msg) -{ - - tvp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_fs2_connection(fd)) + else + return false; +} + +bool LX200FS2::UnPark() +{ + double parkAZ = GetAxis1Park(); + double parkAlt = GetAxis2Park(); + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Unparking from Az (%s) Alt (%s)...", AzStr, AltStr); + + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + horizontalPos.az = parkAZ + 180; + if (horizontalPos.az >= 360) + horizontalPos.az -= 360; + horizontalPos.alt = parkAlt; + + ln_lnlat_posn observer; + + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + + ln_get_equ_from_hrz(&horizontalPos, &observer, ln_get_julian_from_sys(), &equatorialPos); + + char RAStr[16], DEStr[16]; + fs_sexa(RAStr, equatorialPos.ra/15.0, 2, 3600); + fs_sexa(DEStr, equatorialPos.dec, 2, 3600); + DEBUGF(INDI::Logger::DBG_DEBUG, "Syncing to parked coordinates RA (%s) DEC (%s)...", RAStr, DEStr); + + if (Sync(equatorialPos.ra/15.0, equatorialPos.dec)) { - /* The telescope is off locally */ - ConnectSP.sp[0].s = ISS_OFF; - ConnectSP.sp[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetText(tvp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; + SetParked(false); + return true; } - - /* If the error is a time out, then the device doesn't support this property */ - if (err == -2) - { - tvp->s = IPS_ALERT; - IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - - else - /* Changing property failed, user should retry. */ - IDSetText( tvp , "%s failed.", msg); - - fault = true; + else + return false; + +} + +void LX200FS2::SetCurrentPark() +{ + ln_hrz_posn horizontalPos; + // Libnova south = 0, west = 90, north = 180, east = 270 + + ln_lnlat_posn observer; + observer.lat = LocationN[LOCATION_LATITUDE].value; + observer.lng = LocationN[LOCATION_LONGITUDE].value; + if (observer.lng > 180) + observer.lng -= 360; + + ln_equ_posn equatorialPos; + equatorialPos.ra = currentRA * 15; + equatorialPos.dec = currentDEC; + ln_get_hrz_from_equ(&equatorialPos, &observer, ln_get_julian_from_sys(), &horizontalPos); + + double parkAZ = horizontalPos.az - 180; + if (parkAZ < 0) + parkAZ += 360; + double parkAlt = horizontalPos.alt; + + char AzStr[16], AltStr[16]; + fs_sexa(AzStr, parkAZ, 2, 3600); + fs_sexa(AltStr, parkAlt, 2, 3600); + + DEBUGF(INDI::Logger::DBG_DEBUG, "Setting current parking position to coordinates Az (%s) Alt (%s)...", AzStr, AltStr); + + SetAxis1Park(parkAZ); + SetAxis2Park(parkAlt); +} + +void LX200FS2::SetDefaultPark() +{ + // By defualt azimuth 0 + SetAxis1Park(0); + + // Altitude = latitude of observer + SetAxis2Park(LocationN[LOCATION_LATITUDE].value); } diff -Nru libindi-1.0.0/drivers/telescope/lx200fs2.h libindi-1.1.0/drivers/telescope/lx200fs2.h --- libindi-1.0.0/drivers/telescope/lx200fs2.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200fs2.h 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,6 @@ -/* - LX200 FS2 Driver - Copyright (C) 2009 Ferran Casarramona (ferran.casarramona@gmail.com) - Based on LX200 Basic driver from: - Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) +/* + Astro-Electronic FS-2 + Copyright (C) 2015 Jasem Mutlaq (mutlaqja@ikarustech.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,57 +15,46 @@ 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 - */ #ifndef LX200FS2_H #define LX200FS2_H -//#include "indidevapi.h" -//#include "indicom.h" - -#include "lx200genericlegacy.h" -// To prevent of using mydev from generic by error -#ifdef mydev -#undef mydevice -#endif +#include "lx200generic.h" -class LX200Fs2 : public LX200GenericLegacy +class LX200FS2 : public LX200Generic { - public: - LX200Fs2(); - ~LX200Fs2(); - - virtual void ISGetProperties (const char *dev); - virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - // Not implemented. LX200 generic used. - //virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - //virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - //virtual void ISPoll (); - virtual void handleError(ISwitchVectorProperty *svp, int err, const char *msg); - virtual void handleError(INumberVectorProperty *nvp, int err, const char *msg); - virtual void handleError(ITextVectorProperty *tvp, int err, const char *msg); - int check_fs2_connection(int fd); // Added to support firmware versions below 1.19 - - protected: - - const char *DeviceName; - /* Numbers */ - INumber FirmwareVerN[1]; // Firmware version - - /* Number Vectors */ - INumberVectorProperty FirmwareVerNP; - - //*******************************************************/ - /* Connection Routines - ********************************************************/ - void init_properties(); - void getBasicData(); - virtual void connectTelescope(); - bool is_connected(void); +public: + + LX200FS2(); + ~LX200FS2() {} + + virtual bool initProperties(); + virtual bool updateProperties(); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + +protected: + + virtual const char *getDefaultName(); + virtual bool isSlewComplete(); + virtual bool checkConnection(); + + virtual bool saveConfigItems(FILE *fp); + + // Time and Location + virtual bool updateLocation(double latitude, double longitude, double elevation); + virtual bool updateTime(ln_date *utc, double utc_offset); + + // Parking + virtual bool Park(); + virtual bool UnPark(); + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); + + INumber SlewAccuracyN[2]; + INumberVectorProperty SlewAccuracyNP; }; -void changeLX200FS2DeviceName(const char *newName); #endif diff -Nru libindi-1.0.0/drivers/telescope/lx200gemini.cpp libindi-1.1.0/drivers/telescope/lx200gemini.cpp --- libindi-1.0.0/drivers/telescope/lx200gemini.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200gemini.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,73 @@ +#include +#include "lx200gemini.h" + +LX200Gemini::LX200Gemini() +{ + setVersion(1, 0); + + IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); + IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), getDeviceName(), "Slew Accuracy", "", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); +} + +bool LX200Gemini::updateProperties() +{ + LX200Generic::updateProperties(); + + if (isConnected()) + { + defineNumber(&SlewAccuracyNP); + + // Delete unsupported properties + deleteProperty(AlignmentSP.name); + } + else + { + deleteProperty(SlewAccuracyNP.name); + } +} + +bool LX200Gemini::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) + { + if (!strcmp(name, SlewAccuracyNP.name)) + { + if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) + return false; + + SlewAccuracyNP.s = IPS_OK; + + if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) + IDSetNumber(&SlewAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); + + IDSetNumber(&SlewAccuracyNP, NULL); + return true; + } + } + + return LX200Generic::ISNewNumber(dev, name, values, names, n); +} + + +const char * LX200Gemini::getDefaultName() +{ + return (char *)"Losmandy Gemini"; +} + + +bool LX200Gemini::isSlewComplete() +{ + const double dx = targetRA - currentRA; + const double dy = targetDEC - currentDEC; + return fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0); +} + +bool LX200Gemini::saveConfigItems(FILE *fp) +{ + INDI::Telescope::saveConfigItems(fp); + + IUSaveConfigNumber(fp, &SlewAccuracyNP); + + return true; +} diff -Nru libindi-1.0.0/drivers/telescope/lx200gemini.h libindi-1.1.0/drivers/telescope/lx200gemini.h --- libindi-1.0.0/drivers/telescope/lx200gemini.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200gemini.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,50 @@ +/* + Losmandy Gemini INDI driver + + Copyright (C) 2014 Sean Houghton + + Basic LX200 command set with tweaks to support Gemini + + 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 +*/ + +#ifndef LX200GEMINI_H +#define LX200GEMINI_H + +#include "lx200generic.h" + +class LX200Gemini : public LX200Generic +{ +public: + + LX200Gemini(); + ~LX200Gemini() {} + + virtual bool updateProperties(); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + +protected: + + virtual const char *getDefaultName(); + virtual bool isSlewComplete(); + + virtual bool saveConfigItems(FILE *fp); + + INumber SlewAccuracyN[2]; + INumberVectorProperty SlewAccuracyNP; + +}; + +#endif diff -Nru libindi-1.0.0/drivers/telescope/lx200generic.cpp libindi-1.1.0/drivers/telescope/lx200generic.cpp --- libindi-1.0.0/drivers/telescope/lx200generic.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200generic.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -39,6 +39,8 @@ #include "lx200_16.h" #include "lx200classic.h" #include "lx200ap.h" +#include "lx200gemini.h" +#include "lx200fs2.h" // We declare an auto pointer to LX200Generic. std::auto_ptr telescope(0); @@ -107,6 +109,20 @@ if(telescope.get() == 0) telescope.reset(new LX200AstroPhysics()); } + else if (strstr(me, "indi_lx200gemini")) + { + IDLog("initializing from Losmandy Gemini device...\n"); + + if(telescope.get() == 0) telescope.reset(new LX200Gemini()); + + } + else if (strstr(me, "indi_lx200fs2")) + { + IDLog("initializing from Astro-Electronic FS-2...\n"); + + if(telescope.get() == 0) telescope.reset(new LX200FS2()); + + } // be nice and give them a generic device else if(telescope.get() == 0) telescope.reset(new LX200Generic()); @@ -163,32 +179,37 @@ setVersion(2, 0); currentSiteNum = 1; - trackingMode = LX200_TRACK_DEFAULT; + trackingMode = LX200_TRACK_SIDEREAL; GuideNSTID = 0; GuideWETID = 0; - controller = new INDI::Controller(this); - controller->setJoystickCallback(joystickHelper); - controller->setButtonCallback(buttonHelper); + DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); + + currentRA=ln_get_apparent_sidereal_time(ln_get_julian_from_sys()); + currentDEC=90; TelescopeCapability cap; cap.canPark = true; cap.canSync = true; cap.canAbort = true; + cap.hasTime = true; + cap.hasLocation = true; + cap.nSlewRate=4; SetTelescopeCapability(&cap); - IDLog("Initializing from generic LX200 device...\n"); + DEBUG(INDI::Logger::DBG_DEBUG, "Initializing from Generic LX200 device..."); } LX200Generic::~LX200Generic() { - delete(controller); + } void LX200Generic::debugTriggered(bool enable) { - setLX200Debug(enable ? 1 : 0); + INDI_UNUSED(enable); + setLX200Debug(getDeviceName(), DBG_SCOPE); } const char * LX200Generic::getDefaultName() @@ -206,16 +227,17 @@ IUFillSwitch(&AlignmentS[2], "Land", "", ISS_OFF); IUFillSwitchVector(&AlignmentSP, AlignmentS, 3, getDeviceName(), "Alignment", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - IUFillSwitch(&SlewModeS[0], "Max", "", ISS_ON); - IUFillSwitch(&SlewModeS[1], "Find", "", ISS_OFF); - IUFillSwitch(&SlewModeS[2], "Centering", "", ISS_OFF); - IUFillSwitch(&SlewModeS[3], "Guide", "", ISS_OFF); - IUFillSwitchVector(&SlewModeSP, SlewModeS, 4, getDeviceName(), "Slew Rate", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - IUFillSwitch(&TrackModeS[0], "Default", "", ISS_ON); - IUFillSwitch(&TrackModeS[1], "Lunar", "", ISS_OFF); - IUFillSwitch(&TrackModeS[2], "Manual", "", ISS_OFF); - IUFillSwitchVector(&TrackModeSP, TrackModeS, 3, getDeviceName(), "Tracking Mode", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + IUFillSwitch(&SlewRateS[SLEW_GUIDE], "SLEW_GUIDE", "Guide", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_CENTERING], "SLEW_CENTERING", "Centering", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_FIND], "SLEW_FIND", "Find", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_MAX], "SLEW_MAX", "Max", ISS_ON); + IUFillSwitchVector(&SlewRateSP, SlewRateS, 4, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + IUFillSwitch(&TrackModeS[0], "TRACK_SIDEREAL", "Sidereal", ISS_ON); + IUFillSwitch(&TrackModeS[1], "TRACK_SOLAR", "Solar", ISS_OFF); + IUFillSwitch(&TrackModeS[2], "TRACK_LUNAR", "Lunar", ISS_OFF); + IUFillSwitch(&TrackModeS[3], "TRACK_CUSTOM", "Custom", ISS_OFF); + IUFillSwitchVector(&TrackModeSP, TrackModeS, 4, getDeviceName(), "TELESCOPE_TRACK_RATE", "Tracking Mode", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&TrackFreqN[0], "trackFreq", "Freq", "%g", 56.4,60.1, 0.1, 60.1); IUFillNumberVector(&TrackingFreqNP, TrackFreqN, 1, getDeviceName(), "Tracking Frequency", "", MOTION_TAB, IP_RW, 0, IPS_IDLE); @@ -233,7 +255,6 @@ IUFillText(&SiteNameT[0], "Name", "", ""); IUFillTextVector(&SiteNameTP, SiteNameT, 1, getDeviceName(), "Site Name", "", SITE_TAB, IP_RW, 0, IPS_IDLE); - IUFillSwitch(&FocusMotionS[0], "IN", "Focus in", ISS_OFF); IUFillSwitch(&FocusMotionS[1], "OUT", "Focus out", ISS_OFF); IUFillSwitchVector(&FocusMotionSP, FocusMotionS, 2, getDeviceName(), "FOCUS_MOTION", "Motion", FOCUS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); @@ -246,15 +267,6 @@ IUFillSwitch(&FocusModeS[2], "FOCUS_FAST", "Fast", ISS_OFF); IUFillSwitchVector(&FocusModeSP, FocusModeS, 3, getDeviceName(), "FOCUS_MODE", "Mode", FOCUS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - controller->mapController("NSWE Control", "NSWE Control", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1"); - controller->mapController("Slew Max", "Slew Max", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); - controller->mapController("Slew Find", "Slew Find", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); - controller->mapController("Slew Centering", "Slew Centering", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); - controller->mapController("Slew Guide", "Slew Guide", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_4"); - controller->mapController("Abort Motion", "Abort Motion", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_5"); - - controller->initProperties(); - TrackState=SCOPE_IDLE; initGuiderProperties(getDeviceName(), GUIDE_TAB); @@ -277,7 +289,6 @@ if (isConnected()) { defineSwitch(&AlignmentSP); - defineSwitch(&SlewModeSP); defineSwitch(&TrackModeSP); defineNumber(&TrackingFreqNP); defineSwitch(&UsePulseCmdSP); @@ -293,8 +304,6 @@ defineSwitch(&FocusModeSP); } - controller->ISGetProperties(dev); - } bool LX200Generic::updateProperties() @@ -304,7 +313,6 @@ if (isConnected()) { defineSwitch(&AlignmentSP); - defineSwitch(&SlewModeSP); defineSwitch(&TrackModeSP); defineNumber(&TrackingFreqNP); defineSwitch(&UsePulseCmdSP); @@ -321,12 +329,11 @@ getBasicData(); - loadConfig(true); + //loadConfig(true); } else { deleteProperty(AlignmentSP.name); - deleteProperty(SlewModeSP.name); deleteProperty(TrackModeSP.name); deleteProperty(TrackingFreqNP.name); deleteProperty(UsePulseCmdSP.name); @@ -342,8 +349,6 @@ deleteProperty(FocusModeSP.name); } - controller->updateProperties(); - return true; } @@ -353,7 +358,7 @@ if(isConnected()) return true; - rc=Connect(PortT[0].text); + rc=Connect(PortT[0].text, atoi(IUFindOnSwitch(&BaudRateSP)->name)); if(rc) SetTimer(POLLMS); @@ -361,22 +366,27 @@ return rc; } -bool LX200Generic::Connect(char *port) +bool LX200Generic::checkConnection() +{ + return (check_lx200_connection(PortFD) == 0); +} + +bool LX200Generic::Connect(const char *port, uint16_t baud) { if (isSimulation()) { - IDMessage (getDeviceName(), "Simulated LX200 is online. Retrieving basic data..."); + DEBUGF (INDI::Logger::DBG_SESSION, "Simulated %s is online.", getDeviceName()); return true; } - if (tty_connect(port, 9600, 8, 0, 1, &PortFD) != TTY_OK) + if (tty_connect(port, baud, 8, 0, 1, &PortFD) != TTY_OK) { DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); return false; } - if (check_lx200_connection(PortFD)) + if (checkConnection() == false) { DEBUG(INDI::Logger::DBG_ERROR, "Error connecting to Telescope. Telescope is offline."); return false; @@ -384,7 +394,7 @@ //*((int *) UTCOffsetN[0].aux0) = 0; - IDMessage (getDeviceName(), "Telescope is online. Retrieving basic data..."); + DEBUGF (INDI::Logger::DBG_SESSION, "%s is online. Retrieving basic data...", getDeviceName()); return true; } @@ -396,6 +406,11 @@ return true; } +bool LX200Generic::isSlewComplete() +{ + return ::isSlewComplete(PortFD); +} + bool LX200Generic::ReadScopeStatus() { if (isConnected() == false) @@ -413,12 +428,12 @@ if (TrackState == SCOPE_SLEWING) { // Check if LX200 is done slewing - if(isSlewComplete(PortFD) == 0) + if (isSlewComplete()) { // Set slew mode to "Centering" - IUResetSwitch(&SlewModeSP); - SlewModeS[2].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + IUResetSwitch(&SlewRateSP); + SlewRateS[SLEW_CENTERING].s = ISS_ON; + IDSetSwitch(&SlewRateSP, NULL); TrackState=SCOPE_TRACKING; IDMessage(getDeviceName(),"Slew is complete. Tracking..."); @@ -427,12 +442,9 @@ } else if(TrackState == SCOPE_PARKING) { - if(isSlewComplete(PortFD) == 0) + if(isSlewComplete()) { - TrackState=SCOPE_PARKED; - ParkSP.s=IPS_OK; - IDSetSwitch(&ParkSP,NULL); - IDMessage(getDeviceName(),"Telescope is Parked."); + SetParked(true); } } @@ -450,6 +462,7 @@ bool LX200Generic::Goto(double r,double d) { + targetRA=r; targetDEC=d; char RAStr[64], DecStr[64]; @@ -506,7 +519,6 @@ } } - //Parked=false; TrackState = SCOPE_SLEWING; EqNP.s = IPS_BUSY; @@ -518,7 +530,6 @@ { char syncString[256]; - if (isSimulation() == false && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0)) { @@ -537,10 +548,7 @@ currentRA = ra; currentDEC = dec; - if (isDebug()) - IDLog("Synchronization successful %s\n", syncString); - - IDMessage(getDeviceName(), "Synchronization successful."); + DEBUG(INDI::Logger::DBG_SESSION, "Synchronization successful."); TrackState = SCOPE_IDLE; EqNP.s = IPS_OK; @@ -593,16 +601,15 @@ } - ParkSP.s = IPS_OK; - //Parked=true; + ParkSP.s = IPS_BUSY; TrackState = SCOPE_PARKING; IDMessage(getDeviceName(), "Parking telescope in progress..."); return true; } -bool LX200Generic::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool LX200Generic::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { - int current_move = (dir == MOTION_NORTH) ? LX200_NORTH : LX200_SOUTH; + int current_move = (dir == DIRECTION_NORTH) ? LX200_NORTH : LX200_SOUTH; switch (command) { @@ -630,10 +637,9 @@ return true; } -bool LX200Generic::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool LX200Generic::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { - - int current_move = (dir == MOTION_WEST) ? LX200_WEST : LX200_EAST; + int current_move = (dir == DIRECTION_WEST) ? LX200_WEST : LX200_EAST; switch (command) { @@ -705,9 +711,13 @@ IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); IDSetNumber(&EqNP, NULL); - IUResetSwitch(&ParkSP); - ParkSP.s = IPS_IDLE; - IDSetSwitch(&ParkSP, NULL); + + if (capability.canPark) + { + IUResetSwitch(&ParkSP); + ParkSP.s = IPS_IDLE; + IDSetSwitch(&ParkSP, NULL); + } IDMessage(getDeviceName(), "Slew aborted."); return true; @@ -801,8 +811,6 @@ } - controller->ISNewText(dev, name, texts, names, n); - return INDI::Telescope::ISNewText(dev, name, texts, names, n); } @@ -832,7 +840,8 @@ trackingMode = LX200_TRACK_MANUAL; TrackModeS[0].s = ISS_OFF; TrackModeS[1].s = ISS_OFF; - TrackModeS[2].s = ISS_ON; + TrackModeS[2].s = ISS_OFF; + TrackModeS[3].s = ISS_ON; TrackModeSP.s = IPS_OK; selectTrackingMode(PortFD, trackingMode); IDSetSwitch(&TrackModeSP, NULL); @@ -975,28 +984,7 @@ FocusMotionSP.s = IPS_OK; IDSetSwitch(&FocusMotionSP, NULL); return true; - } - - // Slew mode - if (!strcmp (name, SlewModeSP.name)) - { - - if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) - return false; - - index = IUFindOnSwitchIndex(&SlewModeSP); - - if (isSimulation() == false && setSlewMode(PortFD, index) < 0) - { - SlewModeSP.s = IPS_ALERT; - IDSetSwitch(&SlewModeSP, "Error setting slew mode."); - return false; - } - - SlewModeSP.s = IPS_OK; - IDSetSwitch(&SlewModeSP, NULL); - return true; - } + } // Tracking mode if (!strcmp (name, TrackModeSP.name)) @@ -1059,13 +1047,28 @@ } - controller->ISNewSwitch(dev, name, states, names, n); - // Nobody has claimed this, so pass it to the parent return INDI::Telescope::ISNewSwitch(dev,name,states,names,n); } +bool LX200Generic::SetSlewRate(int index) +{ + // Convert index to Meade format + index = 3 - index; + + if (isSimulation() == false && setSlewMode(PortFD, index) < 0) + { + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return false; + } + + SlewRateSP.s = IPS_OK; + IDSetSwitch(&SlewRateSP, NULL); + return true; +} + void LX200Generic::updateFocusHelper(void *p) { ((LX200Generic *) p)->updateFocusTimer(); @@ -1075,7 +1078,6 @@ { switch (FocusTimerNP.s) { - case IPS_IDLE: break; @@ -1155,6 +1157,7 @@ break; case SCOPE_SLEWING: + case SCOPE_PARKING: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; @@ -1182,7 +1185,13 @@ currentDEC -= da; if (nlocked == 2) - TrackState = SCOPE_TRACKING; + { + if (TrackState == SCOPE_SLEWING) + TrackState = SCOPE_TRACKING; + else + SetParked(true); + + } break; @@ -1389,7 +1398,7 @@ IDSetNumber (&LocationNP, NULL); } -bool LX200Generic::GuideNorth(float ms) +IPState LX200Generic::GuideNorth(float ms) { int use_pulse_cmd; @@ -1397,8 +1406,8 @@ if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { - IDMessage(getDeviceName(), "Cannot guide while moving."); - return false; + DEBUG(INDI::Logger::DBG_ERROR, "Cannot guide while moving."); + return IPS_ALERT; } // If already moving (no pulse command), then stop movement @@ -1406,7 +1415,7 @@ { int dir = IUFindOnSwitchIndex(&MovementNSSP); - MoveNS(dir == 0 ? MOTION_NORTH : MOTION_SOUTH, MOTION_STOP); + MoveNS(dir == 0 ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_STOP); } @@ -1423,25 +1432,25 @@ { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { - SlewModeSP.s = IPS_ALERT; - IDSetSwitch(&SlewModeSP, "Error setting slew mode."); - return false; + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return IPS_ALERT; } MovementNSS[0].s = ISS_ON; - MoveNS(MOTION_NORTH, MOTION_START); + MoveNS(DIRECTION_NORTH, MOTION_START); } // Set slew to guiding - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + IUResetSwitch(&SlewRateSP); + SlewRateS[SLEW_GUIDE].s = ISS_ON; + IDSetSwitch(&SlewRateSP, NULL); guide_direction = LX200_NORTH; GuideNSTID = IEAddTimer (ms, guideTimeoutHelper, this); - return true; + return IPS_BUSY; } -bool LX200Generic::GuideSouth(float ms) +IPState LX200Generic::GuideSouth(float ms) { int use_pulse_cmd; @@ -1449,8 +1458,8 @@ if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { - IDMessage(getDeviceName(), "Cannot guide while moving."); - return false; + DEBUG(INDI::Logger::DBG_ERROR, "Cannot guide while moving."); + return IPS_ALERT; } // If already moving (no pulse command), then stop movement @@ -1458,7 +1467,7 @@ { int dir = IUFindOnSwitchIndex(&MovementNSSP); - MoveNS(dir == 0 ? MOTION_NORTH : MOTION_SOUTH, MOTION_STOP); + MoveNS(dir == 0 ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_STOP); } @@ -1475,26 +1484,26 @@ { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { - SlewModeSP.s = IPS_ALERT; - IDSetSwitch(&SlewModeSP, "Error setting slew mode."); - return false; + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return IPS_ALERT; } MovementNSS[1].s = ISS_ON; - MoveNS(MOTION_SOUTH, MOTION_START); + MoveNS(DIRECTION_SOUTH, MOTION_START); } // Set slew to guiding - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + IUResetSwitch(&SlewRateSP); + SlewRateS[SLEW_GUIDE].s = ISS_ON; + IDSetSwitch(&SlewRateSP, NULL); guide_direction = LX200_SOUTH; GuideNSTID = IEAddTimer (ms, guideTimeoutHelper, this); - return true; + return IPS_BUSY; } -bool LX200Generic::GuideEast(float ms) +IPState LX200Generic::GuideEast(float ms) { int use_pulse_cmd; @@ -1503,8 +1512,8 @@ if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { - IDMessage(getDeviceName(), "Cannot guide while moving."); - return false; + DEBUG(INDI::Logger::DBG_ERROR, "Cannot guide while moving."); + return IPS_ALERT; } // If already moving (no pulse command), then stop movement @@ -1512,7 +1521,7 @@ { int dir = IUFindOnSwitchIndex(&MovementWESP); - MoveWE(dir == 0 ? MOTION_WEST : MOTION_EAST, MOTION_STOP); + MoveWE(dir == 0 ? DIRECTION_WEST : DIRECTION_EAST, MOTION_STOP); } @@ -1529,26 +1538,26 @@ { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { - SlewModeSP.s = IPS_ALERT; - IDSetSwitch(&SlewModeSP, "Error setting slew mode."); - return false; + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return IPS_ALERT; } MovementWES[1].s = ISS_ON; - MoveWE(MOTION_EAST, MOTION_START); + MoveWE(DIRECTION_EAST, MOTION_START); } // Set slew to guiding - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + IUResetSwitch(&SlewRateSP); + SlewRateS[SLEW_GUIDE].s = ISS_ON; + IDSetSwitch(&SlewRateSP, NULL); guide_direction = LX200_EAST; GuideWETID = IEAddTimer (ms, guideTimeoutHelper, this); - return true; + return IPS_BUSY; } -bool LX200Generic::GuideWest(float ms) +IPState LX200Generic::GuideWest(float ms) { int use_pulse_cmd; @@ -1557,8 +1566,8 @@ if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { - IDMessage(getDeviceName(), "Cannot guide while moving."); - return false; + DEBUG(INDI::Logger::DBG_ERROR, "Cannot guide while moving."); + return IPS_ALERT; } // If already moving (no pulse command), then stop movement @@ -1566,8 +1575,7 @@ { int dir = IUFindOnSwitchIndex(&MovementWESP); - MoveWE(dir == 0 ? MOTION_WEST : MOTION_EAST, MOTION_STOP); - + MoveWE(dir == 0 ? DIRECTION_WEST : DIRECTION_EAST, MOTION_STOP); } if (GuideWETID) @@ -1583,22 +1591,22 @@ { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { - SlewModeSP.s = IPS_ALERT; - IDSetSwitch(&SlewModeSP, "Error setting slew mode."); - return false; + SlewRateSP.s = IPS_ALERT; + IDSetSwitch(&SlewRateSP, "Error setting slew mode."); + return IPS_ALERT; } MovementWES[0].s = ISS_ON; - MoveWE(MOTION_WEST, MOTION_START); + MoveWE(DIRECTION_WEST, MOTION_START); } // Set slew to guiding - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); + IUResetSwitch(&SlewRateSP); + SlewRateS[SLEW_GUIDE].s = ISS_ON; + IDSetSwitch(&SlewRateSP, NULL); guide_direction = LX200_WEST; GuideWETID = IEAddTimer (ms, guideTimeoutHelper, this); - return true; + return IPS_BUSY; } @@ -1634,7 +1642,7 @@ if (guide_direction == LX200_NORTH || guide_direction == LX200_SOUTH) { - MoveNS(guide_direction == LX200_NORTH ? MOTION_NORTH : MOTION_SOUTH, MOTION_STOP); + MoveNS(guide_direction == LX200_NORTH ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_STOP); if (guide_direction == LX200_NORTH) GuideNSNP.np[0].value = 0; @@ -1649,7 +1657,7 @@ } if (guide_direction == LX200_WEST || guide_direction == LX200_EAST) { - MoveWE(guide_direction == LX200_WEST ? MOTION_WEST : MOTION_EAST, MOTION_STOP); + MoveWE(guide_direction == LX200_WEST ? DIRECTION_WEST : DIRECTION_EAST, MOTION_STOP); if (guide_direction == LX200_WEST) GuideWENP.np[0].value = 0; else @@ -1680,156 +1688,3 @@ } } -bool LX200Generic::ISSnoopDevice(XMLEle *root) -{ - - controller->ISSnoopDevice(root); - - return INDI::Telescope::ISSnoopDevice(root); - -} - -void LX200Generic::processButton(const char * button_n, ISState state) -{ - //ignore OFF - if (state == ISS_OFF) - return; - - // Max Slew speed - if (!strcmp(button_n, "Slew Max")) - { - setSlewMode(PortFD, 0); - IUResetSwitch(&SlewModeSP); - SlewModeS[0].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Find Slew speed - else if (!strcmp(button_n, "Slew Find")) - { - setSlewMode(PortFD, 1); - IUResetSwitch(&SlewModeSP); - SlewModeS[1].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Centering Slew - else if (!strcmp(button_n, "Slew Centering")) - { - setSlewMode(PortFD, 2); - IUResetSwitch(&SlewModeSP); - SlewModeS[2].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Guide Slew - else if (!strcmp(button_n, "Slew Guide")) - { - setSlewMode(PortFD, 3); - IUResetSwitch(&SlewModeSP); - SlewModeS[3].s = ISS_ON; - IDSetSwitch(&SlewModeSP, NULL); - } - // Abort - else if (!strcmp(button_n, "Abort Motion")) - { - // Only abort if we have some sort of motion going on - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY - || GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) - { - - Abort(); - } - } - -} - -void LX200Generic::processNSWE(double mag, double angle) -{ - if (mag < 0.5) - { - // Moving in the same direction will make it stop - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - Abort(); - } - // Put high threshold - else if (mag > 0.9) - { - // North - if (angle > 0 && angle < 180) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON) - MoveNS(MOTION_NORTH, MOTION_START); - - MovementNSSP.s = IPS_BUSY; - MovementNSSP.sp[0].s = ISS_ON; - MovementNSSP.sp[1].s = ISS_OFF; - IDSetSwitch(&MovementNSSP, NULL); - } - // South - if (angle > 180 && angle < 360) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON) - MoveNS(MOTION_SOUTH, MOTION_START); - - MovementNSSP.s = IPS_BUSY; - MovementNSSP.sp[0].s = ISS_OFF; - MovementNSSP.sp[1].s = ISS_ON; - IDSetSwitch(&MovementNSSP, NULL); - } - // East - if (angle < 90 || angle > 270) - { - // Don't try to move if you're busy and moving in the same direction - if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON) - MoveWE(MOTION_EAST, MOTION_START); - - MovementWESP.s = IPS_BUSY; - MovementWESP.sp[0].s = ISS_OFF; - MovementWESP.sp[1].s = ISS_ON; - IDSetSwitch(&MovementWESP, NULL); - } - - // West - if (angle > 90 && angle < 270) - { - - // Don't try to move if you're busy and moving in the same direction - if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON) - MoveWE(MOTION_WEST, MOTION_START); - - MovementWESP.s = IPS_BUSY; - MovementWESP.sp[0].s = ISS_ON; - MovementWESP.sp[1].s = ISS_OFF; - IDSetSwitch(&MovementWESP, NULL); - } - } - -} - -bool LX200Generic::saveConfigItems(FILE *fp) -{ - controller->saveConfigItems(fp); - - INDI::Telescope::saveConfigItems(fp); - - return true; -} - -void LX200Generic::processJoystick(const char * joystick_n, double mag, double angle) -{ - if (!strcmp(joystick_n, "NSWE Control")) - processNSWE(mag, angle); -} - - -void LX200Generic::joystickHelper(const char * joystick_n, double mag, double angle, void *context) -{ - static_cast(context)->processJoystick(joystick_n, mag, angle); - -} - -void LX200Generic::buttonHelper(const char * button_n, ISState state, void *context) -{ - static_cast(context)->processButton(button_n, state); -} - diff -Nru libindi-1.0.0/drivers/telescope/lx200generic.h libindi-1.1.0/drivers/telescope/lx200generic.h --- libindi-1.0.0/drivers/telescope/lx200generic.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200generic.h 2015-09-06 13:17:35.000000000 +0000 @@ -38,7 +38,7 @@ virtual const char *getDefaultName(); virtual bool Connect(); - virtual bool Connect(char *); + virtual bool Connect(const char *port, uint16_t baud); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual void ISGetProperties(const char *dev); @@ -47,35 +47,33 @@ virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual bool ISSnoopDevice(XMLEle *root); void updateFocusTimer(); void guideTimeout(); - static void joystickHelper(const char * joystick_n, double mag, double angle, void *context); - static void buttonHelper(const char * button_n, ISState state, void *context); - protected: - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + virtual bool SetSlewRate(int index); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); virtual bool Abort(); virtual bool updateTime(ln_date * utc, double utc_offset); virtual bool updateLocation(double latitude, double longitude, double elevation); - virtual bool GuideNorth(float ms); - virtual bool GuideSouth(float ms); - virtual bool GuideEast(float ms); - virtual bool GuideWest(float ms); - - virtual bool saveConfigItems(FILE *fp); + virtual IPState GuideNorth(float ms); + virtual IPState GuideSouth(float ms); + virtual IPState GuideEast(float ms); + virtual IPState GuideWest(float ms); virtual bool Goto(double,double); virtual bool Park(); virtual bool Sync(double ra, double dec); - virtual void debugTriggered(bool enable); + virtual bool isSlewComplete(); + virtual bool checkConnection(); + + virtual void debugTriggered(bool enable); virtual void getBasicData(); void slewError(int slewCode); @@ -87,10 +85,6 @@ static void updateFocusHelper(void *p); static void guideTimeoutHelper(void *p); - virtual void processNSWE(double mag, double angle); - virtual void processJoystick(const char * joystick_n, double mag, double angle); - virtual void processButton(const char * button_n, ISState state); - int GuideNSTID; int GuideWETID; @@ -99,24 +93,20 @@ int trackingMode; long guide_direction; + unsigned int DBG_SCOPE; + double JD; double targetRA, targetDEC; double currentRA, currentDEC; int MaxReticleFlashRate; - INDI::Controller *controller; - /* Telescope Alignment Mode */ ISwitchVectorProperty AlignmentSP; ISwitch AlignmentS[3]; - /* Slew Speed */ - ISwitchVectorProperty SlewModeSP; - ISwitch SlewModeS[4]; - /* Tracking Mode */ ISwitchVectorProperty TrackModeSP; - ISwitch TrackModeS[3]; + ISwitch TrackModeS[4]; /* Tracking Frequency */ INumberVectorProperty TrackingFreqNP; diff -Nru libindi-1.0.0/drivers/telescope/lx200genericlegacy.cpp libindi-1.1.0/drivers/telescope/lx200genericlegacy.cpp --- libindi-1.0.0/drivers/telescope/lx200genericlegacy.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200genericlegacy.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2186 +0,0 @@ -#if 0 - LX200 Generic - Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "indicom.h" -#include "lx200driver.h" -#include "lx200ap.h" -#include "lx200fs2.h" - -#include - -#ifdef HAVE_NOVA_H -#include -#endif - -LX200GenericLegacy *telescope = NULL; -int MaxReticleFlashRate = 3; - -/* There is _one_ binary for all LX200 drivers, but each binary is renamed -** to its device name (i.e. lx200gps, lx200_16..etc). The main function will -** fetch from std args the binary name and ISInit will create the apporpiate -** device afterwards. If the binary name does not match any known devices, -** we simply create a generic device. -*/ -extern char* me; - -#define COMM_GROUP "Communication" -#define BASIC_GROUP "Main Control" -#define MOTION_GROUP "Motion Control" -#define DATETIME_GROUP "Date/Time" -#define SITE_GROUP "Site Management" -#define FOCUS_GROUP "Focus Control" - -#define LX200_TRACK 0 -#define LX200_SYNC 1 - -/* Simulation Parameters */ -#define SLEWRATE 1 /* slew rate, degrees/s */ -#define SIDRATE 0.004178 /* sidereal rate, degrees/s */ - -/* Handy Macros */ -#define currentRA EquatorialCoordsRN[0].value -#define currentDEC EquatorialCoordsRN[1].value - -static void ISPoll(void *); -static void retryConnection(void *); - -/*INDI Propertries */ - -/**********************************************************************************************/ -/************************************ GROUP: Communication ************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: Connection -*********************************************/ -static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; -ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0}; - -/******************************************** - Property: Device Port -*********************************************/ -/*wildi removed static */ -static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; -ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; - -/******************************************** - Property: Telescope Alignment Mode -*********************************************/ -static ISwitch AlignmentS [] = {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}}; -static ISwitchVectorProperty AlignmentSw= { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0}; - -/**********************************************************************************************/ -/************************************ GROUP: Main Control *************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: Equatorial Coordinates JNow - Perm: RO -*********************************************/ -INumber EquatorialCoordsRN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}}; -INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0}; - -/******************************************** - Property: On Coord Set - Description: This property decides what happens - when we receive a new equatorial coord - value. We either track, or sync - to the new coordinates. -*********************************************/ -static ISwitch OnCoordSetS[] = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"SYNC", "Sync", ISS_OFF, 0 , 0}}; -ISwitchVectorProperty OnCoordSetSP= { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0}; - -/******************************************** - Property: Abort telescope motion -*********************************************/ -static ISwitch AbortSlewS[] = {{"ABORT", "Abort", ISS_OFF, 0, 0 }}; -ISwitchVectorProperty AbortSlewSP= { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0}; - -/**********************************************************************************************/ -/************************************** GROUP: Motion *****************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: Slew Speed -*********************************************/ -static ISwitch SlewModeS[] = {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}}; -ISwitchVectorProperty SlewModeSP = { mydev, "Slew rate", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0}; - -/******************************************** - Property: Tracking Mode -*********************************************/ -static ISwitch TrackModeS[] = {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}}; -static ISwitchVectorProperty TrackModeSP= { mydev, "Tracking Mode", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0}; - -/******************************************** - Property: Tracking Frequency -*********************************************/ -static INumber TrackFreqN[] = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}}; -static INumberVectorProperty TrackingFreqNP= { mydev, "Tracking Frequency", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, TrackFreqN, NARRAY(TrackFreqN), "", 0}; - -/******************************************** - Property: Movement (Arrow keys on handset). North/South -*********************************************/ -static ISwitch MovementNSS[] = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}}; -ISwitchVectorProperty MovementNSSP = { mydev, "TELESCOPE_MOTION_NS", "North/South", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0}; - -/******************************************** - Property: Movement (Arrow keys on handset). West/East -*********************************************/ -static ISwitch MovementWES[] = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}}; -ISwitchVectorProperty MovementWESP = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0}; - -/******************************************** - Property: Timed Guide movement. North/South -*********************************************/ -static INumber GuideNSN[] = {{"TIMED_GUIDE_N", "North (ms)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_S", "South (ms)", "%g", 0, 10000, 100, 100, 0, 0}}; -INumberVectorProperty GuideNSNP = { mydev, "TELESCOPE_TIMED_GUIDE_NS", "Guide North/South", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideNSN, NARRAY(GuideNSN), "", 0}; - -/******************************************** - Property: Timed Guide movement. West/East -*********************************************/ -static INumber GuideWEN[] = {{"TIMED_GUIDE_W", "West (ms)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_E", "East (ms)", "%g", 0, 10000, 100, 100, 0, 0}}; -INumberVectorProperty GuideWENP = { mydev, "TELESCOPE_TIMED_GUIDE_WE", "Guide West/East", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideWEN, NARRAY(GuideWEN), "", 0}; - -/******************************************** - Property: Slew Accuracy - Desciption: How close the scope have to be with - respect to the requested coords for - the tracking operation to be successull - i.e. returns OK -*********************************************/ -INumber SlewAccuracyN[] = { - {"SlewRA", "RA (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0}, - {"SlewkDEC", "Dec (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0}, -}; -INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0}; - -/******************************************** - Property: Use pulse-guide commands - Desciption: Set to on if this mount can support - pulse guide commands. There appears to - be no way to query this information from - the mount -*********************************************/ -static ISwitch UsePulseCmdS[] = {{ "Off", "", ISS_ON, 0, 0} , { "On", "", ISS_OFF, 0, 0}}; -static ISwitchVectorProperty UsePulseCmdSP= { mydev, "Use Pulse Cmd", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, UsePulseCmdS, NARRAY(UsePulseCmdS), "", 0}; - -/**********************************************************************************************/ -/************************************** GROUP: Focus ******************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: Focus Direction -*********************************************/ -ISwitch FocusMotionS[] = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}}; -ISwitchVectorProperty FocusMotionSP = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0}; - -/******************************************** - Property: Focus Timer -*********************************************/ -INumber FocusTimerN[] = { {"TIMER", "Timer (ms)", "%g", 0., 10000., 1000., 50., 0, 0, 0 }}; -INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0}; - -/******************************************** - Property: Focus Mode -*********************************************/ -static ISwitch FocusModeS[] = { {"FOCUS_HALT", "Halt", ISS_ON, 0, 0}, - {"FOCUS_SLOW", "Slow", ISS_OFF, 0, 0}, - {"FOCUS_FAST", "Fast", ISS_OFF, 0, 0}}; -static ISwitchVectorProperty FocusModeSP = {mydev, "FOCUS_MODE", "Mode", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusModeS, NARRAY(FocusModeS), "", 0}; - -/**********************************************************************************************/ -/*********************************** GROUP: Date & Time ***************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: UTC Time -*********************************************/ -static IText TimeT[] = {{"UTC", "UTC", 0, 0, 0, 0}}; -ITextVectorProperty TimeTP = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, TimeT, NARRAY(TimeT), "", 0}; - -/******************************************** - Property: DST Corrected UTC Offfset -*********************************************/ -static INumber UTCOffsetN[] = {{"OFFSET", "Offset", "%0.3g" , -12.,12.,0.5,0., 0, 0, 0}}; -INumberVectorProperty UTCOffsetNP = { mydev, "TIME_UTC_OFFSET", "UTC Offset", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTCOffsetN , NARRAY(UTCOffsetN), "", 0}; - -/******************************************** - Property: Sidereal Time -*********************************************/ -static INumber SDTimeN[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}}; -INumberVectorProperty SDTimeNP = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, SDTimeN, NARRAY(SDTimeN), "", 0}; - -/**********************************************************************************************/ -/************************************* GROUP: Sites *******************************************/ -/**********************************************************************************************/ - -/******************************************** - Property: Site Management -*********************************************/ -static ISwitch SitesS[] = {{"Site 1", "", ISS_ON, 0, 0}, {"Site 2", "", ISS_OFF, 0, 0}, {"Site 3", "", ISS_OFF, 0, 0}, {"Site 4", "", ISS_OFF, 0 ,0}}; -static ISwitchVectorProperty SitesSP = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0}; - -/******************************************** - Property: Site Name -*********************************************/ -static IText SiteNameT[] = {{"Name", "", 0, 0, 0, 0}}; -static ITextVectorProperty SiteNameTP = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0}; - -/******************************************** - Property: Geographical Location -*********************************************/ - -static INumber geo[] = { - {"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, - {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0}, - {"HEIGHT", "Height m", "%10.2f", -300., 6000., 0., 610., 0, 0, 0}, -}; -INumberVectorProperty geoNP = { - mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE, - geo, NARRAY(geo), "", 0}; - -/*****************************************************************************************************/ -/**************************************** END PROPERTIES *********************************************/ -/*****************************************************************************************************/ - -void changeLX200GenericLegacyDeviceName(const char * newName) -{ - // COMM_GROUP - strcpy(ConnectSP.device , newName); - strcpy(PortTP.device , newName); - strcpy(AlignmentSw.device, newName); - - // BASIC_GROUP - strcpy(EquatorialCoordsRNP.device, newName); - strcpy(OnCoordSetSP.device , newName ); - strcpy(AbortSlewSP.device , newName ); - - // MOTION_GROUP - strcpy(SlewModeSP.device , newName ); - strcpy(TrackModeSP.device , newName ); - strcpy(TrackingFreqNP.device , newName ); - strcpy(MovementNSSP.device , newName ); - strcpy(MovementWESP.device , newName ); - strcpy(GuideNSNP.device , newName ); - strcpy(GuideWENP.device , newName ); - strcpy(SlewAccuracyNP.device, newName); - strcpy(UsePulseCmdSP.device, newName); - - // FOCUS_GROUP - strcpy(FocusModeSP.device , newName ); - strcpy(FocusMotionSP.device , newName ); - strcpy(FocusTimerNP.device, newName); - - // DATETIME_GROUP - strcpy(TimeTP.device , newName ); - strcpy(UTCOffsetNP.device , newName ); - strcpy(SDTimeNP.device , newName ); - - // SITE_GROUP - strcpy(SitesSP.device , newName ); - strcpy(SiteNameTP.device , newName ); - strcpy(geoNP.device , newName ); - -} - -void changeAllDeviceNames(const char *newName) -{ - changeLX200GenericLegacyDeviceName(newName); - changeLX200FS2DeviceName(newName); -} - - -/* send client definitions of all properties */ -void ISInit() -{ - static int isInit=0; - char *envDev = getenv("INDIDEV"); - - if (isInit) - return; - - isInit = 1; - - IUSaveText(&PortT[0], "/dev/ttyS0"); - IUSaveText(&TimeT[0], "YYYY-MM-DDTHH:MM:SS"); - - // We need to check if UTCOffset has been set by user or not - UTCOffsetN[0].aux0 = (int *) malloc(sizeof(int)); - *((int *) UTCOffsetN[0].aux0) = 0; - - - if (strstr(me, "indi_lx200fs2")) - { - fprintf(stderr , "initializing from fs2 device...\n"); - - // 2. device = sub_class - telescope = new LX200Fs2(); - - if (envDev != NULL) - { - // 1. change device name - changeAllDeviceNames(envDev); - telescope->setCurrentDeviceName(envDev); - } - else - { - // 1. change device name - changeAllDeviceNames("LX200 FS2"); - telescope->setCurrentDeviceName("LX200 FS2"); - } - - } - // be nice and give them a generic device - else - { - telescope = new LX200GenericLegacy(); - - if (envDev != NULL) - { - // 1. change device name - changeAllDeviceNames(envDev); - telescope->setCurrentDeviceName(envDev); - } - else - { - // 1. change device name - changeAllDeviceNames("LX200 Generic"); - telescope->setCurrentDeviceName("LX200 Generic"); - } - - } - IEAddTimer (POLLMS, ISPoll, NULL); -} - -void ISGetProperties (const char *dev) -{ ISInit(); telescope->ISGetProperties(dev);} -void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);} -void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ ISInit(); telescope->ISNewText(dev, name, texts, names, n);} -void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ ISInit(); telescope->ISNewNumber(dev, name, values, names, n);} -void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;} -void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) -{ - INDI_UNUSED(dev); - INDI_UNUSED(name); - INDI_UNUSED(sizes); - INDI_UNUSED(blobsizes); - INDI_UNUSED(blobs); - INDI_UNUSED(formats); - INDI_UNUSED(names); - INDI_UNUSED(n); -} - -void ISSnoopDevice (XMLEle *root) -{ - telescope->ISSnoopDevice(root); -} - -/************************************************** -*** LX200 Generic Implementation -***************************************************/ - -LX200GenericLegacy::LX200GenericLegacy() -{ - currentSiteNum = 1; - trackingMode = LX200_TRACK_DEFAULT; - lastSet = -1; - fault = false; - simulation = false; - currentSet = 0; - fd = -1; - GuideNSTID = 0; - GuideWETID = 0; - - // Children call parent routines, this is the default - IDLog("INDI Library v%g\n", INDI_LIBV); - IDLog("initializing from generic LX200 device...\n"); - IDLog("Driver Version: 2012-07-27\n"); - - //enableSimulation(true); -} - -LX200GenericLegacy::~LX200GenericLegacy() -{ -} - -void LX200GenericLegacy::setCurrentDeviceName(const char * devName) -{ - strcpy(thisDevice, devName); -} - -void LX200GenericLegacy::ISGetProperties(const char *dev) -{ - - if (dev && strcmp (thisDevice, dev)) - return; - - // COMM_GROUP - IDDefSwitch (&ConnectSP, NULL); - IDDefText (&PortTP, NULL); - IDDefSwitch (&AlignmentSw, NULL); - - // BASIC_GROUP - IDDefNumber (&EquatorialCoordsRNP, NULL); - IDDefSwitch (&OnCoordSetSP, NULL); - IDDefSwitch (&AbortSlewSP, NULL); - - // MOTION_GROUP - IDDefNumber (&TrackingFreqNP, NULL); - IDDefSwitch (&SlewModeSP, NULL); - IDDefSwitch (&TrackModeSP, NULL); - IDDefSwitch (&MovementNSSP, NULL); - IDDefSwitch (&MovementWESP, NULL); - IDDefNumber (&GuideNSNP, NULL ); - IDDefNumber (&GuideWENP, NULL ); - IDDefNumber (&SlewAccuracyNP, NULL); - IDDefSwitch (&UsePulseCmdSP, NULL); - - // FOCUS_GROUP - IDDefSwitch(&FocusModeSP, NULL); - IDDefSwitch(&FocusMotionSP, NULL); - IDDefNumber(&FocusTimerNP, NULL); - - // DATETIME_GROUP - #ifdef HAVE_NOVA_H - IDDefText (&TimeTP, NULL); - IDDefNumber(&UTCOffsetNP, NULL); - #endif - - IDDefNumber (&SDTimeNP, NULL); - - // SITE_GROUP - IDDefSwitch (&SitesSP, NULL); - IDDefText (&SiteNameTP, NULL); - IDDefNumber (&geoNP, NULL); - - /* Send the basic data to the new client if the previous client(s) are already connected. */ - if (ConnectSP.s == IPS_OK) - getBasicData(); - -} - -void LX200GenericLegacy::ISSnoopDevice (XMLEle *root) -{ - INDI_UNUSED(root); -} - -void LX200GenericLegacy::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - int err; - IText *tp; - - // ignore if not ours // - if (strcmp (dev, thisDevice)) - return; - - // suppress warning - n=n; - - if (!strcmp(name, PortTP.name) ) - { - PortTP.s = IPS_OK; - tp = IUFindText( &PortTP, names[0] ); - if (!tp) - return; - - IUSaveText(&PortTP.tp[0], texts[0]); - IDSetText (&PortTP, NULL); - return; - } - - if (!strcmp (name, SiteNameTP.name) ) - { - if (checkPower(&SiteNameTP)) - return; - - if ( ( err = setSiteName(fd, texts[0], currentSiteNum) < 0) ) - { - handleError(&SiteNameTP, err, "Setting site name"); - return; - } - SiteNameTP.s = IPS_OK; - tp = IUFindText(&SiteNameTP, names[0]); - tp->text = new char[strlen(texts[0])+1]; - strcpy(tp->text, texts[0]); - IDSetText(&SiteNameTP , "Site name updated"); - return; - } - - #ifdef HAVE_NOVA_H - if (!strcmp (name, TimeTP.name)) - { - if (checkPower(&TimeTP)) - return; - - if (simulation) - { - TimeTP.s = IPS_OK; - IUSaveText(&TimeTP.tp[0], texts[0]); - IDSetText(&TimeTP, "Simulated time updated."); - return; - } - - struct ln_date utm; - struct ln_zonedate ltm; - - if (*((int *) UTCOffsetN[0].aux0) == 0) - { - TimeTP.s = IPS_IDLE; - IDSetText(&TimeTP, "You must set the UTC Offset property first."); - return; - } - - if (extractISOTime(texts[0], &utm) < 0) - { - TimeTP.s = IPS_IDLE; - IDSetText(&TimeTP , "Time invalid"); - return; - } - - // update JD - JD = ln_get_julian_day(&utm); - IDLog("New JD is %f\n", (float) JD); - - ln_date_to_zonedate(&utm, <m, UTCOffsetN[0].value*3600.0); - - // Set Local Time - if ( ( err = setLocalTime(fd, ltm.hours, ltm.minutes, ltm.seconds) < 0) ) - { - handleError(&TimeTP, err, "Setting local time"); - return; - } - - if (!strcmp(dev, "LX200 GPS")) - { - if ( ( err = setCalenderDate(fd, utm.days, utm.months, utm.years) < 0) ) - { - handleError(&TimeTP, err, "Setting TimeT date."); - return; - } - } - else - { - if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) ) - { - handleError(&TimeTP, err, "Setting local date."); - return; - } - } - - // Everything Ok, save time value - if (IUUpdateText(&TimeTP, texts, names, n) < 0) - return; - - TimeTP.s = IPS_OK; - IDSetText(&TimeTP , "Time updated to %s, updating planetary data...", texts[0]); - - // Also update telescope's sidereal time - getSDTime(fd, &SDTimeN[0].value); - IDSetNumber(&SDTimeNP, NULL); - } - #endif -} - - -void LX200GenericLegacy::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - int h =0, m =0, s=0, err; - double newRA =0, newDEC =0; - - // ignore if not ours // - if (strcmp (dev, thisDevice)) - return; - - // Slewing Accuracy - if (!strcmp (name, SlewAccuracyNP.name)) - { - if (!IUUpdateNumber(&SlewAccuracyNP, values, names, n)) - { - SlewAccuracyNP.s = IPS_OK; - IDSetNumber(&SlewAccuracyNP, NULL); - return; - } - - SlewAccuracyNP.s = IPS_ALERT; - IDSetNumber(&SlewAccuracyNP, "unknown error while setting tracking precision"); - return; - } - - #ifdef HAVE_NOVA_H - // DST Correct TimeT Offset - if (!strcmp (name, UTCOffsetNP.name)) - { - if (strcmp(names[0], UTCOffsetN[0].name)) - { - UTCOffsetNP.s = IPS_ALERT; - IDSetNumber( &UTCOffsetNP , "Unknown element %s for property %s.", names[0], UTCOffsetNP.label); - return; - } - - if (!simulation) - if ( ( err = setUTCOffset(fd, (values[0] * -1.0)) < 0) ) - { - UTCOffsetNP.s = IPS_ALERT; - IDSetNumber( &UTCOffsetNP , "Setting UTC Offset failed."); - return; - } - - *((int *) UTCOffsetN[0].aux0) = 1; - IUUpdateNumber(&UTCOffsetNP, values, names, n); - UTCOffsetNP.s = IPS_OK; - IDSetNumber(&UTCOffsetNP, NULL); - return; - } - #endif - - if (!strcmp (name, EquatorialCoordsRNP.name)) - { - int i=0, nset=0; - - if (checkPower(&EquatorialCoordsRNP)) - return; - - for (nset = i = 0; i < n; i++) - { - INumber *eqp = IUFindNumber (&EquatorialCoordsRNP, names[i]); - if (eqp == &EquatorialCoordsRN[0]) - { - newRA = values[i]; - nset += newRA >= 0 && newRA <= 24.0; - } else if (eqp == &EquatorialCoordsRN[1]) - { - newDEC = values[i]; - nset += newDEC >= -90.0 && newDEC <= 90.0; - } - } - - if (nset == 2) - { - /*EquatorialCoordsWNP.s = IPS_BUSY;*/ - char RAStr[32], DecStr[32]; - - fs_sexa(RAStr, newRA, 2, 3600); - fs_sexa(DecStr, newDEC, 2, 3600); - - #ifdef INDI_DEBUG - IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC); - IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr); - #endif - - if (!simulation) - if ( (err = setObjectRA(fd, newRA)) < 0 || ( err = setObjectDEC(fd, newDEC)) < 0) - { - EquatorialCoordsRNP.s = IPS_ALERT ; - IDSetNumber(&EquatorialCoordsRNP, NULL); - handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC"); - return; - } - /* wildi In principle this line is according to the discussion */ - /* In case the telescope is slewing, we have to abort that. No status change here */ - /* EquatorialCoordsWNP.s = IPS_OK; */ - IDSetNumber(&EquatorialCoordsRNP, NULL); - targetRA = newRA; - targetDEC = newDEC; - - if (handleCoordSet()) - { - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP, NULL); - } - } // end nset - else - { - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid"); - } - - return; - } /* end EquatorialCoordsWNP */ - - // Update Sidereal Time - if ( !strcmp (name, SDTimeNP.name) ) - { - if (checkPower(&SDTimeNP)) - return; - - - if (values[0] < 0.0 || values[0] > 24.0) - { - SDTimeNP.s = IPS_IDLE; - IDSetNumber(&SDTimeNP , "Time invalid"); - return; - } - - getSexComponents(values[0], &h, &m, &s); - IDLog("Sidereal Time is %02d:%02d:%02d\n", h, m, s); - - if ( ( err = setSDTime(fd, h, m, s) < 0) ) - { - handleError(&SDTimeNP, err, "Setting sidereal time"); - return; - } - - SDTimeNP.np[0].value = values[0]; - SDTimeNP.s = IPS_OK; - - IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s); - - return; - } - - // Update Geographical Location - if (!strcmp (name, geoNP.name)) - { - // new geographic coords - double newLong = 0, newLat = 0; - int i, nset; - char msg[128]; - - if (checkPower(&geoNP)) - return; - - - for (nset = i = 0; i < n; i++) - { - INumber *geop = IUFindNumber (&geoNP, names[i]); - if (geop == &geo[0]) - { - newLat = values[i]; - nset += newLat >= -90.0 && newLat <= 90.0; - } else if (geop == &geo[1]) - { - newLong = values[i]; - nset += newLong >= 0.0 && newLong < 360.0; - } - } - - if (nset == 2) - { - char l[32], L[32]; - geoNP.s = IPS_OK; - fs_sexa (l, newLat, 3, 3600); - fs_sexa (L, newLong, 4, 3600); - - if (!simulation) - { - if ( ( err = setSiteLongitude(fd, 360.0 - newLong) < 0) ) - { - handleError(&geoNP, err, "Setting site longitude coordinates"); - return; - } - if ( ( err = setSiteLatitude(fd, newLat) < 0) ) - { - handleError(&geoNP, err, "Setting site latitude coordinates"); - return; - } - } - - geoNP.np[0].value = newLat; - geoNP.np[1].value = newLong; - snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L); - } else - { - geoNP.s = IPS_IDLE; - strcpy(msg, "Lat or Long missing or invalid"); - } - IDSetNumber (&geoNP, "%s", msg); - return; - } - - // Update Frequency - if ( !strcmp (name, TrackingFreqNP.name) ) - { - - if (checkPower(&TrackingFreqNP)) - return; - - IDLog("Trying to set track freq of: %f\n", values[0]); - - if ( ( err = setTrackFreq(fd, values[0])) < 0) - { - handleError(&TrackingFreqNP, err, "Setting tracking frequency"); - return; - } - - TrackingFreqNP.s = IPS_OK; - TrackingFreqNP.np[0].value = values[0]; - IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]); - if (trackingMode != LX200_TRACK_MANUAL) - { - trackingMode = LX200_TRACK_MANUAL; - TrackModeS[0].s = ISS_OFF; - TrackModeS[1].s = ISS_OFF; - TrackModeS[2].s = ISS_ON; - TrackModeSP.s = IPS_OK; - selectTrackingMode(fd, trackingMode); - IDSetSwitch(&TrackModeSP, NULL); - } - - return; - } - - if (!strcmp(name, FocusTimerNP.name)) - { - if (checkPower(&FocusTimerNP)) - return; - - // Don't update if busy - if (FocusTimerNP.s == IPS_BUSY) - return; - - IUUpdateNumber(&FocusTimerNP, values, names, n); - - FocusTimerNP.s = IPS_OK; - - IDSetNumber(&FocusTimerNP, NULL); - IDLog("Setting focus timer to %g\n", FocusTimerN[0].value); - - return; - - } - - if (!strcmp(name, GuideNSNP.name)) - { - long direction; - int duration_msec; - int use_pulse_cmd; - if (checkPower(&GuideNSNP)) - return; - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - { - handleError(&GuideNSNP, err, "Can't guide while moving"); - return; - } - if (GuideNSNP.s == IPS_BUSY) - { - // Already guiding so stop before restarting timer - HaltMovement(fd, LX200_NORTH); - HaltMovement(fd, LX200_SOUTH); - } - if (GuideNSTID) { - IERmTimer(GuideNSTID); - GuideNSTID = 0; - } - IUUpdateNumber(&GuideNSNP, values, names, n); - - if (GuideNSNP.np[0].value > 0) { - duration_msec = GuideNSNP.np[0].value * 1000; - direction = LX200_NORTH; - } else { - duration_msec = GuideNSNP.np[1].value * 1000; - direction = LX200_SOUTH; - } - if (duration_msec <= 0) { - GuideNSNP.s = IPS_IDLE; - IDSetNumber (&GuideNSNP, NULL); - return; - } - use_pulse_cmd = getOnSwitch(&UsePulseCmdSP); - // fprintf(stderr, "Using %s mode to move %dmsec %s\n", - // use_pulse_cmd ? "Pulse" : "Legacy", - // duration_msec, direction == LX200_NORTH ? "North" : "South"); - if (use_pulse_cmd) { - SendPulseCmd(fd, direction, duration_msec); - } else { - if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) ) - { - handleError(&SlewModeSP, err, "Setting slew mode"); - return; - } - MoveTo(fd, direction); - } - GuideNSTID = IEAddTimer (duration_msec, guideTimeout, (void *)direction); - GuideNSNP.s = IPS_BUSY; - IDSetNumber(&GuideNSNP, NULL); - } - if (!strcmp(name, GuideWENP.name)) - { - long direction; - int duration_msec; - int use_pulse_cmd; - - if (checkPower(&GuideWENP)) - return; - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - { - handleError(&GuideWENP, err, "Can't guide while moving"); - return; - } - if (GuideWENP.s == IPS_BUSY) - { - // Already guiding so stop before restarting timer - HaltMovement(fd, LX200_WEST); - HaltMovement(fd, LX200_EAST); - } - if (GuideWETID) { - IERmTimer(GuideWETID); - GuideWETID = 0; - } - IUUpdateNumber(&GuideWENP, values, names, n); - - if (GuideWENP.np[0].value > 0) { - duration_msec = GuideWENP.np[0].value; - direction = LX200_WEST; - } else { - duration_msec = GuideWENP.np[1].value; - direction = LX200_EAST; - } - if (duration_msec <= 0) { - GuideWENP.s = IPS_IDLE; - IDSetNumber (&GuideWENP, NULL); - return; - } - use_pulse_cmd = getOnSwitch(&UsePulseCmdSP); - // fprintf(stderr, "Using %s mode to move %dmsec %s\n", - // use_pulse_cmd ? "Pulse" : "Legacy", - // duration_msec, direction == LX200_WEST ? "West" : "East"); - - if (use_pulse_cmd) { - SendPulseCmd(fd, direction, duration_msec); - } else { - if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) ) - { - handleError(&SlewModeSP, err, "Setting slew mode"); - return; - } - MoveTo(fd, direction); - } - GuideWETID = IEAddTimer (duration_msec, guideTimeout, (void *)direction); - GuideWENP.s = IPS_BUSY; - IDSetNumber(&GuideWENP, NULL); - } -} - -void LX200GenericLegacy::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - int err=0, index=0; - INDI_UNUSED(names); - - // ignore if not ours // - if (strcmp (thisDevice, dev)) - return; - - // FIRST Switch ALWAYS for power - if (!strcmp (name, ConnectSP.name)) - { - bool connectionEstablished = (ConnectS[0].s == ISS_ON); - if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return; - if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON)) - { - ConnectSP.s = IPS_OK; - IDSetSwitch(&ConnectSP, NULL); - return; - } - connectTelescope(); - return; - } - - // Coord set - if (!strcmp(name, OnCoordSetSP.name)) - { - if (checkPower(&OnCoordSetSP)) - return; - - if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return; - currentSet = getOnSwitch(&OnCoordSetSP); - OnCoordSetSP.s = IPS_OK; - IDSetSwitch(&OnCoordSetSP, NULL); - } - - // Abort Slew - if (!strcmp (name, AbortSlewSP.name)) - { - if (checkPower(&AbortSlewSP)) - { - AbortSlewSP.s = IPS_IDLE; - IDSetSwitch(&AbortSlewSP, NULL); - return; - } - - IUResetSwitch(&AbortSlewSP); - if (!simulation && abortSlew(fd) < 0) - { - AbortSlewSP.s = IPS_ALERT; - IDSetSwitch(&AbortSlewSP, NULL); - return; - } - - if (EquatorialCoordsRNP.s == IPS_BUSY) - { - AbortSlewSP.s = IPS_OK; - EquatorialCoordsRNP.s = IPS_IDLE; - IDSetSwitch(&AbortSlewSP, "Slew aborted."); - IDSetNumber(&EquatorialCoordsRNP, NULL); - } - else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - { - MovementNSSP.s = MovementWESP.s = IPS_IDLE; - - AbortSlewSP.s = IPS_OK; - EquatorialCoordsRNP.s = IPS_IDLE; - IUResetSwitch(&MovementNSSP); - IUResetSwitch(&MovementWESP); - IUResetSwitch(&AbortSlewSP); - - IDSetSwitch(&AbortSlewSP, "Slew aborted."); - IDSetSwitch(&MovementNSSP, NULL); - IDSetSwitch(&MovementWESP, NULL); - IDSetNumber(&EquatorialCoordsRNP, NULL); - } - else if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) - { - GuideNSNP.s = GuideWENP.s = IPS_IDLE; - GuideNSN[0].value = GuideNSN[1].value = 0.0; - GuideWEN[0].value = GuideWEN[1].value = 0.0; - if (GuideNSTID) { - IERmTimer(GuideNSTID); - GuideNSTID = 0; - } - if (GuideWETID) { - IERmTimer(GuideWETID); - GuideNSTID = 0; - } - - AbortSlewSP.s = IPS_OK; - EquatorialCoordsRNP.s = IPS_IDLE; - IUResetSwitch(&AbortSlewSP); - - IDSetSwitch(&AbortSlewSP, "Guide aborted."); - IDSetNumber(&GuideNSNP, NULL); - IDSetNumber(&GuideWENP, NULL); - IDSetNumber(&EquatorialCoordsRNP, NULL); - } - else - { - AbortSlewSP.s = IPS_OK; - IDSetSwitch(&AbortSlewSP, NULL); - } - - return; - } - - // Alignment - if (!strcmp (name, AlignmentSw.name)) - { - if (checkPower(&AlignmentSw)) - return; - - if (IUUpdateSwitch(&AlignmentSw, states, names, n) < 0) return; - index = getOnSwitch(&AlignmentSw); - - if ( ( err = setAlignmentMode(fd, index) < 0) ) - { - handleError(&AlignmentSw, err, "Setting alignment"); - return; - } - - AlignmentSw.s = IPS_OK; - IDSetSwitch (&AlignmentSw, NULL); - return; - - } - - // Sites - if (!strcmp (name, SitesSP.name)) - { - int dd=0, mm=0; - - if (checkPower(&SitesSP)) - return; - - if (IUUpdateSwitch(&SitesSP, states, names, n) < 0) return; - currentSiteNum = getOnSwitch(&SitesSP) + 1; - - if ( ( err = selectSite(fd, currentSiteNum) < 0) ) - { - handleError(&SitesSP, err, "Selecting sites"); - return; - } - - if ( ( err = getSiteLatitude(fd, &dd, &mm) < 0)) - { - handleError(&SitesSP, err, "Selecting sites"); - return; - } - - if (dd > 0) geoNP.np[0].value = dd + mm / 60.0; - else geoNP.np[0].value = dd - mm / 60.0; - - if ( ( err = getSiteLongitude(fd, &dd, &mm) < 0)) - { - handleError(&SitesSP, err, "Selecting sites"); - return; - } - - if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm / 60.0); - else geoNP.np[1].value = (dd - mm / 60.0) * -1.0; - - getSiteName(fd, SiteNameTP.tp[0].text, currentSiteNum); - - IDLog("Selecting site %d\n", currentSiteNum); - - geoNP.s = SiteNameTP.s = SitesSP.s = IPS_OK; - - IDSetNumber (&geoNP, NULL); - IDSetText (&SiteNameTP, NULL); - IDSetSwitch (&SitesSP, NULL); - return; - } - - // Focus Motion - if (!strcmp (name, FocusMotionSP.name)) - { - if (checkPower(&FocusMotionSP)) - return; - - // If mode is "halt" - if (FocusModeS[0].s == ISS_ON) - { - FocusMotionSP.s = IPS_IDLE; - IDSetSwitch(&FocusMotionSP, NULL); - return; - } - - if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return; - index = getOnSwitch(&FocusMotionSP); - - if ( ( err = setFocuserMotion(fd, index) < 0) ) - { - handleError(&FocusMotionSP, err, "Setting focuser speed"); - return; - } - - FocusMotionSP.s = IPS_BUSY; - - // with a timer - if (FocusTimerN[0].value > 0) - { - FocusTimerNP.s = IPS_BUSY; - IEAddTimer(50, LX200GenericLegacy::updateFocusTimer, this); - } - - IDSetSwitch(&FocusMotionSP, NULL); - return; - } - - // Slew mode - if (!strcmp (name, SlewModeSP.name)) - { - if (checkPower(&SlewModeSP)) - return; - - if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return; - index = getOnSwitch(&SlewModeSP); - - if ( ( err = setSlewMode(fd, index) < 0) ) - { - handleError(&SlewModeSP, err, "Setting slew mode"); - return; - } - - SlewModeSP.s = IPS_OK; - IDSetSwitch(&SlewModeSP, NULL); - return; - } - - // Movement (North/South) - if (!strcmp (name, MovementNSSP.name)) - { - if (checkPower(&MovementNSSP)) - return; - if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) - { - handleError(&MovementNSSP, err, "Can't move while guiding"); - return; - } - - int last_move=-1; - int current_move = -1; - - // -1 means all off previously - last_move = getOnSwitch(&MovementNSSP); - - if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0) - return; - - current_move = getOnSwitch(&MovementNSSP); - - // Previosuly active switch clicked again, so let's stop. - if (current_move == last_move) - { - HaltMovement(fd, (current_move == 0) ? LX200_NORTH : LX200_SOUTH); - IUResetSwitch(&MovementNSSP); - MovementNSSP.s = IPS_IDLE; - IDSetSwitch(&MovementNSSP, NULL); - return; - } - - #ifdef INDI_DEBUG - IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); - #endif - - // 0 (North) or 1 (South) - last_move = current_move; - - // Correction for LX200 Driver: North 0 - South 3 - current_move = (current_move == 0) ? LX200_NORTH : LX200_SOUTH; - - if ( ( err = MoveTo(fd, current_move) < 0) ) - { - handleError(&MovementNSSP, err, "Setting motion direction"); - return; - } - - MovementNSSP.s = IPS_BUSY; - IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == LX200_NORTH) ? "North" : "South"); - return; - } - - // Movement (West/East) - if (!strcmp (name, MovementWESP.name)) - { - if (checkPower(&MovementWESP)) - return; - if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) - { - handleError(&MovementWESP, err, "Can't move while guiding"); - return; - } - - int last_move=-1; - int current_move = -1; - - // -1 means all off previously - last_move = getOnSwitch(&MovementWESP); - - if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0) - return; - - current_move = getOnSwitch(&MovementWESP); - - // Previosuly active switch clicked again, so let's stop. - if (current_move == last_move) - { - HaltMovement(fd, (current_move ==0) ? LX200_WEST : LX200_EAST); - IUResetSwitch(&MovementWESP); - MovementWESP.s = IPS_IDLE; - IDSetSwitch(&MovementWESP, NULL); - return; - } - - #ifdef INDI_DEBUG - IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); - #endif - - // 0 (West) or 1 (East) - last_move = current_move; - - // Correction for LX200 Driver: West 1 - East 2 - current_move = (current_move == 0) ? LX200_WEST : LX200_EAST; - - if ( ( err = MoveTo(fd, current_move) < 0) ) - { - handleError(&MovementWESP, err, "Setting motion direction"); - return; - } - - MovementWESP.s = IPS_BUSY; - IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == LX200_WEST) ? "West" : "East"); - return; - } - - // Tracking mode - if (!strcmp (name, TrackModeSP.name)) - { - if (checkPower(&TrackModeSP)) - return; - - IUResetSwitch(&TrackModeSP); - IUUpdateSwitch(&TrackModeSP, states, names, n); - trackingMode = getOnSwitch(&TrackModeSP); - - if ( ( err = selectTrackingMode(fd, trackingMode) < 0) ) - { - handleError(&TrackModeSP, err, "Setting tracking mode."); - return; - } - - getTrackFreq(fd, &TrackFreqN[0].value); - TrackModeSP.s = IPS_OK; - IDSetNumber(&TrackingFreqNP, NULL); - IDSetSwitch(&TrackModeSP, NULL); - return; - } - - // Focus speed - if (!strcmp (name, FocusModeSP.name)) - { - if (checkPower(&FocusModeSP)) - return; - - IUResetSwitch(&FocusModeSP); - IUUpdateSwitch(&FocusModeSP, states, names, n); - - index = getOnSwitch(&FocusModeSP); - - /* disable timer and motion */ - if (index == 0) - { - IUResetSwitch(&FocusMotionSP); - FocusMotionSP.s = IPS_IDLE; - FocusTimerNP.s = IPS_IDLE; - IDSetSwitch(&FocusMotionSP, NULL); - IDSetNumber(&FocusTimerNP, NULL); - } - - setFocuserSpeedMode(fd, index); - FocusModeSP.s = IPS_OK; - IDSetSwitch(&FocusModeSP, NULL); - return; - } - - // Pulse-Guide command support - if (!strcmp (name, UsePulseCmdSP.name)) - { - if (checkPower(&UsePulseCmdSP)) - return; - - IUResetSwitch(&UsePulseCmdSP); - IUUpdateSwitch(&UsePulseCmdSP, states, names, n); - - UsePulseCmdSP.s = IPS_OK; - IDSetSwitch(&UsePulseCmdSP, NULL); - return; - } -} - -void LX200GenericLegacy::handleError(ISwitchVectorProperty *svp, int err, const char *msg) -{ - - svp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_lx200_connection(fd)) - { - /* The telescope is off locally */ - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetSwitch(svp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; - } - - /* If the error is a time out, then the device doesn't support this property or busy*/ - if (err == -2) - { - svp->s = IPS_ALERT; - IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - else - /* Changing property failed, user should retry. */ - IDSetSwitch( svp , "%s failed.", msg); - - fault = true; -} - -void LX200GenericLegacy::handleError(INumberVectorProperty *nvp, int err, const char *msg) -{ - - nvp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_lx200_connection(fd)) - { - /* The telescope is off locally */ - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetNumber(nvp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; - } - - /* If the error is a time out, then the device doesn't support this property */ - if (err == -2) - { - nvp->s = IPS_ALERT; - IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - else - /* Changing property failed, user should retry. */ - IDSetNumber( nvp , "%s failed.", msg); - - fault = true; -} - -void LX200GenericLegacy::handleError(ITextVectorProperty *tvp, int err, const char *msg) -{ - - tvp->s = IPS_ALERT; - - /* First check to see if the telescope is connected */ - if (check_lx200_connection(fd)) - { - /* The telescope is off locally */ - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_BUSY; - IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); - - IDSetText(tvp, NULL); - IEAddTimer(10000, retryConnection, &fd); - return; - } - - /* If the error is a time out, then the device doesn't support this property */ - if (err == -2) - { - tvp->s = IPS_ALERT; - IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); - } - - else - /* Changing property failed, user should retry. */ - IDSetText( tvp , "%s failed.", msg); - - fault = true; -} - - void LX200GenericLegacy::correctFault() - { - - fault = false; - IDMessage(thisDevice, "Telescope is online."); - - } - -bool LX200GenericLegacy::isTelescopeOn(void) -{ - //if (simulation) return true; - - return (ConnectSP.sp[0].s == ISS_ON); -} - -static void retryConnection(void * p) -{ - int fd = *( (int *) p); - - if (check_lx200_connection(fd)) - { - ConnectSP.s = IPS_IDLE; - IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); - return; - } - - ConnectS[0].s = ISS_ON; - ConnectS[1].s = ISS_OFF; - ConnectSP.s = IPS_OK; - - IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); - -} - -void LX200GenericLegacy::updateFocusTimer(void *p) -{ - int err=0; - - switch (FocusTimerNP.s) - { - - case IPS_IDLE: - break; - - case IPS_BUSY: - IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value); - FocusTimerN[0].value-=50; - - if (FocusTimerN[0].value <= 0) - { - IDLog("Focus Timer Expired\n"); - if ( ( err = setFocuserSpeedMode(telescope->fd, 0) < 0) ) - { - telescope->handleError(&FocusModeSP, err, "setting focuser mode"); - IDLog("Error setting focuser mode\n"); - return; - } - - - FocusMotionSP.s = IPS_IDLE; - FocusTimerNP.s = IPS_OK; - FocusModeSP.s = IPS_OK; - - IUResetSwitch(&FocusMotionSP); - IUResetSwitch(&FocusModeSP); - FocusModeS[0].s = ISS_ON; - - IDSetSwitch(&FocusModeSP, NULL); - IDSetSwitch(&FocusMotionSP, NULL); - } - - IDSetNumber(&FocusTimerNP, NULL); - - if (FocusTimerN[0].value > 0) - IEAddTimer(50, LX200GenericLegacy::updateFocusTimer, p); - break; - - case IPS_OK: - break; - - case IPS_ALERT: - break; - } - -} - -void LX200GenericLegacy::guideTimeout(void *p) -{ - long direction = (long)p; - int use_pulse_cmd; - - use_pulse_cmd = telescope->getOnSwitch(&UsePulseCmdSP); - if (direction == -1) - { - HaltMovement(telescope->fd, LX200_NORTH); - HaltMovement(telescope->fd, LX200_SOUTH); - HaltMovement(telescope->fd, LX200_EAST); - HaltMovement(telescope->fd, LX200_WEST); - IERmTimer(telescope->GuideNSTID); - IERmTimer(telescope->GuideWETID); - - } - else if (! use_pulse_cmd) - { - HaltMovement(telescope->fd, direction); - } - if (direction == LX200_NORTH || direction == LX200_SOUTH || direction == -1) - { - GuideNSNP.np[0].value = 0; - GuideNSNP.np[1].value = 0; - GuideNSNP.s = IPS_IDLE; - telescope->GuideNSTID = 0; - IDSetNumber(&GuideNSNP, NULL); - } - if (direction == LX200_WEST || direction == LX200_EAST || direction == -1) - { - GuideWENP.np[0].value = 0; - GuideWENP.np[1].value = 0; - GuideWENP.s = IPS_IDLE; - telescope->GuideWETID = 0; - IDSetNumber(&GuideWENP, NULL); - } -} - -void LX200GenericLegacy::ISPoll() -{ - double dx, dy; - int err=0; - - if (!isTelescopeOn()) - return; - - if (simulation) - { - mountSim(); - return; - } - - if ( (err = getLX200RA(fd, ¤tRA)) < 0 || (err = getLX200DEC(fd, ¤tDEC)) < 0) - { - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP, NULL); - handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); - return; - } - - if (fault) - correctFault(); - - switch (EquatorialCoordsRNP.s) - { - case IPS_IDLE: - case IPS_OK: - if ( fabs(lastRA - currentRA) > (SlewAccuracyN[0].value/(60.0*15.0)) || fabs(lastDEC - currentDEC) > (SlewAccuracyN[1].value/60.0)) - { - lastRA = currentRA; - lastDEC = currentDEC; - IDSetNumber (&EquatorialCoordsRNP, NULL); - } - break; - - case IPS_BUSY: - dx = targetRA - currentRA; - dy = targetDEC - currentDEC; - - // Wait until acknowledged or within threshold - if ( fabs(dx) <= (SlewAccuracyN[0].value/(60.0*15.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0)) - { - lastRA = currentRA; - lastDEC = currentDEC; - - EquatorialCoordsRNP.s = IPS_OK; - IDSetNumber(&EquatorialCoordsRNP, "Slew is complete, target locked..."); - } - break; - - case IPS_ALERT: - break; - } -} - - -// wildi nothing changed in LX200GenericLegacy::mountSim -void LX200GenericLegacy::mountSim () -{ - static struct timeval ltv; - struct timeval tv; - double dt, da, dx; - int nlocked; - - /* update elapsed time since last poll, don't presume exactly POLLMS */ - gettimeofday (&tv, NULL); - - if (ltv.tv_sec == 0 && ltv.tv_usec == 0) - ltv = tv; - - dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; - ltv = tv; - da = SLEWRATE*dt; - - /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ - switch (EquatorialCoordsRNP.s) - { - - /* #1 State is idle, update telesocpe at sidereal rate */ - case IPS_IDLE: - /* RA moves at sidereal, Dec stands still */ - currentRA += (SIDRATE*dt/15.); - - IDSetNumber(&EquatorialCoordsRNP, NULL); - - break; - - case IPS_BUSY: - /* slewing - nail it when both within one pulse @ SLEWRATE */ - nlocked = 0; - - dx = targetRA - currentRA; - - if (fabs(dx) <= da) - { - currentRA = targetRA; - nlocked++; - } - else if (dx > 0) - currentRA += da/15.; - else - currentRA -= da/15.; - - - dx = targetDEC - currentDEC; - if (fabs(dx) <= da) - { - currentDEC = targetDEC; - nlocked++; - } - else if (dx > 0) - currentDEC += da; - else - currentDEC -= da; - - if (nlocked == 2) - { - EquatorialCoordsRNP.s = IPS_OK; - IDSetNumber(&EquatorialCoordsRNP, "Now tracking"); - } else - IDSetNumber(&EquatorialCoordsRNP, NULL); - - break; - - case IPS_OK: - /* tracking */ - IDSetNumber(&EquatorialCoordsRNP, NULL); - break; - - case IPS_ALERT: - break; - } - -} - -void LX200GenericLegacy::getBasicData() -{ - - int err; - #ifdef HAVE_NOVA_H - struct tm *timep; - time_t ut; - time (&ut); - timep = gmtime (&ut); - strftime (TimeTP.tp[0].text, strlen(TimeTP.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep); - - IDLog("PC UTC time is %s\n", TimeTP.tp[0].text); - #endif - - getAlignment(); - - checkLX200Format(fd); - - if ( (err = getTimeFormat(fd, &timeFormat)) < 0) - IDMessage(thisDevice, "Failed to retrieve time format from device."); - else - { - timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM; - // We always do 24 hours - if (timeFormat != LX200_24) - err = toggleTimeFormat(fd); - } -// wildi proposal - if ( (err = getLX200RA(fd, &targetRA)) < 0 || (err = getLX200DEC(fd, &targetDEC)) < 0) - { - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP, NULL); - handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); - return; - } - - if (fault) - correctFault(); - -// getLX200RA(fd, &targetRA); -// getLX200DEC(fd, &targetDEC); - - EquatorialCoordsRNP.np[0].value = targetRA; - EquatorialCoordsRNP.np[1].value = targetDEC; - - EquatorialCoordsRNP.s = IPS_OK; - IDSetNumber (&EquatorialCoordsRNP, NULL); - - SiteNameT[0].text = new char[64]; - - if ( (err = getSiteName(fd, SiteNameT[0].text, currentSiteNum)) < 0) - IDMessage(thisDevice, "Failed to get site name from device"); - else - IDSetText (&SiteNameTP, NULL); - - if ( (err = getTrackFreq(fd, &TrackFreqN[0].value)) < 0) - IDMessage(thisDevice, "Failed to get tracking frequency from device."); - else - IDSetNumber (&TrackingFreqNP, NULL); - - /*updateLocation(); - updateTime();*/ - -} - -int LX200GenericLegacy::handleCoordSet() -{ - - int err; - char syncString[256]; - char RAStr[32], DecStr[32]; - - switch (currentSet) - { - // Slew - case LX200_TRACK: - lastSet = LX200_TRACK; - if (EquatorialCoordsRNP.s == IPS_BUSY) - { - #ifdef INDI_DEBUG - IDLog("Aborting Slew\n"); - #endif - if (!simulation && abortSlew(fd) < 0) - { - AbortSlewSP.s = IPS_ALERT; - IDSetSwitch(&AbortSlewSP, NULL); - slewError(err); - return (-1); - } - - AbortSlewSP.s = IPS_OK; - EquatorialCoordsRNP.s = IPS_IDLE; - IDSetSwitch(&AbortSlewSP, "Slew aborted."); - IDSetNumber(&EquatorialCoordsRNP, NULL); - - if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) - { - MovementNSSP.s = MovementWESP.s = IPS_IDLE; - EquatorialCoordsRNP.s = IPS_IDLE; - IUResetSwitch(&MovementNSSP); - IUResetSwitch(&MovementWESP); - IUResetSwitch(&AbortSlewSP); - - IDSetSwitch(&MovementNSSP, NULL); - IDSetSwitch(&MovementWESP, NULL); - } - - // sleep for 100 mseconds - usleep(100000); - } - - if (!simulation && (err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */ - { - IDMessage(mydev "ERROR Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); - slewError(err); - return -1; - } - - EquatorialCoordsRNP.s = IPS_BUSY; - fs_sexa(RAStr, targetRA, 2, 3600); - fs_sexa(DecStr, targetDEC, 2, 3600); - IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); - #ifdef INDI_DEBUG - IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); - #endif - break; - - // Sync - case LX200_SYNC: - lastSet = LX200_SYNC; - - if (!simulation) - if ( ( err = Sync(fd, syncString) < 0) ) - { - EquatorialCoordsRNP.s = IPS_ALERT; - IDSetNumber(&EquatorialCoordsRNP , "Synchronization failed."); - return (-1); - } - - EquatorialCoordsRN[0].value = targetRA; - EquatorialCoordsRN[1].value = targetDEC; - EquatorialCoordsRNP.s = IPS_OK; - IDLog("Synchronization successful %s\n", syncString); - IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful."); - break; - - } - - return (0); - -} - -int LX200GenericLegacy::getOnSwitch(ISwitchVectorProperty *sp) -{ - for (int i=0; i < sp->nsp ; i++) - if (sp->sp[i].s == ISS_ON) - return i; - - return -1; -} - - -int LX200GenericLegacy::checkPower(ISwitchVectorProperty *sp) -{ - if (simulation) return 0; - - if (ConnectSP.s != IPS_OK) - { - if (!strcmp(sp->label, "")) - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name); - else - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label); - - sp->s = IPS_IDLE; - IDSetSwitch(sp, NULL); - return -1; - } - - return 0; -} - -int LX200GenericLegacy::checkPower(INumberVectorProperty *np) -{ - if (simulation) return 0; - - if (ConnectSP.s != IPS_OK) - { - if (!strcmp(np->label, "")) - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name); - else - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label); - - np->s = IPS_IDLE; - IDSetNumber(np, NULL); - return -1; - } - - return 0; - -} - -int LX200GenericLegacy::checkPower(ITextVectorProperty *tp) -{ - - if (simulation) return 0; - - if (ConnectSP.s != IPS_OK) - { - if (!strcmp(tp->label, "")) - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name); - else - IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label); - - tp->s = IPS_IDLE; - IDSetText(tp, NULL); - return -1; - } - - return 0; - -} - -void LX200GenericLegacy::connectTelescope() -{ - switch (ConnectSP.sp[0].s) - { - case ISS_ON: - - if (simulation) - { - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Simulated telescope is online."); - //updateTime(); - return; - } - - tty_disconnect(fd); // Close if already open - if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) - { - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text); - return; - } - if (check_lx200_connection(fd)) - { - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); - return; - } - - #ifdef INDI_DEBUG - IDLog("Telescope test successful.\n"); - #endif - - *((int *) UTCOffsetN[0].aux0) = 0; - ConnectSP.s = IPS_OK; - IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); - getBasicData(); - break; - - case ISS_OFF: - ConnectS[0].s = ISS_OFF; - ConnectS[1].s = ISS_ON; - ConnectSP.s = IPS_IDLE; - IDSetSwitch (&ConnectSP, "Telescope is offline."); - IDLog("Telescope is offline."); - tty_disconnect(fd); - break; - - } - -} - -void LX200GenericLegacy::slewError(int slewCode) -{ - EquatorialCoordsRNP.s = IPS_ALERT; - - if (slewCode == 1) - IDSetNumber(&EquatorialCoordsRNP, "Object below horizon."); - else if (slewCode == 2) - IDSetNumber(&EquatorialCoordsRNP, "Object below the minimum elevation limit."); - else - IDSetNumber(&EquatorialCoordsRNP, "Slew failed."); - -} - -void LX200GenericLegacy::getAlignment() -{ - - if (ConnectSP.s != IPS_OK) - return; - - signed char align = ACK(fd); - if (align < 0) - { - IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment."); - return; - } - - AlignmentS[0].s = ISS_OFF; - AlignmentS[1].s = ISS_OFF; - AlignmentS[2].s = ISS_OFF; - - switch (align) - { - case 'P': AlignmentS[0].s = ISS_ON; - break; - case 'A': AlignmentS[1].s = ISS_ON; - break; - case 'L': AlignmentS[2].s = ISS_ON; - break; - } - - AlignmentSw.s = IPS_OK; - IDSetSwitch (&AlignmentSw, NULL); - IDLog("ACK success %c\n", align); -} - -void LX200GenericLegacy::enableSimulation(bool enable) -{ - simulation = enable; - - if (simulation) - IDLog("Warning: Simulation is activated.\n"); - else - IDLog("Simulation is disabled.\n"); -} - -void LX200GenericLegacy::updateTime() -{ - #ifdef HAVE_NOVA_H - char cdate[32]; - double ctime; - int h, m, s, lx200_utc_offset=0; - int day, month, year, result; - struct tm ltm; - struct tm utm; - time_t time_epoch; - - if (simulation) - { - sprintf(TimeT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30); - IDLog("Telescope ISO date and time: %s\n", TimeT[0].text); - IDSetText(&TimeTP, NULL); - return; - } - - getUTCOffset(fd, &lx200_utc_offset); - - // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition. - UTCOffsetN[0].value = lx200_utc_offset*-1; - - // We got a valid value for UTCOffset now - *((int *) UTCOffsetN[0].aux0) = 1; - - #ifdef INDI_DEBUG - IDLog("Telescope TimeT Offset: %g\n", UTCOffsetN[0].value); - #endif - - getLocalTime24(fd, &ctime); - getSexComponents(ctime, &h, &m, &s); - - if ( (result = getSDTime(fd, &SDTimeN[0].value)) < 0) - IDMessage(thisDevice, "Failed to retrieve sidereal time from device."); - - getCalenderDate(fd, cdate); - result = sscanf(cdate, "%d/%d/%d", &year, &month, &day); - if (result != 3) return; - - // Let's fill in the local time - ltm.tm_sec = s; - ltm.tm_min = m; - ltm.tm_hour = h; - ltm.tm_mday = day; - ltm.tm_mon = month - 1; - ltm.tm_year = year - 1900; - - // Get time epoch - time_epoch = mktime(<m); - - // Convert to TimeT - time_epoch -= (int) (UTCOffsetN[0].value * 60.0 * 60.0); - - // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time) - localtime_r(&time_epoch, &utm); - - /* Format it into ISO 8601 */ - strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm); - IUSaveText(&TimeT[0], cdate); - - #ifdef INDI_DEBUG - IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s); - IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value); - IDLog("Telescope UTC Time: %s\n", TimeT[0].text); - #endif - - // Let's send everything to the client - IDSetText(&TimeTP, NULL); - IDSetNumber(&SDTimeNP, NULL); - IDSetNumber(&UTCOffsetNP, NULL); - #endif - -} - -void LX200GenericLegacy::updateLocation() -{ - - int dd = 0, mm = 0, err = 0; - - if (simulation) - return; - - if ( (err = getSiteLatitude(fd, &dd, &mm)) < 0) - IDMessage(thisDevice, "Failed to get site latitude from device."); - else - { - if (dd > 0) - geoNP.np[0].value = dd + mm/60.0; - else - geoNP.np[0].value = dd - mm/60.0; - - IDLog("Autostar Latitude: %d:%d\n", dd, mm); - IDLog("INDI Latitude: %g\n", geoNP.np[0].value); - } - - if ( (err = getSiteLongitude(fd, &dd, &mm)) < 0) - IDMessage(thisDevice, "Failed to get site longitude from device."); - else - { - if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm/60.0); - else geoNP.np[1].value = (dd - mm/60.0) * -1.0; - - IDLog("Autostar Longitude: %d:%d\n", dd, mm); - IDLog("INDI Longitude: %g\n", geoNP.np[1].value); - } - - IDSetNumber (&geoNP, NULL); - -} - diff -Nru libindi-1.0.0/drivers/telescope/lx200genericlegacy.h libindi-1.1.0/drivers/telescope/lx200genericlegacy.h --- libindi-1.0.0/drivers/telescope/lx200genericlegacy.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200genericlegacy.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/* - LX200 Generic - Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -*/ - -#ifndef LX200GenericLegacy_H -#define LX200GenericLegacy_H - -#include "indidevapi.h" -#include "indicom.h" - -#define POLLMS 1000 /* poll period, ms */ -#define mydev "LX200 Generic" /* The device name */ - -class LX200GenericLegacy -{ - public: - LX200GenericLegacy(); - virtual ~LX200GenericLegacy(); - - virtual void ISGetProperties (const char *dev); - virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual void ISSnoopDevice (XMLEle *root); - virtual void ISPoll (); - virtual void getBasicData(); - - int checkPower(INumberVectorProperty *np); - int checkPower(ISwitchVectorProperty *sp); - int checkPower(ITextVectorProperty *tp); - virtual void handleError(ISwitchVectorProperty *svp, int err, const char *msg); - virtual void handleError(INumberVectorProperty *nvp, int err, const char *msg); - virtual void handleError(ITextVectorProperty *tvp, int err, const char *msg); - bool isTelescopeOn(void); - virtual void connectTelescope(); - void slewError(int slewCode); - void getAlignment(); - int handleCoordSet(); - int getOnSwitch(ISwitchVectorProperty *sp); - void setCurrentDeviceName(const char * devName); - void correctFault(); - void enableSimulation(bool enable); - void updateTime(); - void updateLocation(); - void mountSim(); - - static void updateFocusTimer(void *p); - static void guideTimeout(void *p); - int fd; - int GuideNSTID; - int GuideWETID; - - protected: - int timeFormat; - int currentSiteNum; - int trackingMode; - - double JD; - double lastRA; - double lastDEC; - bool fault; - bool simulation; - char thisDevice[64]; - int currentSet; - int lastSet; - double targetRA, targetDEC; - -}; - -void changeLX200GenericLegacyDeviceName(const char * newName); -void changeAllDeviceNames(const char *newName); - -#endif diff -Nru libindi-1.0.0/drivers/telescope/lx200gps.cpp libindi-1.1.0/drivers/telescope/lx200gps.cpp --- libindi-1.0.0/drivers/telescope/lx200gps.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200gps.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -83,6 +83,7 @@ IUFillNumber(&OTATempN[0], "Temp", "", "%03g", -200.0, 500.0, 0.0, 0); IUFillNumberVector(&OTATempNP, OTATempN, 1, getDeviceName(), "OTA Temp (C)", "", GPS_TAB, IP_RO, 0, IPS_IDLE); + return true; } void LX200GPS::ISGetProperties (const char *dev) @@ -375,3 +376,12 @@ DEBUG(INDI::Logger::DBG_SESSION , "Time updated, updating planetary data..."); return true; } + + bool LX200GPS::UnPark() + { + initTelescope(PortFD); + + TrackState = SCOPE_IDLE; + + return true; + } diff -Nru libindi-1.0.0/drivers/telescope/lx200gps.h libindi-1.1.0/drivers/telescope/lx200gps.h --- libindi-1.0.0/drivers/telescope/lx200gps.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/lx200gps.h 2015-09-06 13:17:35.000000000 +0000 @@ -37,6 +37,9 @@ virtual bool updateTime(ln_date *utc, double utc_offset); protected: + + virtual bool UnPark(); + ISwitchVectorProperty GPSPowerSP; ISwitch GPSPowerS[2]; diff -Nru libindi-1.0.0/drivers/telescope/magellan1.cpp libindi-1.1.0/drivers/telescope/magellan1.cpp --- libindi-1.0.0/drivers/telescope/magellan1.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/magellan1.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -149,7 +149,6 @@ fd = -1; // Children call parent routines, this is the default - IDLog("INDI Library v%g\n", INDI_LIBV); IDLog("Initializing from MAGELLAN device...\n"); IDLog("Driver Version: 2011-07-28\n"); } diff -Nru libindi-1.0.0/drivers/telescope/skycommander.c libindi-1.1.0/drivers/telescope/skycommander.c --- libindi-1.0.0/drivers/telescope/skycommander.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/skycommander.c 2015-09-06 13:17:35.000000000 +0000 @@ -32,11 +32,16 @@ #include "indicom.h" #include "lx200driver.h" +#ifndef _WIN32 +#include +#endif + #define mydev "Sky Commander" #define BASIC_GROUP "Main Control" #define POLLMS 1000 #define currentRA eq[0].value #define currentDEC eq[1].value +#define SKYCOMMANDER_TIMEOUT 5 static void ISPoll(void *); static void ISInit(void); @@ -137,6 +142,35 @@ INDI_UNUSED(root); } +int updateSkyCommanderCoord(int fd, double *ra, double *dec) +{ + char coords[16]; + char CR[1] = { (char) 0x0D }; + float RA=0.0, DEC=0.0; + int error_type; + int nbytes_read=0; + + error_type = write(fd, CR, 1); + + error_type = tty_read(fd, coords, 16, SKYCOMMANDER_TIMEOUT, &nbytes_read); + /*read_ret = portRead(coords, 16, LX200_TIMEOUT);*/ + tcflush(fd, TCIFLUSH); + + nbytes_read = sscanf(coords, " %g %g", &RA, &DEC); + + if (nbytes_read < 2) + { + IDLog("Error in Sky commander number format [%s], exiting.\n", coords); + return error_type; + } + + *ra = RA; + *dec = DEC; + + return 0; + +} + void ISPoll (void *p) { p=p; diff -Nru libindi-1.0.0/drivers/telescope/skywatcherAPIMount.cpp libindi-1.1.0/drivers/telescope/skywatcherAPIMount.cpp --- libindi-1.0.0/drivers/telescope/skywatcherAPIMount.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/skywatcherAPIMount.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -97,6 +97,8 @@ cap.canPark = true; cap.canSync = true; cap.canAbort = true; + cap.hasLocation = true; + cap.hasTime = true; SetTelescopeCapability(&cap); } @@ -266,7 +268,7 @@ addConfigurationControl(); // Add alignment properties - InitProperties(this); + InitAlignmentProperties(this); // Force the alignment system to always be on getSwitch("ALIGNMENT_SUBSYSTEM_ACTIVE")->sp[0].s = ISS_ON; @@ -474,7 +476,7 @@ if(strcmp(dev,getDeviceName())==0) { // It is for us - ProcessBlobProperties(this, name, sizes, blobsizes, blobs, formats, names, n); + 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); @@ -485,7 +487,7 @@ if(strcmp(dev,getDeviceName())==0) { // It is for us - ProcessNumberProperties(this, name, values, names, n); + ProcessAlignmentNumberProperties(this, name, values, names, n); } // Pass it up the chain return INDI::Telescope::ISNewNumber(dev, name, values, names, n); @@ -496,7 +498,7 @@ if(strcmp(dev,getDeviceName())==0) { // It is for us - ProcessSwitchProperties(this, name, states, names, n); + ProcessAlignmentSwitchProperties(this, name, states, names, n); } // Pass it up the chain return INDI::Telescope::ISNewSwitch(dev, name, states, names, n); @@ -506,18 +508,18 @@ { if(strcmp(dev,getDeviceName())==0) { - ProcessTextProperties(this, name, texts, names, n); + ProcessAlignmentTextProperties(this, name, texts, names, n); } // Pass it up the chain return INDI::Telescope::ISNewText(dev, name, texts, names, n); } -bool SkywatcherAPIMount::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool SkywatcherAPIMount::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { DEBUG(DBG_SCOPE, "SkywatcherAPIMount::MoveNS"); - double speed = (dir == MOTION_NORTH) ? (LOW_SPEED_MARGIN / 2) : -(LOW_SPEED_MARGIN / 2); - const char *dirStr = (dir == MOTION_NORTH) ? "North" : "South"; + double speed = (dir == DIRECTION_NORTH) ? (LOW_SPEED_MARGIN / 2) : -(LOW_SPEED_MARGIN / 2); + const char *dirStr = (dir == DIRECTION_NORTH) ? "North" : "South"; switch (command) { @@ -535,12 +537,12 @@ return true; } -bool SkywatcherAPIMount::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool SkywatcherAPIMount::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { DEBUG(DBG_SCOPE, "SkywatcherAPIMount::MoveWE"); - double speed = (dir == MOTION_WEST) ? (LOW_SPEED_MARGIN / 2) : -(LOW_SPEED_MARGIN / 2); - const char *dirStr = (dir == MOTION_WEST) ? "West" : "East"; + double speed = (dir == DIRECTION_WEST) ? (LOW_SPEED_MARGIN / 2) : -(LOW_SPEED_MARGIN / 2); + const char *dirStr = (dir == DIRECTION_WEST) ? "West" : "East"; switch (command) { @@ -664,7 +666,7 @@ bool SkywatcherAPIMount::saveConfigItems(FILE *fp) { - SaveConfigProperties(fp); + SaveAlignmentConfigProperties(fp); return INDI::Telescope::saveConfigItems(fp); } @@ -937,6 +939,7 @@ // Start the timer if we need one // SetTimer(POLLMS); + return true; } else { @@ -950,6 +953,7 @@ deleteProperty(AxisTwoStateV.name); deleteProperty(AxisOneEncoderValuesV.name); deleteProperty(AxisTwoEncoderValuesV.name); + return true; } } diff -Nru libindi-1.0.0/drivers/telescope/skywatcherAPIMount.h libindi-1.1.0/drivers/telescope/skywatcherAPIMount.h --- libindi-1.0.0/drivers/telescope/skywatcherAPIMount.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/skywatcherAPIMount.h 2015-09-06 13:17:35.000000000 +0000 @@ -37,8 +37,8 @@ virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); virtual bool Park(); virtual bool ReadScopeStatus(); virtual bool saveConfigItems(FILE *fp); @@ -84,12 +84,12 @@ INumberVectorProperty AxisTwoEncoderValuesV; // Previous motion direction - typedef enum { PREVIOUS_NS_MOTION_NORTH = MOTION_NORTH, - PREVIOUS_NS_MOTION_SOUTH = MOTION_SOUTH, + typedef enum { PREVIOUS_NS_MOTION_NORTH = DIRECTION_NORTH, + PREVIOUS_NS_MOTION_SOUTH = DIRECTION_SOUTH, PREVIOUS_NS_MOTION_UNKNOWN = -1} PreviousNSMotion_t; PreviousNSMotion_t PreviousNSMotion; - typedef enum { PREVIOUS_WE_MOTION_WEST = MOTION_WEST, - PREVIOUS_WE_MOTION_EAST = MOTION_EAST, + typedef enum { PREVIOUS_WE_MOTION_WEST = DIRECTION_WEST, + PREVIOUS_WE_MOTION_EAST = DIRECTION_EAST, PREVIOUS_WE_MOTION_UNKNOWN = -1} PreviousWEMotion_t; PreviousWEMotion_t PreviousWEMotion; diff -Nru libindi-1.0.0/drivers/telescope/synscanmount.cpp libindi-1.1.0/drivers/telescope/synscanmount.cpp --- libindi-1.0.0/drivers/telescope/synscanmount.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/synscanmount.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -96,6 +96,10 @@ cap.canPark = true; cap.canSync = false; + cap.canAbort = true; + cap.hasLocation = false; + cap.hasTime = false; + cap.nSlewRate=0; SetTelescopeCapability(&cap); } @@ -109,26 +113,6 @@ return "SynScan"; } -bool SynscanMount::initProperties() -{ - //if (isDebug()) - IDLog("Synscan::init_properties\n"); - - //setDeviceName("Synscan"); - INDI::Telescope::initProperties(); - - return true; -} -void SynscanMount::ISGetProperties (const char *dev) -{ - // First we let our parent class do it's thing - INDI::Telescope::ISGetProperties(dev); - - // Now we add anything that's specific to this telescope - // or we could just load from a skeleton file too - return; -} - bool SynscanMount::ReadScopeStatus() { char str[20]; diff -Nru libindi-1.0.0/drivers/telescope/synscanmount.h libindi-1.1.0/drivers/telescope/synscanmount.h --- libindi-1.0.0/drivers/telescope/synscanmount.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/synscanmount.h 2015-09-06 13:17:35.000000000 +0000 @@ -30,8 +30,8 @@ virtual ~SynscanMount(); // overrides of base class virtual functions - bool initProperties(); - void ISGetProperties (const char *dev); + //bool initProperties(); + //void ISGetProperties (const char *dev); const char *getDefaultName(); bool ReadScopeStatus(); diff -Nru libindi-1.0.0/drivers/telescope/telescope_simulator.cpp libindi-1.1.0/drivers/telescope/telescope_simulator.cpp --- libindi-1.0.0/drivers/telescope/telescope_simulator.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/telescope_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -87,7 +87,7 @@ } void ISSnoopDevice (XMLEle *root) { - INDI_UNUSED(root); + telescope_sim->ISSnoopDevice(root); } @@ -96,7 +96,6 @@ //ctor currentRA=0; currentDEC=90; - Parked=false; forceMeridianFlip = false; @@ -106,7 +105,10 @@ cap.canPark = true; cap.canSync = true; - cap.canAbort = true; + cap.canAbort = true; + cap.hasLocation = true; + cap.hasTime = true; + cap.nSlewRate=4; SetTelescopeCapability(&cap); /* initialize random seed: */ @@ -115,7 +117,7 @@ ScopeSim::~ScopeSim() { - //dtor + } const char * ScopeSim::getDefaultName() @@ -134,13 +136,13 @@ IUFillNumberVector(&EqPENV,EqPEN,2,getDeviceName(),"EQUATORIAL_PE","Periodic Error",MOTION_TAB,IP_RO,60,IPS_IDLE); /* Enable client to manually add periodic error northward or southward for simulation purposes */ - IUFillSwitch(&PEErrNSS[MOTION_NORTH], "PE_N", "North", ISS_OFF); - IUFillSwitch(&PEErrNSS[MOTION_SOUTH], "PE_S", "South", ISS_OFF); + IUFillSwitch(&PEErrNSS[DIRECTION_NORTH], "PE_N", "North", ISS_OFF); + IUFillSwitch(&PEErrNSS[DIRECTION_SOUTH], "PE_S", "South", ISS_OFF); IUFillSwitchVector(&PEErrNSSP, PEErrNSS, 2, getDeviceName(),"PE_NS", "PE N/S", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); /* Enable client to manually add periodic error westward or easthward for simulation purposes */ - IUFillSwitch(&PEErrWES[MOTION_WEST], "PE_W", "West", ISS_OFF); - IUFillSwitch(&PEErrWES[MOTION_EAST], "PE_E", "East", ISS_OFF); + IUFillSwitch(&PEErrWES[DIRECTION_WEST], "PE_W", "West", ISS_OFF); + IUFillSwitch(&PEErrWES[DIRECTION_EAST], "PE_E", "East", ISS_OFF); IUFillSwitchVector(&PEErrWESP, PEErrWES, 2, getDeviceName(),"PE_WE", "PE W/E", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); /* How fast do we guide compared to sidereal rate */ @@ -148,6 +150,12 @@ IUFillNumber(&GuideRateN[DEC_AXIS], "GUIDE_RATE_NS", "N/S Rate", "%g", 0, 1, 0.1, 0.3); IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0, IPS_IDLE); + IUFillSwitch(&SlewRateS[SLEW_GUIDE], "SLEW_GUIDE", "Guide", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_CENTERING], "SLEW_CENTERING", "Centering", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_FIND], "SLEW_FIND", "Find", ISS_OFF); + IUFillSwitch(&SlewRateS[SLEW_MAX], "SLEW_MAX", "Max", ISS_ON); + IUFillSwitchVector(&SlewRateSP, SlewRateS, 4, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + // Let's simulate it to be an F/7.5 120mm telescope ScopeParametersN[0].value = 120; ScopeParametersN[1].value = 900; @@ -156,6 +164,8 @@ TrackState=SCOPE_IDLE; + SetParkDataType(PARK_RA_DEC); + initGuiderProperties(getDeviceName(), MOTION_TAB); /* Add debug controls so we may debug driver if necessary */ @@ -181,6 +191,7 @@ defineSwitch(&PEErrWESP); } + return; } @@ -197,6 +208,24 @@ defineSwitch(&PEErrNSSP); defineSwitch(&PEErrWESP); + double HA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys()); + double DEC = 90; + + if (InitPark()) + { + // If loading parking data is successful, we just set the default parking values. + SetAxis1ParkDefault(HA); + SetAxis2ParkDefault(DEC); + } + else + { + // Otherwise, we set all parking data to default in case no parking data is found. + SetAxis1Park(HA); + SetAxis2Park(DEC); + SetAxis1ParkDefault(HA); + SetAxis2ParkDefault(DEC); + } + } else { @@ -217,7 +246,7 @@ if(isConnected()) return true; - rc=Connect(PortT[0].text); + rc=Connect(PortT[0].text, atoi(IUFindOnSwitch(&BaudRateSP)->name)); if(rc) SetTimer(POLLMS); @@ -225,8 +254,9 @@ return rc; } -bool ScopeSim::Connect(char *port) +bool ScopeSim::Connect(const char *port, uint16_t baud) { + DEBUGF(INDI::Logger::DBG_SESSION, "Simulating connecting to port %s with speed %d", port, baud); DEBUG(INDI::Logger::DBG_SESSION, "Telescope simulator is online."); return true; } @@ -269,32 +299,58 @@ else da_dec = FINE_SLEW_RATE *dt; - switch (MovementNSSP.s) + if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { - case IPS_BUSY: - if (MovementNSS[MOTION_NORTH].s == ISS_ON) - currentDEC += da_dec; - else if (MovementNSS[MOTION_SOUTH].s == ISS_ON) - currentDEC -= da_dec; + int rate = IUFindOnSwitchIndex(&SlewRateSP); - NewRaDec(currentRA, currentDEC); - return true; - break; - } + switch (rate) + { + case SLEW_GUIDE: + da_ra = FINE_SLEW_RATE *dt*0.05; + da_dec = FINE_SLEW_RATE *dt*0.05; + break; - switch (MovementWESP.s) - { - case IPS_BUSY: + case SLEW_CENTERING: + da_ra = FINE_SLEW_RATE *dt*.1; + da_dec = FINE_SLEW_RATE *dt*.1; + break; - if (MovementWES[MOTION_WEST].s == ISS_ON) - currentRA += da_ra/15.; - else if (MovementWES[MOTION_EAST].s == ISS_ON) - currentRA -= da_ra/15.; + case SLEW_FIND: + da_ra = SLEW_RATE *dt; + da_dec = SLEW_RATE *dt; + break; + + default: + da_ra = GOTO_RATE *dt; + da_dec = GOTO_RATE *dt; + break; + } + + switch (MovementNSSP.s) + { + case IPS_BUSY: + if (MovementNSS[DIRECTION_NORTH].s == ISS_ON) + currentDEC += da_dec; + else if (MovementNSS[DIRECTION_SOUTH].s == ISS_ON) + currentDEC -= da_dec; + + break; + } + + switch (MovementWESP.s) + { + case IPS_BUSY: + + if (MovementWES[DIRECTION_WEST].s == ISS_ON) + currentRA += da_ra/15.; + else if (MovementWES[DIRECTION_EAST].s == ISS_ON) + currentRA -= da_ra/15.; + + break; + } NewRaDec(currentRA, currentDEC); return true; - break; - } /* Process per current state. We check the state of EQUATORIAL_EOD_COORDS_REQUEST and act acoordingly */ @@ -373,18 +429,18 @@ } else { - TrackState = SCOPE_PARKED; - IUResetSwitch(&ParkSP); - ParkSP.s=IPS_OK; - IDSetSwitch(&ParkSP,NULL); - EqNP.s = IPS_IDLE; - DEBUG(INDI::Logger::DBG_SESSION,"Telescope parked successfully."); + SetParked(true); + EqNP.s = IPS_IDLE; } } break; case SCOPE_IDLE: + currentRA += (SID_RATE*dt)/15.0; + currentRA = range24(currentRA); + break; + case SCOPE_TRACKING: /* tracking */ @@ -423,6 +479,12 @@ else guiderNSTarget[ns_guide_dir] = 0; + if (guiderNSTarget[ns_guide_dir] == 0) + { + GuideNSNP.s = IPS_IDLE; + IDSetNumber(&GuideNSNP, NULL); + } + EqPEN[DEC_AXIS].value += dec_guide_dt; } @@ -437,6 +499,12 @@ else guiderEWTarget[we_guide_dir] = 0; + if (guiderEWTarget[we_guide_dir] == 0) + { + GuideWENP.s = IPS_IDLE; + IDSetNumber(&GuideWENP, NULL); + } + EqPEN[RA_AXIS].value += ra_guide_dt; } @@ -467,11 +535,11 @@ { last_dx=dx; last_dy=dy; - DEBUGF(INDI::Logger::DBG_DEBUG, "dt is %g\n", dt); - DEBUGF(INDI::Logger::DBG_DEBUG, "RA Displacement (%c%s) %s -- %s of target RA %s\n", dx >= 0 ? '+' : '-', RA_DISP, RA_PE, (EqPEN[RA_AXIS].value - targetRA) > 0 ? "East" : "West", RA_TARGET); - DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Displacement (%c%s) %s -- %s of target RA %s\n", dy >= 0 ? '+' : '-', DEC_DISP, DEC_PE, (EqPEN[DEC_AXIS].value - targetDEC) > 0 ? "North" : "South", DEC_TARGET); - DEBUGF(INDI::Logger::DBG_DEBUG, "RA Guide Correction (%g) %s -- Direction %s\n", ra_guide_dt, RA_GUIDE, ra_guide_dt > 0 ? "East" : "West"); - DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Guide Correction (%g) %s -- Direction %s\n", dec_guide_dt, DEC_GUIDE, dec_guide_dt > 0 ? "North" : "South"); + //DEBUGF(INDI::Logger::DBG_DEBUG, "dt is %g\n", dt); + DEBUGF(INDI::Logger::DBG_DEBUG, "RA Displacement (%c%s) %s -- %s of target RA %s", dx >= 0 ? '+' : '-', RA_DISP, RA_PE, (EqPEN[RA_AXIS].value - targetRA) > 0 ? "East" : "West", RA_TARGET); + DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Displacement (%c%s) %s -- %s of target RA %s", dy >= 0 ? '+' : '-', DEC_DISP, DEC_PE, (EqPEN[DEC_AXIS].value - targetDEC) > 0 ? "North" : "South", DEC_TARGET); + DEBUGF(INDI::Logger::DBG_DEBUG, "RA Guide Correction (%g) %s -- Direction %s", ra_guide_dt, RA_GUIDE, ra_guide_dt > 0 ? "East" : "West"); + DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Guide Correction (%g) %s -- Direction %s", dec_guide_dt, DEC_GUIDE, dec_guide_dt > 0 ? "North" : "South"); } if (ns_guide_dir != -1 || we_guide_dir != -1) @@ -496,7 +564,6 @@ bool ScopeSim::Goto(double r,double d) { - //IDLog("ScopeSim Goto\n"); targetRA=r; targetDEC=d; char RAStr[64], DecStr[64]; @@ -529,7 +596,6 @@ } } - Parked=false; TrackState = SCOPE_SLEWING; EqNP.s = IPS_BUSY; @@ -540,6 +606,7 @@ bool ScopeSim::Sync(double ra, double dec) { + currentRA = ra; currentDEC = dec; @@ -560,14 +627,19 @@ bool ScopeSim::Park() { - targetRA=0; - targetDEC=90; - Parked=true; + targetRA= GetAxis1Park(); + targetDEC= GetAxis2Park(); TrackState = SCOPE_PARKING; DEBUG(INDI::Logger::DBG_SESSION,"Parking telescope in progress..."); return true; } +bool ScopeSim::UnPark() +{ + SetParked(false); + return true; +} + bool ScopeSim::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device @@ -599,13 +671,25 @@ { if(strcmp(dev,getDeviceName())==0) { + // Slew mode + if (!strcmp (name, SlewRateSP.name)) + { + + if (IUUpdateSwitch(&SlewRateSP, states, names, n) < 0) + return false; + + SlewRateSP.s = IPS_OK; + IDSetSwitch(&SlewRateSP, NULL); + return true; + } + if(strcmp(name,"PE_NS")==0) { IUUpdateSwitch(&PEErrNSSP,states,names,n); PEErrNSSP.s = IPS_OK; - if (PEErrNSS[MOTION_NORTH].s == ISS_ON) + if (PEErrNSS[DIRECTION_NORTH].s == ISS_ON) { EqPEN[DEC_AXIS].value += SID_RATE * GuideRateN[DEC_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulating PE in NORTH direction for value of %g", SID_RATE); @@ -629,7 +713,7 @@ PEErrWESP.s = IPS_OK; - if (PEErrWES[MOTION_WEST].s == ISS_ON) + if (PEErrWES[DIRECTION_WEST].s == ISS_ON) { EqPEN[RA_AXIS].value -= SID_RATE/15. * GuideRateN[RA_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulator PE in WEST direction for value of %g", SID_RATE); @@ -695,64 +779,60 @@ } -bool ScopeSim::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool ScopeSim::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { + if (TrackState == SCOPE_PARKED) + { + DEBUG(INDI::Logger::DBG_ERROR, "Please unpark the mount before issuing any motion commands."); + return false; + } + return true; } -bool ScopeSim::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool ScopeSim::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { + if (TrackState == SCOPE_PARKED) + { + DEBUG(INDI::Logger::DBG_ERROR, "Please unpark the mount before issuing any motion commands."); + return false; + } + return true; } -bool ScopeSim::GuideNorth(float ms) +IPState ScopeSim::GuideNorth(float ms) { guiderNSTarget[GUIDE_NORTH] = ms; guiderNSTarget[GUIDE_SOUTH] = 0; - return true; + return IPS_BUSY; } -bool ScopeSim::GuideSouth(float ms) +IPState ScopeSim::GuideSouth(float ms) { guiderNSTarget[GUIDE_SOUTH] = ms; guiderNSTarget[GUIDE_NORTH] = 0; - return true; + return IPS_BUSY; } -bool ScopeSim::GuideEast(float ms) +IPState ScopeSim::GuideEast(float ms) { guiderEWTarget[GUIDE_EAST] = ms; guiderEWTarget[GUIDE_WEST] = 0; - return true; + return IPS_BUSY; } -bool ScopeSim::GuideWest(float ms) +IPState ScopeSim::GuideWest(float ms) { guiderEWTarget[GUIDE_WEST] = ms; guiderEWTarget[GUIDE_EAST] = 0; - return true; + return IPS_BUSY; } -double ScopeSim::range24(double r) -{ - double res = r; - while (res<0.0) res+=24.0; - while (res>24.0) res-=24.0; - return res; -} - -double ScopeSim::range360(double r) -{ - double res = r; - while (res<0.0) res+=360.0; - while (res>360.0) res-=360.0; - return res; -} - bool ScopeSim::updateLocation(double latitude, double longitude, double elevation) { INDI_UNUSED(elevation); @@ -763,6 +843,24 @@ lnobserver.lng -= 360; lnobserver.lat = latitude; - DEBUGF(INDI::Logger::DBG_SESSION,"Located updated: long = %g lat = %g", lnobserver.lng, lnobserver.lat); + DEBUGF(INDI::Logger::DBG_SESSION,"Location updated: Longitude (%g) Latitude (%g)", lnobserver.lng, lnobserver.lat); return true; } + +void ScopeSim::SetCurrentPark() +{ + SetAxis1Park(currentRA); + SetAxis2Park(currentDEC); +} + +void ScopeSim::SetDefaultPark() +{ + // By default set RA to HA + SetAxis1Park(ln_get_apparent_sidereal_time(ln_get_julian_from_sys())); + + // Set DEC to 90 or -90 depending on the hemisphere + SetAxis2Park( (LocationN[LOCATION_LATITUDE].value > 0) ? 90 : -90); + +} + + diff -Nru libindi-1.0.0/drivers/telescope/telescope_simulator.h libindi-1.1.0/drivers/telescope/telescope_simulator.h --- libindi-1.0.0/drivers/telescope/telescope_simulator.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/telescope/telescope_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -3,8 +3,7 @@ #include "indibase/indiguiderinterface.h" #include "indibase/inditelescope.h" - - +#include "indicontroller.h" class ScopeSim : public INDI::Telescope, public INDI::GuiderInterface { @@ -14,35 +13,38 @@ virtual const char *getDefaultName(); virtual bool Connect(); - virtual bool Connect(char *); + virtual bool Connect(const char *port, uint16_t baud); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual bool initProperties(); virtual void ISGetProperties (const char *dev); virtual bool updateProperties(); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); protected: - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); virtual bool Abort(); - virtual bool GuideNorth(float ms); - virtual bool GuideSouth(float ms); - virtual bool GuideEast(float ms); - virtual bool GuideWest(float ms); + virtual IPState GuideNorth(float ms); + virtual IPState GuideSouth(float ms); + virtual IPState GuideEast(float ms); + virtual IPState GuideWest(float ms); virtual bool updateLocation(double latitude, double longitude, double elevation); bool Goto(double,double); bool Park(); + bool UnPark(); bool Sync(double ra, double dec); - private: + // Parking + virtual void SetCurrentPark(); + virtual void SetDefaultPark(); - double range24(double r); - double range360(double r); + private: double currentRA; double currentDEC; @@ -53,7 +55,6 @@ ln_hrz_posn lnaltaz; bool forceMeridianFlip; unsigned int DBG_SCOPE; - bool Parked; double guiderEWTarget[2]; double guiderNSTarget[2]; diff -Nru libindi-1.0.0/drivers/video/indi_lpi.cpp libindi-1.1.0/drivers/video/indi_lpi.cpp --- libindi-1.0.0/drivers/video/indi_lpi.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/indi_lpi.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/* - Meade LPI Experimental driver - Copyright (C) 2005 by 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 "v4ldriver.h" - -class Meade_LPI : public V4L_Driver -{ - public: - Meade_LPI(); - ~Meade_LPI(); - - #ifdef HAVE_LINUX_VIDEODEV2_H - void connectCamera(void); - #endif - -}; - -Meade_LPI::Meade_LPI() : V4L_Driver() -{ -} - -Meade_LPI::~Meade_LPI() -{ -} - -#ifdef HAVE_LINUX_VIDEODEV2_H -void Meade_LPI::connectCamera() -{ - char errmsg[ERRMSGSIZ]; - - switch (PowerS[0].s) - { - case ISS_ON: - if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_SBGGR8, 352, 288) < 0) - { - PowerSP.s = IPS_IDLE; - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - IDSetSwitch(&PowerSP, "Error: unable to open device"); - IDLog("Error: %s\n", errmsg); - return; - } - - /* Sucess! */ - PowerS[0].s = ISS_ON; - PowerS[1].s = ISS_OFF; - PowerSP.s = IPS_OK; - IDSetSwitch(&PowerSP, "Meade LPI is online. Retrieving basic data."); - - v4l_base->registerCallback(newFrame, this); - - V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1); - - IDLog("Meade LPI is online. Retrieving basic data.\n"); - getBasicData(); - - break; - - case ISS_OFF: - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - PowerSP.s = IPS_IDLE; - - free(V4LFrame->compressedFrame); - V4LFrame->compressedFrame = NULL; - v4l_base->disconnectCam(true); - - IDSetSwitch(&PowerSP, "Meade LPI is offline."); - - break; - } - -} -#endif - -Meade_LPI *MainCam = NULL; /* Main and only camera */ - -/* send client definitions of all properties */ -void ISInit() -{ - if (MainCam == NULL) - { - MainCam = new Meade_LPI(); - MainCam->initProperties("Meade LPI"); - MainCam->initCamBase(); - } -} - -void ISGetProperties (const char *dev) -{ - ISInit(); - - MainCam->ISGetProperties(dev); -} - - -void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewSwitch(dev, name, states, names, n); -} - -void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewText(dev, name, texts, names, n); -} - - -void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewNumber(dev, name, values, names, n); -} - -void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) -{ - INDI_UNUSED(dev); - INDI_UNUSED(name); - INDI_UNUSED(sizes); - INDI_UNUSED(blobsizes); - INDI_UNUSED(blobs); - INDI_UNUSED(formats); - INDI_UNUSED(names); - INDI_UNUSED(n); -} -void ISSnoopDevice (XMLEle *root) -{ - INDI_UNUSED(root); -} - - diff -Nru libindi-1.0.0/drivers/video/indi_philips.cpp libindi-1.1.0/drivers/video/indi_philips.cpp --- libindi-1.0.0/drivers/video/indi_philips.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/indi_philips.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -#if 0 - V4L INDI Driver - INDI Interface for V4L devices (Philips) - Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#include "v4lphilips.h" - -V4L_Philips *MainCam = NULL; /* Main and only camera */ - -/* send client definitions of all properties */ -void ISInit() -{ - if (MainCam == NULL) - { - MainCam = new V4L_Philips(); - MainCam->initProperties("Philips Webcam"); - MainCam->initCamBase(); - } -} - -void ISGetProperties (const char *dev) -{ - ISInit(); - - MainCam->ISGetProperties(dev); -} - - -void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewSwitch(dev, name, states, names, n); -} - -void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewText(dev, name, texts, names, n); -} - - -void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewNumber(dev, name, values, names, n); -} - -void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {} -void ISSnoopDevice (XMLEle *root) {} diff -Nru libindi-1.0.0/drivers/video/indi_v4l.cpp libindi-1.1.0/drivers/video/indi_v4l.cpp --- libindi-1.0.0/drivers/video/indi_v4l.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/indi_v4l.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -#if 0 - V4L INDI Driver - INDI Interface for V4L devices - Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#include "v4ldriver.h" - -V4L_Driver *MainCam = NULL; /* Main and only camera */ - -/* send client definitions of all properties */ -void ISInit() -{ - if (MainCam == NULL) - { - MainCam = new V4L_Driver(); - MainCam->initProperties("Legacy Video4Linux"); - MainCam->initCamBase(); - } -} - -void ISGetProperties (const char *dev) -{ - ISInit(); - - MainCam->ISGetProperties(dev); -} - - -void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewSwitch(dev, name, states, names, n); -} - -void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewText(dev, name, texts, names, n); -} - - -void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - - ISInit(); - - MainCam->ISNewNumber(dev, name, values, names, n); -} - -void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {} -void ISSnoopDevice (XMLEle *root) {} diff -Nru libindi-1.0.0/drivers/video/v4l2driver.cpp libindi-1.1.0/drivers/video/v4l2driver.cpp --- libindi-1.0.0/drivers/video/v4l2driver.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4l2driver.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -23,6 +23,10 @@ V4L2_Driver::V4L2_Driver() { + //sigevent sevp; + //struct itimerspec fpssettings; + struct itimerval fpssettings; + allocateBuffers(); divider = 128.; @@ -41,13 +45,32 @@ cap.hasBayer = false; SetCCDCapability(&cap); + + is_capturing = false; + is_exposing = false; + is_streaming = false; + is_recording = false; Options=NULL; v4loptions=0; AbsExposureN=NULL; ManualExposureSP=NULL; - stackMode=0; + stackMode=STACK_NONE; + + // Timer + // now use BSD setimer to avoi librt dependency + //sevp.sigev_notify=SIGEV_NONE; + //timer_create(CLOCK_MONOTONIC, &sevp, &fpstimer); + //fpssettings.it_interval.tv_sec=24*3600; + //fpssettings.it_interval.tv_nsec=0; + //fpssettings.it_value=fpssettings.it_interval; + //timer_settime(fpstimer, 0, &fpssettings, NULL); + fpssettings.it_interval.tv_sec=24*3600; + fpssettings.it_interval.tv_usec=0; + fpssettings.it_value=fpssettings.it_interval; + signal(SIGALRM, SIG_IGN); //portable + setitimer(ITIMER_REAL, &fpssettings, NULL); lx=new Lx(); v4l2_record=new V4L2_Record(); @@ -75,22 +98,39 @@ IUFillTextVector(&PortTP, PortT, NARRAY(PortT), getDeviceName(), "DEVICE_PORT", "Ports", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); /* Video Stream */ - IUFillSwitch(&StreamS[0], "ON", "Stream On", ISS_OFF); - IUFillSwitch(&StreamS[1], "OFF", "Stream Off", ISS_ON); - IUFillSwitchVector(&StreamSP, StreamS, NARRAY(StreamS), getDeviceName(), "VIDEO_STREAM", "Video Stream", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - /* Image type */ - IUFillSwitch(&ImageTypeS[0], "Grey", "", ISS_ON); - IUFillSwitch(&ImageTypeS[1], "Color", "", ISS_OFF); - IUFillSwitchVector(&ImageTypeSP, ImageTypeS, NARRAY(ImageTypeS), getDeviceName(), "Image Type", "", IMAGE_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + IUFillSwitch(&StreamS[0], "STREAM_ON", "Stream On", ISS_OFF); + IUFillSwitch(&StreamS[1], "STREAM_OFF", "Stream Off", ISS_ON); + IUFillSwitchVector(&StreamSP, StreamS, NARRAY(StreamS), getDeviceName(), "CCD_VIDEO_STREAM", "Video Stream", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + /* Stream Rate divisor */ + IUFillNumber(&StreamOptionsN[0], "STREAM_RATE", "Rate Divisor", "%3.0f", 1.0, 999.0, 1, 10); + IUFillNumberVector(&StreamOptionsNP, StreamOptionsN, NARRAY(StreamOptionsN), getDeviceName(), "STREAM_OPTIONS", "Streaming", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE); + + /* Measured FPS */ + IUFillNumber(&FpsN[0], "EST_FPS", "Instant.", "%3.2f", 0.0, 999.0, 0.0, 30); + IUFillNumber(&FpsN[1], "AVG_FPS", "Average (1 sec.)", "%3.2f", 0.0, 999.0, 0.0, 30); + IUFillNumberVector(&FpsNP, FpsN, NARRAY(FpsN), getDeviceName(), "FPS", "FPS", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE); + + /* Color space */ + IUFillSwitch(&ImageColorS[0], "CCD_COLOR_GRAY", "Gray", ISS_ON); + IUFillSwitch(&ImageColorS[1], "CCD_COLOR_RGB", "Color", ISS_OFF); + IUFillSwitchVector(&ImageColorSP, ImageColorS, NARRAY(ImageColorS), getDeviceName(), "CCD_COLOR_SPACE", "Image Type", IMAGE_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + /* Image depth */ + IUFillSwitch(&ImageDepthS[0], "8 bits", "", ISS_ON); + IUFillSwitch(&ImageDepthS[1], "16 bits", "", ISS_OFF); + IUFillSwitchVector(&ImageDepthSP, ImageDepthS, NARRAY(ImageDepthS), getDeviceName(), "Image Depth", "", IMAGE_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Camera Name */ IUFillText(&camNameT[0], "Model", "", NULL); - IUFillTextVector(&camNameTP, camNameT, NARRAY(camNameT), getDeviceName(), "Camera Model", "", IMAGE_INFO_TAB, IP_RO, 0, IPS_IDLE); + IUFillTextVector(&camNameTP, camNameT, NARRAY(camNameT), getDeviceName(), "Camera", "", IMAGE_INFO_TAB, IP_RO, 0, IPS_IDLE); /* Stacking Mode */ - IUFillSwitch(&StackModeS[0], "None", "", ISS_ON); - IUFillSwitch(&StackModeS[1], "Additive", "", ISS_OFF); + IUFillSwitch(&StackModeS[STACK_NONE], "None", "", ISS_ON); + IUFillSwitch(&StackModeS[STACK_MEAN], "Mean", "", ISS_OFF); + IUFillSwitch(&StackModeS[STACK_ADDITIVE], "Additive", "", ISS_OFF); + IUFillSwitch(&StackModeS[STACK_TAKE_DARK], "Take Dark", "", ISS_OFF); + IUFillSwitch(&StackModeS[STACK_RESET_DARK], "Reset Dark", "", ISS_OFF); IUFillSwitchVector(&StackModeSP, StackModeS, NARRAY(StackModeS), getDeviceName(), "Stack", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Drop Frames */ @@ -98,6 +138,9 @@ IUFillSwitch(&DropFrameS[1], "Off", "", ISS_ON); IUFillSwitchVector(&DropFrameSP, DropFrameS, NARRAY(DropFrameS), getDeviceName(), "Drop Frames", "", IMAGE_SETTINGS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + IUFillNumber(&FramestoDropN[0], "To drop", "", "%2.0f", 0, 99, 1, 1); + IUFillNumberVector(&FramestoDropNP, FramestoDropN, NARRAY(FramestoDropN), getDeviceName(), "Frames", "", IMAGE_SETTINGS_TAB, IP_RW, 60, IPS_IDLE); + stackMode=0; /* Inputs */ @@ -110,20 +153,39 @@ /* Frame Rate */ IUFillSwitchVector(&FrameRatesSP, NULL, 0, getDeviceName(), "V4L2_FRAMEINT_DISCRETE", "Frame Interval", CAPTURE_FORMAT, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumberVector(&FrameRateNP, NULL, 0, getDeviceName(), "V4L2_FRAMEINT_STEP", "Frame Interval", CAPTURE_FORMAT, IP_RW, 60, IPS_IDLE); + /* Capture Colorspace */ + IUFillText(&CaptureColorSpaceT[0], "Name", "", NULL); + IUFillText(&CaptureColorSpaceT[1], "YCbCr Encoding", "", NULL); + IUFillText(&CaptureColorSpaceT[2], "Quantization", "", NULL); + IUFillTextVector(&CaptureColorSpaceTP, CaptureColorSpaceT, NARRAY(CaptureColorSpaceT), getDeviceName(), "V4L2_COLORSPACE", "ColorSpace", IMAGE_INFO_TAB, IP_RO, 0, IPS_IDLE); + + /* Color Processing */ + IUFillSwitch(&ColorProcessingS[0], "Quantization", "", ISS_ON); + IUFillSwitch(&ColorProcessingS[1], "Color Conversion", "", ISS_OFF); + IUFillSwitch(&ColorProcessingS[2], "Linearization", "", ISS_OFF); + IUFillSwitchVector(&ColorProcessingSP, ColorProcessingS, NARRAY(ColorProcessingS), getDeviceName(), "V4L2_COLOR_PROCESSING", "Color Process", CAPTURE_FORMAT, IP_RW, ISR_NOFMANY, 0, IPS_IDLE); + /* V4L2 Settings */ IUFillNumberVector(&ImageAdjustNP, NULL, 0, getDeviceName(), "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); /* Record Frames */ /* File */ - IUFillText(&RecordFileT[0], "RECORD_FILE_NAME", "File name", "/tmp/indimovie.ser"); + IUFillText(&RecordFileT[0], "RECORD_FILE_DIR", "Dir.", "/tmp/indi__D_"); + IUFillText(&RecordFileT[1], "RECORD_FILE_NAME", "Name", "indi_record__T_.ser"); IUFillTextVector(&RecordFileTP, RecordFileT, NARRAY(RecordFileT), getDeviceName(), "RECORD_FILE", "Record File", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); - - /* Video Record Switch */ - IUFillSwitch(&RecordS[0], "ON", "Record On", ISS_OFF); - IUFillSwitch(&RecordS[1], "OFF", "Record Off", ISS_ON); - IUFillSwitchVector(&RecordSP, RecordS, NARRAY(RecordS), getDeviceName(), "VIDEO_RECORD", "Video Record", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - + + /* Record Options */ + IUFillNumber(&RecordOptionsN[0], "RECORD_DURATION", "Duration (sec)", "%6.3f", 0.001, 999999.0, 0.0, 1); + IUFillNumber(&RecordOptionsN[1], "RECORD_FRAME_TOTAL", "Frames", "%9.0f", 1.0, 999999999.0, 1.0, 30.0); + IUFillNumberVector(&RecordOptionsNP, RecordOptionsN, NARRAY(RecordOptionsN), getDeviceName(), "RECORD_OPTIONS", "Record Options", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE); + + /* Record Switch */ + IUFillSwitch(&RecordS[0], "RECORD_ON", "Record On", ISS_OFF); + IUFillSwitch(&RecordS[1], "RECORD_DURATION_ON", "Record (Duration)", ISS_OFF); + IUFillSwitch(&RecordS[2], "RECORD_FRAME_ON", "Record (Frames)", ISS_OFF); + IUFillSwitch(&RecordS[3], "RECORD_OFF", "Record Off", ISS_ON); + IUFillSwitchVector(&RecordStreamSP, RecordS, NARRAY(RecordS), getDeviceName(), "RECORD_STREAM", "Video Record", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); PrimaryCCD.getCCDInfo()->p = IP_RW; @@ -154,22 +216,36 @@ { defineText(&camNameTP); defineSwitch(&StreamSP); - defineSwitch(&StackModeSP); - defineSwitch(&ImageTypeSP); + defineNumber(&StreamOptionsNP); + defineNumber(&FpsNP); + + defineSwitch(&ImageColorSP); defineSwitch(&InputsSP); defineSwitch(&CaptureFormatsSP); defineSwitch(&DropFrameSP); + defineNumber(&FramestoDropNP); + if (CaptureSizesSP.sp != NULL) defineSwitch(&CaptureSizesSP); else if (CaptureSizesNP.np != NULL) defineNumber(&CaptureSizesNP); - if (FrameRatesSP.sp != NULL) + if (FrameRatesSP.sp != NULL) defineSwitch(&FrameRatesSP); else if (FrameRateNP.np != NULL) defineNumber(&FrameRateNP); - } + defineSwitch(&RecordStreamSP); + defineText(&RecordFileTP); + defineNumber(&RecordOptionsNP); + +#ifdef WITH_V4L2_EXPERIMENTS + defineSwitch(&ImageDepthSP); + defineSwitch(&StackModeSP); + defineSwitch(&ColorProcessingSP); + defineText(&CaptureColorSpaceTP); +#endif + } } bool V4L2_Driver::updateProperties () @@ -194,31 +270,40 @@ getBasicData(); defineSwitch(&StreamSP); - defineSwitch(&StackModeSP); - defineSwitch(&ImageTypeSP); + defineNumber(&StreamOptionsNP); + defineNumber(&FpsNP); + + defineSwitch(&ImageColorSP); defineSwitch(&InputsSP); defineSwitch(&CaptureFormatsSP); defineSwitch(&DropFrameSP); + defineNumber(&FramestoDropNP); if (CaptureSizesSP.sp != NULL) defineSwitch(&CaptureSizesSP); else if (CaptureSizesNP.np != NULL) defineNumber(&CaptureSizesNP); - if (FrameRatesSP.sp != NULL) + if (FrameRatesSP.sp != NULL) defineSwitch(&FrameRatesSP); else if (FrameRateNP.np != NULL) defineNumber(&FrameRateNP); - defineSwitch(&RecordSP); + defineSwitch(&RecordStreamSP); defineText(&RecordFileTP); - - SetCCDParams(V4LFrame->width, V4LFrame->height, 8, 5.6, 5.6); + defineNumber(&RecordOptionsNP); +#ifdef WITH_V4L2_EXPERIMENTS + defineSwitch(&ImageDepthSP); + defineSwitch(&StackModeSP); + defineSwitch(&ColorProcessingSP); + defineText(&CaptureColorSpaceTP); +#endif - PrimaryCCD.setImageExtension("fits"); - + SetCCDParams(V4LFrame->width, V4LFrame->height, V4LFrame->bpp, 5.6, 5.6); + PrimaryCCD.setImageExtension("fits"); - if (v4l_base->isLXmodCapable()) lx->updateProperties(); + if (v4l_base->isLXmodCapable()) lx->updateProperties(); + return true; } else { @@ -229,11 +314,14 @@ deleteProperty(camNameTP.name); deleteProperty(StreamSP.name); - deleteProperty(StackModeSP.name); - deleteProperty(ImageTypeSP.name); + deleteProperty(StreamOptionsNP.name); + deleteProperty(FpsNP.name); + + deleteProperty(ImageColorSP.name); deleteProperty(InputsSP.name); deleteProperty(CaptureFormatsSP.name); deleteProperty(DropFrameSP.name); + deleteProperty(FramestoDropNP.name); if (CaptureSizesSP.sp != NULL) deleteProperty(CaptureSizesSP.name); @@ -245,7 +333,6 @@ deleteProperty(FrameRateNP.name); deleteProperty(ImageAdjustNP.name); - for (i=0; is == IPS_BUSY) || (RecordSP.s == IPS_BUSY)) { + if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)) { DEBUG(INDI::Logger::DBG_ERROR, "Can not set input while capturing."); InputsSP.s = IPS_BUSY; IDSetSwitch(&InputsSP, NULL); @@ -321,7 +418,7 @@ /* Capture Format */ if ((!strcmp(name, CaptureFormatsSP.name))) { - if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordSP.s == IPS_BUSY)) { + if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)) { DEBUG(INDI::Logger::DBG_ERROR, "Can not set format while capturing."); CaptureFormatsSP.s = IPS_BUSY; IDSetSwitch(&CaptureFormatsSP, NULL); @@ -340,7 +437,10 @@ IDSetSwitch(&CaptureFormatsSP, NULL); return false; } - + + V4LFrame->bpp = v4l_base->getBpp(); + PrimaryCCD.setBPP(V4LFrame->bpp); + if (CaptureSizesSP.sp != NULL) deleteProperty(CaptureSizesSP.name); else if (CaptureSizesNP.np != NULL) @@ -352,7 +452,13 @@ else if (CaptureSizesNP.np != NULL) defineNumber(&CaptureSizesNP); CaptureFormatsSP.s = IPS_OK; - + +#ifdef WITH_V4L2_EXPERIMENTS + IUSaveText(&CaptureColorSpaceT[0], getColorSpaceName(&v4l_base->fmt)); + IUSaveText(&CaptureColorSpaceT[1], getYCbCrEncodingName(&v4l_base->fmt)); + IUSaveText(&CaptureColorSpaceT[2], getQuantizationName(&v4l_base->fmt)); + IDSetText(&CaptureColorSpaceTP, NULL); +#endif direct_record=recorder->setpixelformat(v4l_base->fmt.fmt.pix.pixelformat); IDSetSwitch(&CaptureFormatsSP, "Capture format: %d. %s", index, CaptureFormatsSP.sp[index].name); @@ -362,7 +468,7 @@ /* Capture Size (Discrete) */ if ((!strcmp(name, CaptureSizesSP.name))) { - if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordSP.s == IPS_BUSY)) { + if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)) { DEBUG(INDI::Logger::DBG_ERROR, "Can not set capture size while capturing."); CaptureSizesSP.s = IPS_BUSY; IDSetSwitch(&CaptureSizesSP, NULL); @@ -423,24 +529,48 @@ } /* Image Type */ - if (!strcmp(name, ImageTypeSP.name)) { - IUResetSwitch(&ImageTypeSP); - IUUpdateSwitch(&ImageTypeSP, states, names, n); - ImageTypeSP.s = IPS_OK; - if (ImageTypeS[0].s == ISS_ON) { - PrimaryCCD.setBPP(8); + if (!strcmp(name, ImageColorSP.name)) { + if (is_recording) { + DEBUG(INDI::Logger::DBG_WARNING, "Can not set Image type (GRAY/COLOR) while recording."); + return false; + } + + IUResetSwitch(&ImageColorSP); + IUUpdateSwitch(&ImageColorSP, states, names, n); + ImageColorSP.s = IPS_OK; + if (ImageColorS[0].s == ISS_ON) { + //PrimaryCCD.setBPP(8); PrimaryCCD.setNAxis(2); } else { //PrimaryCCD.setBPP(32); - PrimaryCCD.setBPP(8); + //PrimaryCCD.setBPP(8); PrimaryCCD.setNAxis(3); } - frameBytes = (ImageTypeS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH()): - (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * 4); + frameBytes = (ImageColorS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8)): + (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8) * 4); PrimaryCCD.setFrameBufferSize(frameBytes); - IDSetSwitch(&ImageTypeSP, NULL); + IDSetSwitch(&ImageColorSP, NULL); + return true; + } + + /* Image Depth */ + if (!strcmp(name, ImageDepthSP.name)) { + if (is_recording) { + DEBUG(INDI::Logger::DBG_WARNING, "Can not set Image depth (8/16bits) while recording."); + return false; + } + + IUResetSwitch(&ImageDepthSP); + IUUpdateSwitch(&ImageDepthSP, states, names, n); + ImageDepthSP.s = IPS_OK; + if (ImageDepthS[0].s == ISS_ON) { + PrimaryCCD.setBPP(8); + } else { + PrimaryCCD.setBPP(16); + } + IDSetSwitch(&ImageDepthSP, NULL); return true; } @@ -450,6 +580,12 @@ IUUpdateSwitch(&StackModeSP, states, names, n); StackModeSP.s = IPS_OK; stackMode=IUFindOnSwitchIndex(&StackModeSP); + if (stackMode==STACK_RESET_DARK) { + if (V4LFrame->darkFrame != NULL) { + free(V4LFrame->darkFrame); + V4LFrame->darkFrame = NULL; + } + } IDSetSwitch(&StackModeSP, "Setting Stacking Mode: %s", StackModeS[stackMode].name); return true; @@ -457,78 +593,65 @@ /* Video Stream */ if (!strcmp(name, StreamSP.name)) { - bool is_streaming = (StreamSP.s == IPS_BUSY); - bool is_recording = (RecordSP.s == IPS_BUSY); IUResetSwitch(&StreamSP); IUUpdateSwitch(&StreamSP, states, names, n); if (StreamS[0].s == ISS_ON) { - if ((!is_streaming) && (!is_recording)) { + if (!is_streaming) { StreamSP.s = IPS_BUSY; - frameCount = 0; - DEBUG(INDI::Logger::DBG_DEBUG, "Starting the video stream.\n"); - v4l_base->start_capturing(errmsg); - } else { - if (!is_streaming) StreamSP.s=IPS_IDLE; + streamframeCount = 0; + DEBUG(INDI::Logger::DBG_DEBUG, "Starting the video stream."); + streamframeCount = 0; + start_capturing(); + is_streaming=true; } } else { StreamSP.s = IPS_IDLE; if (is_streaming) { - DEBUGF(INDI::Logger::DBG_DEBUG, "The video stream has been disabled. Frame count %d\n", frameCount); - v4l_base->stop_capturing(errmsg); + DEBUGF(INDI::Logger::DBG_DEBUG, "The video stream has been disabled. Frame count %d", streamframeCount); + if (!is_exposing && !is_recording) stop_capturing(); + is_streaming=false; } } - IDSetSwitch(&StreamSP, NULL); return true; } /* Record Stream */ - if (!strcmp(name, RecordSP.name)) { - bool is_streaming = (StreamSP.s == IPS_BUSY); - bool is_recording = (RecordSP.s == IPS_BUSY); - IUResetSwitch(&RecordSP); - IUUpdateSwitch(&RecordSP, states, names, n); - - if (RecordS[0].s == ISS_ON) { - if ((!is_streaming) && (!is_recording)) { - frameCount = 0; - DEBUG(INDI::Logger::DBG_SESSION, "Recording the video stream (no binning).\n"); - RecordSP.s = IPS_BUSY; - if (!recorder->open(RecordFileT[0].text, errmsg)) { - RecordSP.s = IPS_ALERT; - IDSetSwitch(&RecordSP, NULL); - DEBUGF(INDI::Logger::DBG_ERROR, "%s", errmsg); - return false; - } - if (direct_record) { - DEBUG(INDI::Logger::DBG_SESSION, "Using direct recording (no soft crop, no frame count).\n"); - v4l_base->doDecode(false); - v4l_base->doRecord(true); - } else { - if (ImageTypeS[0].s == ISS_ON) - recorder->setDefaultMono(); - else - recorder->setDefaultColor(); + if (!strcmp(name, RecordStreamSP.name)) { + if (is_recording && RecordStreamSP.sp[3].s != ISS_ON) { + DEBUG(INDI::Logger::DBG_WARNING, "Recording device is busy."); + return false; + } + IUResetSwitch(&RecordStreamSP); + IUUpdateSwitch(&RecordStreamSP, states, names, n); + + if ((RecordStreamSP.sp[0].s == ISS_ON) || (RecordStreamSP.sp[1].s == ISS_ON) || (RecordStreamSP.sp[2].s == ISS_ON)) { + if (!is_recording) { + RecordStreamSP.s = IPS_BUSY; + if (RecordStreamSP.sp[1].s == ISS_ON) + DEBUGF(INDI::Logger::DBG_SESSION, "Starting video record (Duration): %g secs.", RecordOptionsNP.np[0].value); + else if (RecordStreamSP.sp[2].s == ISS_ON) + DEBUGF(INDI::Logger::DBG_SESSION, "Starting video record (Frame count): %d.", (int)(RecordOptionsNP.np[1].value)); + else + DEBUG(INDI::Logger::DBG_SESSION, "Starting video record."); + if (!start_recording()) { + RecordStreamSP.sp[0].s = ISS_OFF; RecordStreamSP.sp[1].s = ISS_OFF; + RecordStreamSP.sp[2].s = ISS_OFF; RecordStreamSP.sp[3].s = ISS_ON; + RecordStreamSP.s = IPS_ALERT; } - v4l_base->start_capturing(errmsg); - } else { - if (!is_recording) RecordSP.s=IPS_IDLE; - } + } } else { - RecordSP.s = IPS_IDLE; + RecordStreamSP.s = IPS_IDLE; if (is_recording) { - v4l_base->stop_capturing(errmsg); - if (direct_record) { - v4l_base->doDecode(true); - v4l_base->doRecord(false); - } - recorder->close(); - DEBUGF(INDI::Logger::DBG_SESSION, "Recording stream has been disabled. Frame count %d\n", frameCount); + DEBUGF(INDI::Logger::DBG_SESSION, "Recording stream has been disabled. Frame count %d", recordframeCount); + stop_recording(); + + } } - IDSetSwitch(&RecordSP, NULL); + IDSetSwitch(&RecordStreamSP, NULL); return true; } @@ -539,7 +662,7 @@ if (iopt < v4loptions) { unsigned int ctrl_id, optindex, ctrlindex; - DEBUGF(INDI::Logger::DBG_DEBUG, "Toggle switch %s=%s\n", Options[iopt].name, Options[iopt].label); + DEBUGF(INDI::Logger::DBG_DEBUG, "Toggle switch %s=%s", Options[iopt].name, Options[iopt].label); Options[iopt].s = IPS_IDLE; IUResetSwitch(&Options[iopt]); @@ -552,19 +675,45 @@ else ctrlindex=optindex; ctrl_id = (*((unsigned int*) Options[iopt].aux)); - DEBUGF(INDI::Logger::DBG_DEBUG, " On switch is (%d) %s=\"%s\", ctrl_id = 0x%X ctrl_index=%d\n", optindex, + DEBUGF(INDI::Logger::DBG_DEBUG, " On switch is (%d) %s=\"%s\", ctrl_id = 0x%X ctrl_index=%d", optindex, Options[iopt].sp[optindex].name, Options[iopt].sp[optindex].label, ctrl_id, ctrlindex); if (v4l_base->setOPTControl( ctrl_id , ctrlindex, errmsg) < 0) { + if (Options[iopt].nsp == 1) { // button + Options[iopt].sp[optindex].s = ISS_OFF; + } Options[iopt].s = IPS_ALERT; IDSetSwitch(&Options[iopt], NULL); DEBUGF(INDI::Logger::DBG_ERROR, "Unable to adjust setting. %s", errmsg); return false; } + if (Options[iopt].nsp == 1) { // button + Options[iopt].sp[optindex].s = ISS_OFF; + } Options[iopt].s = IPS_OK; IDSetSwitch(&Options[iopt], NULL); return true; } + /* ColorProcessing */ + if (!strcmp(name, ColorProcessingSP.name)) + { + if (ImageColorS[0].s == ISS_ON) { + IUUpdateSwitch(&ColorProcessingSP, states, names, n); + v4l_base->setColorProcessing(ColorProcessingS[0].s == ISS_ON, ColorProcessingS[1].s == ISS_ON, ColorProcessingS[2].s == ISS_ON); + ColorProcessingSP.s = IPS_OK; + IDSetSwitch(&ColorProcessingSP, NULL); + V4LFrame->bpp = v4l_base->getBpp(); + PrimaryCCD.setBPP(V4LFrame->bpp); + PrimaryCCD.setBPP(V4LFrame->bpp); + frameBytes = (ImageColorS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8)): + (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8) * 4); + PrimaryCCD.setFrameBufferSize(frameBytes); + return true; + } else { + DEBUG(INDI::Logger::DBG_WARNING, "No color processing in color mode "); + return false; + } + } lx->ISNewSwitch (dev, name, states, names, n); return INDI::CCD::ISNewSwitch (dev, name, states, names, n); @@ -572,36 +721,37 @@ bool V4L2_Driver::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { - IText *tp; + IText *tp; - /* ignore if not ours */ - if (dev && strcmp (getDeviceName(), dev)) - return true; - - if (!strcmp(name, PortTP.name) ) - { - PortTP.s = IPS_OK; - tp = IUFindText( &PortTP, names[0] ); - if (!tp) - return false; - IUSaveText(tp, texts[0]); - IDSetText (&PortTP, NULL); - return true; - } + /* ignore if not ours */ + if (dev && strcmp (getDeviceName(), dev)) + return true; + + if (!strcmp(name, PortTP.name) ) + { + PortTP.s = IPS_OK; + tp = IUFindText( &PortTP, names[0] ); + if (!tp) + return false; + IUSaveText(tp, texts[0]); + IDSetText (&PortTP, NULL); + return true; + } + + if (!strcmp(name, RecordFileTP.name) ) + { + tp = IUFindText(&RecordFileTP, "RECORD_FILE_NAME"); + if (strchr(tp->text, '/')) { + DEBUG(INDI::Logger::DBG_WARNING, "Dir. separator (/) not allowed in filename."); + return false; + } + IUUpdateText(&RecordFileTP, texts, names, n); + IDSetText (&RecordFileTP, NULL); + return true; + } - if (!strcmp(name, RecordFileTP.name) ) - { - RecordFileTP.s = IPS_OK; - tp = IUFindText( &RecordFileTP, names[0] ); - if (!tp) - return false; - IUSaveText(tp, texts[0]); - IDSetText (&RecordFileTP, NULL); - return true; - } - - lx->ISNewText (dev, name, texts, names, n); - return INDI::CCD::ISNewText (dev, name, texts, names, n); + lx->ISNewText (dev, name, texts, names, n); + return INDI::CCD::ISNewText (dev, name, texts, names, n); } bool V4L2_Driver::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) @@ -611,60 +761,84 @@ /* ignore if not ours */ if (dev && strcmp (getDeviceName(), dev)) return true; + + /* Stream rate */ + if (!strcmp (StreamOptionsNP.name, name)) + { + IUUpdateNumber(&StreamOptionsNP, values, names, n); + StreamOptionsNP.s = IPS_OK; + IDSetNumber(&StreamOptionsNP, NULL); + return true; + } + + /* Record Options */ + if (!strcmp (RecordOptionsNP.name, name)) + { + if (is_recording) { + DEBUG(INDI::Logger::DBG_WARNING, "Recording device is busy"); + return false; + } + IUUpdateNumber(&RecordOptionsNP, values, names, n); + RecordOptionsNP.s = IPS_OK; + IDSetNumber(&RecordOptionsNP, NULL); + return true; + } - /* Capture Size (Step/Continuous) */ + /* Capture Size (Step/Continuous) */ if ((!strcmp(name, CaptureSizesNP.name))) { - if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordSP.s == IPS_BUSY)) { - DEBUG(INDI::Logger::DBG_ERROR, "Can not set capture size while capturing."); - CaptureSizesNP.s = IPS_BUSY; - IDSetNumber(&CaptureSizesNP, NULL); - return false; - } else - { - unsigned int index, sizes[2], w, h; - double rsizes[2]; - double fsizes[4]; - const char *fnames[]={"X", "Y", "WIDTH", "HEIGHT"}; - if (!strcmp(names[0], "Width")) { - sizes[0] = values[0]; - sizes[1] = values[1]; - } else { - sizes[0] = values[1]; - sizes[1] = values[0]; - } - if (v4l_base->setcapturesize(sizes[0], sizes[1], errmsg) == -1) - { - DEBUGF(INDI::Logger::DBG_SESSION, "ERROR (setsize): %s", errmsg); - CaptureSizesNP.s = IPS_ALERT; - IDSetNumber(&CaptureSizesNP, NULL); + if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)) + { + DEBUG(INDI::Logger::DBG_ERROR, "Can not set capture size while capturing."); + CaptureSizesNP.s = IPS_BUSY; + IDSetNumber(&CaptureSizesNP, NULL); return false; - } - if (!strcmp(names[0], "Width")) - { - w=v4l_base->getWidth(); rsizes[0]=(double)w; - h=v4l_base->getHeight();rsizes[1]=(double)h; - } else { - w=v4l_base->getWidth();rsizes[1]=(double)w; - h=v4l_base->getHeight();rsizes[0]=(double)h; - } - - PrimaryCCD.setFrame(0, 0, w, h); - IUUpdateNumber(&CaptureSizesNP, rsizes, names, n); - V4LFrame->width = w; - V4LFrame->height= h; - PrimaryCCD.setResolution(w, h); - CaptureSizesNP.s = IPS_OK; - frameBytes = (ImageTypeS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH()): - (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * 4); - PrimaryCCD.setFrameBufferSize(frameBytes); + } else + { + unsigned int index, sizes[2], w, h; + double rsizes[2]; + double fsizes[4]; + const char *fnames[]={"X", "Y", "WIDTH", "HEIGHT"}; + if (!strcmp(names[0], "Width")) { + sizes[0] = values[0]; + sizes[1] = values[1]; + } else { + sizes[0] = values[1]; + sizes[1] = values[0]; + } + if (v4l_base->setcapturesize(sizes[0], sizes[1], errmsg) == -1) + { + DEBUGF(INDI::Logger::DBG_SESSION, "ERROR (setsize): %s", errmsg); + CaptureSizesNP.s = IPS_ALERT; + IDSetNumber(&CaptureSizesNP, NULL); + return false; + } + if (!strcmp(names[0], "Width")) + { + w=v4l_base->getWidth(); rsizes[0]=(double)w; + h=v4l_base->getHeight();rsizes[1]=(double)h; + } else + { + w=v4l_base->getWidth();rsizes[1]=(double)w; + h=v4l_base->getHeight();rsizes[0]=(double)h; + } + + PrimaryCCD.setFrame(0, 0, w, h); + IUUpdateNumber(&CaptureSizesNP, rsizes, names, n); + V4LFrame->width = w; + V4LFrame->height= h; + PrimaryCCD.setResolution(w, h); + CaptureSizesNP.s = IPS_OK; + frameBytes = (ImageColorS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8)): + (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8) * 4); + PrimaryCCD.setFrameBufferSize(frameBytes); - recorder->setsize(w, h); - - IDSetNumber(&CaptureSizesNP, "Capture size (step/cont): %dx%d", w, h); - return true; + recorder->setsize(w, h); + + IDSetNumber(&CaptureSizesNP, "Capture size (step/cont): %dx%d", w, h); + return true; + } } - } if (!strcmp (ImageAdjustNP.name, name)) { @@ -678,20 +852,18 @@ { ctrl_id = *((unsigned int *) ImageAdjustNP.np[i].aux0); - DEBUGF(INDI::Logger::DBG_DEBUG, " Setting %s (%s) to %d, ctrl_id = 0x%X \n", ImageAdjustNP.np[i].name, ImageAdjustNP.np[i].label, (int)ImageAdjustNP.np[i].value, ctrl_id); + DEBUGF(INDI::Logger::DBG_DEBUG, " Setting %s (%s) to %d, ctrl_id = 0x%X", ImageAdjustNP.np[i].name, ImageAdjustNP.np[i].label, (int)ImageAdjustNP.np[i].value, ctrl_id); if (v4l_base->setINTControl( ctrl_id , ImageAdjustNP.np[i].value, errmsg) < 0) { - /* Some controls may become read-only depending on selected options - ImageAdjustNP.s = IPS_ALERT; - IDSetNumber(&ImageAdjustNP, "Unable to adjust setting. %s", errmsg); - return false; - */ + /* Some controls may become read-only depending on selected options */ DEBUGF(INDI::Logger::DBG_WARNING,"Unable to adjust %s (ctrl_id = 0x%X)", ImageAdjustNP.np[i].label, ctrl_id); - v4l_base->getControl(ctrl_id, &(ImageAdjustNP.np[i].value), errmsg); + } - } - + /* Some controls may have been ajusted by the driver */ + /* a read is mandatory as VIDIOC_S_CTRL is write only and does not return the actual new value */ + v4l_base->getControl(ctrl_id, &(ImageAdjustNP.np[i].value), errmsg); + } ImageAdjustNP.s = IPS_OK; IDSetNumber(&ImageAdjustNP, NULL); return true; @@ -703,55 +875,65 @@ bool rc; int width = v4l_base->getWidth(); int height = v4l_base->getHeight(); - - if (StreamS[0].s == ISS_ON) - v4l_base->stop_capturing(errmsg); - - StreamS[0].s = ISS_OFF; - StreamS[1].s = ISS_ON; - StreamSP.s = IPS_IDLE; - IDSetSwitch(&StreamSP, NULL); - + + if (is_exposing) { + DEBUG(INDI::Logger::DBG_ERROR, "Can not start new exposure while exposing."); + return false; + } + V4LFrame->expose = values[0]; - - if (AbsExposureN && ManualExposureSP && (AbsExposureN->max >= (V4LFrame->expose * 10000))) - { - DEBUGF(INDI::Logger::DBG_SESSION, "Using device manual exposure (max %f, required %f).", AbsExposureN->max, (V4LFrame->expose * 10000)); - rc = setManualExposure(V4LFrame->expose); - if (rc == false) - DEBUG(INDI::Logger::DBG_WARNING, "Unable to set manual exposure, falling back to auto exposure."); - } - - timerclear(&exposure_duration); - exposure_duration.tv_sec = (long) values[0] ; - exposure_duration.tv_usec = (long) ((values[0] - (double) exposure_duration.tv_sec) - * 1000000.0) ; - frameCount=0; - gettimeofday(&capture_start, NULL); - if (lx->isenabled()) { - rc=startlongexposure(V4LFrame->expose); - if (rc == false) - DEBUG(INDI::Logger::DBG_WARNING, "Unable to start long exposure, falling back to auto exposure."); - else { - if( lx->getLxmode() == LXSERIAL ) { - v4l_base->start_capturing( errmsg ); - } - } - } - else - v4l_base->start_capturing(errmsg); + setShutter(V4LFrame->expose); + + if (!(lx->isenabled()) || (lx->getLxmode() == LXSERIAL )) + start_capturing(); + + is_exposing=true; ExposeTimeNP->s = IPS_BUSY; if (IUUpdateNumber(ExposeTimeNP, values, names, n) < 0) - return false; + return false; //?? return true; } + /* Frames to drop */ + if (!strcmp (FramestoDropNP.name, name)) + { + IUUpdateNumber(&FramestoDropNP, values, names, n); + v4l_base->setDropFrameCount(values[0]); + FramestoDropNP.s = IPS_OK; + IDSetNumber(&FramestoDropNP, NULL); + return true; + } return INDI::CCD::ISNewNumber(dev, name, values, names, n); } + +bool V4L2_Driver::setShutter(double duration) { + bool rc; + gettimeofday(&capture_start, NULL); + if (lx->isenabled()) + { + DEBUGF(INDI::Logger::DBG_SESSION, "Using long exposure mode for %g sec frame.", duration); + rc=startlongexposure(duration); + if (rc == false) + DEBUG(INDI::Logger::DBG_WARNING, "Unable to start long exposure, falling back to auto exposure."); + } + else if (AbsExposureN && ManualExposureSP && (AbsExposureN->max >= (duration * 10000))) + { + DEBUGF(INDI::Logger::DBG_SESSION, "Using device manual exposure (max %f, required %f).", AbsExposureN->max, (duration * 10000)); + rc = setManualExposure(duration); + if (rc == false) + DEBUG(INDI::Logger::DBG_WARNING, "Unable to set manual exposure, falling back to auto exposure."); + } + timerclear(&exposure_duration); + exposure_duration.tv_sec = (long) duration ; + exposure_duration.tv_usec = (long) ((duration - (double) exposure_duration.tv_sec) * 1000000.0) ; + frameCount=0; + subframeCount=0; +} + bool V4L2_Driver::setManualExposure(double duration) { if (AbsExposureN == NULL || ManualExposureSP == NULL) @@ -796,19 +978,7 @@ IDSetNumber(&ImageAdjustNP, "Unable to adjust AbsExposure. %s", errmsg); return false; } - - /* - for (int i=0; i < ImageAdjustNP.nnp; i++) { - ctrl_id = *((unsigned int *) ImageAdjustNP.np[i].aux0); - - if (v4l_base->setINTControl( ctrl_id , ImageAdjustNP.np[i].value, errmsg) < 0) { - ImageAdjustNP.s = IPS_ALERT; - AbsExposureN->value = curVal; - IDSetNumber(&ImageAdjustNP, "Unable to adjust setting. %s", errmsg); - return false; - } - } - */ + ImageAdjustNP.s = IPS_OK; IDSetNumber(&ImageAdjustNP, NULL); } @@ -816,6 +986,90 @@ return true; } +void V4L2_Driver::start_capturing() { + char errmsg[ERRMSGSIZ]; + if (is_capturing) return; + v4l_base->start_capturing(errmsg); + is_capturing = true; + //timer_gettime(fpstimer, &tframe1); + getitimer(ITIMER_REAL, &tframe1); + mssum=0; framecountsec=0; +} + +void V4L2_Driver::stop_capturing() { + char errmsg[ERRMSGSIZ]; + if (!is_capturing) return; + v4l_base->stop_capturing(errmsg); + is_capturing = false; +} + +bool V4L2_Driver::start_recording() { + char errmsg[ERRMSGSIZ]; + std::string filename, expfilename, expfiledir; + std::string filtername; + std::map patterns; + if (is_recording) return true; + /* get filter name for pattern substitution */ + if (CurrentFilterSlot != -1 && CurrentFilterSlot <= FilterNames.size()) { + filtername=FilterNames.at(CurrentFilterSlot-1); + patterns["_F_"]=filtername; + DEBUGF(INDI::Logger::DBG_SESSION, "Adding filter pattern %s", filtername.c_str()); + } + /* pattern substitution */ + recordfiledir.assign(RecordFileTP.tp[0].text); + expfiledir=expand(recordfiledir, patterns); + if (expfiledir.at(expfiledir.size() - 1) != '/') + expfiledir+='/'; + recordfilename.assign(RecordFileTP.tp[1].text); + expfilename=expand(recordfilename, patterns); + if (expfilename.substr(expfilename.size() - 4, 4) != ".ser") + expfilename+=".ser"; + filename=expfiledir+expfilename; + //DEBUGF(INDI::Logger::DBG_SESSION, "Expanded file is %s", filename.c_str()); + //filename=recordfiledir+recordfilename; + DEBUGF(INDI::Logger::DBG_SESSION, "Record file is %s", filename.c_str()); + /* Create/open file/dir */ + if (mkpath(expfiledir, 0755)) { + DEBUGF(INDI::Logger::DBG_WARNING, "Can not create record directory %s: %s", expfiledir.c_str(), strerror(errno)); + return false; + } + if (!recorder->open(filename.c_str(), errmsg)) { + RecordStreamSP.s = IPS_ALERT; + IDSetSwitch(&RecordStreamSP, NULL); + DEBUGF(INDI::Logger::DBG_WARNING, "Can not open record file: %s", errmsg); + return false; + } + /* start capture */ + if (direct_record) { + DEBUG(INDI::Logger::DBG_SESSION, "Using direct recording (no software cropping)."); + //v4l_base->doDecode(false); + v4l_base->doRecord(true); + } else { + if (ImageColorS[0].s == ISS_ON) + recorder->setDefaultMono(); + else + recorder->setDefaultColor(); + } + recordDuration=0.0; + recordframeCount=0; + if (!is_capturing) start_capturing(); + is_recording=true; + return true; +} + +bool V4L2_Driver::stop_recording() { + if (!is_recording) return true; + if (!is_streaming && !is_exposing) stop_capturing(); + if (direct_record) { + //v4l_base->doDecode(true); + v4l_base->doRecord(false); + } + is_recording=false; + recorder->close(); + DEBUGF(INDI::Logger::DBG_SESSION, "Record Duration(millisec): %g -- Frame count: %d", recordDuration, recordframeCount); + return true; +} + bool V4L2_Driver::startlongexposure(double timeinsec) { lxtimer=IEAddTimer((int)(timeinsec*1000.0), (IE_TCF *)lxtimerCallback, this); @@ -825,13 +1079,19 @@ void V4L2_Driver::lxtimerCallback(void *userpointer) { + struct timespec waittime; char errmsg[ERRMSGSIZ]; V4L2_Driver *p = (V4L2_Driver *)userpointer; p->lx->stopLx(); - p->v4l_base->setlxstate( LX_TRIGGERED ); + if (p->lx->getLxmode() == LXSERIAL ) { + p->v4l_base->setlxstate( LX_TRIGGERED ); + } else { + p->v4l_base->setlxstate( LX_ACTIVE ); + } IERmTimer(p->lxtimer); if( !p->v4l_base->isstreamactive() ) - p->v4l_base->start_capturing(errmsg); // jump to new/updateFrame + p->start_capturing(); // jump to new/updateFrame + //p->v4l_base->start_capturing(errmsg); // jump to new/updateFrame } bool V4L2_Driver::UpdateCCDBin(int hor, int ver) @@ -910,8 +1170,8 @@ V4LFrame->width = crect.width; V4LFrame->height= crect.height; PrimaryCCD.setFrame(x, y, w, h); - frameBytes = (ImageTypeS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH()): - (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * 4); + frameBytes = (ImageColorS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8)): + (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8) * 4); PrimaryCCD.setFrameBufferSize(frameBytes); recorder->setsize(w, h); //DEBUGF(INDI::Logger::DBG_SESSION, "updateCCDFrame ok: %d %d %d %d", x, y, w, h); @@ -926,50 +1186,174 @@ void V4L2_Driver::newFrame(void *p) { + ((V4L2_Driver *) (p))->updateFrame(); } +void V4L2_Driver::stackFrame() +{ + struct timeval current_exposure; + + if (!V4LFrame->stackedFrame) { + float *src, *dest; + unsigned int i; + + V4LFrame->stackedFrame = (float *)malloc(sizeof(float) * v4l_base->getWidth() * v4l_base->getHeight()); + src=v4l_base->getLinearY(); + dest=V4LFrame->stackedFrame; + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = *src++; + subframeCount=1; + } else { + float *src, *dest; + unsigned int i; + + src=v4l_base->getLinearY(); + dest=V4LFrame->stackedFrame; + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ += *src++; + subframeCount+=1; + } + +} void V4L2_Driver::updateFrame() { char errmsg[ERRMSGSIZ]; - + double ms1, ms2, deltams; + // Measure FPS + // This uses High Resolution Timer but requires to link with librt provided in glibc + // To not add a dependency I switch back to BSD timer as clock_gettime also needs librt for glibc < 2.17 + /* + timer_gettime(fpstimer, &tframe2); + //ms2=capture->get(CV_CAP_PROP_POS_MSEC); + ms1=(1000.0 * (double)tframe1.it_value.tv_sec) + ((double)tframe1.it_value.tv_nsec / 1000000.0); + ms2=(1000.0 * (double)tframe2.it_value.tv_sec) + ((double)tframe2.it_value.tv_nsec / 1000000.0); + if (ms2 > ms1) deltams = ms1 +( (24*3600*1000.0) - ms2); + else deltams=ms1-ms2; + //EstFps->value=1000.0 / deltams; + tframe1=tframe2; + mssum+=deltams; + framecountsec+=1; + FpsN[0].value= 1000.0 / deltams; + if (mssum >= 1000.0) { + FpsN[1].value=(framecountsec * 1000.0) / mssum; + mssum=0; framecountsec=0; + } + IDSetNumber(&FpsNP, NULL); + */ + getitimer(ITIMER_REAL, &tframe2); + //ms2=capture->get(CV_CAP_PROP_POS_MSEC); + ms1=(1000.0 * (double)tframe1.it_value.tv_sec) + ((double)tframe1.it_value.tv_usec / 1000.0); + ms2=(1000.0 * (double)tframe2.it_value.tv_sec) + ((double)tframe2.it_value.tv_usec / 1000.0); + if (ms2 > ms1) deltams = ms1 +( (24*3600*1000.0) - ms2); + else deltams=ms1-ms2; + //EstFps->value=1000.0 / deltams; + tframe1=tframe2; + mssum+=deltams; + framecountsec+=1; + FpsN[0].value= 1000.0 / deltams; + if (mssum >= 1000.0) { + FpsN[1].value=(framecountsec * 1000.0) / mssum; + mssum=0; framecountsec=0; + } + IDSetNumber(&FpsNP, NULL); + if (StreamSP.s == IPS_BUSY) { - frameCount++; - updateStream(); + streamframeCount++; + if (streamframeCount >= StreamOptionsN[0].value) { + updateStream(); + streamframeCount = 0; + } } - else if (RecordSP.s == IPS_BUSY) + if (RecordStreamSP.s == IPS_BUSY) { - frameCount++; - recordStream(); + recordStream(deltams); } - else if (ExposeTimeNP->s == IPS_BUSY) + if (ExposeTimeNP->s == IPS_BUSY) { - PrimaryCCD.setExposureDuration(ExposeTimeN[0].value); - struct timeval current_exposure; unsigned int i; - unsigned char *src, *dest; - + struct timeval current_exposure; + // Stack Mono frames + if ((stackMode) && !(lx->isenabled()) && !(ImageColorS[1].s == ISS_ON)) { + stackFrame(); + } gettimeofday(&capture_end,NULL); timersub(&capture_end, &capture_start, ¤t_exposure); + PrimaryCCD.setExposureDuration(ExposeTimeN[0].value); + if ((stackMode) && !(lx->isenabled()) && !(ImageColorS[1].s == ISS_ON) && (timercmp(¤t_exposure, &exposure_duration, <))) + return; // go on stacking - if (ImageTypeS[0].s == ISS_ON) { - src = v4l_base->getY(); - dest = (unsigned char *)PrimaryCCD.getFrameBuffer(); - if (frameCount==0) - for (i=0; i< frameBytes; i++) - *(dest++) = *(src++); - else - for (i=0; i< frameBytes; i++) - *(dest++) += *(src++); - binFrame(); - } else { + //IDLog("Copying frame.\n"); + if (ImageColorS[0].s == ISS_ON) { + if (!stackMode) { + unsigned char *src, *dest; + src = v4l_base->getY(); + dest = (unsigned char *)PrimaryCCD.getFrameBuffer(); + for (i=0; i< frameBytes; i++) + *(dest++) = *(src++); + binFrame(); + } else { + float *src=V4LFrame->stackedFrame; + if ((stackMode != STACK_TAKE_DARK) && (V4LFrame->darkFrame != NULL)) { + float *dark=V4LFrame->darkFrame; + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) { + if (*src > *dark) *src -= *dark; + else *src = 0.0; + src++; dark++; + } + src=V4LFrame->stackedFrame; + } + //IDLog("Copying stack frame from %p to %p.\n", src, dest); + if (stackMode == STACK_MEAN) { + if (ImageDepthS[0].s == ISS_ON) { // depth 8 bits + unsigned char *dest=(unsigned char *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned char) ((*src++ * 255) / subframeCount ); + } else { // depth 16 bits + unsigned short *dest=(unsigned short *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned short) ((*src++ * 65535) / subframeCount ); + } + free(V4LFrame->stackedFrame); + V4LFrame->stackedFrame=NULL; + } else if (stackMode == STACK_ADDITIVE) { + if (ImageDepthS[0].s == ISS_ON) { // depth 8 bits + unsigned char *dest=(unsigned char *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned char) ((*src++ * 255)); + } else { // depth 16 bits + unsigned short *dest=(unsigned short *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned short) ((*src++ * 65535)); + } + free(V4LFrame->stackedFrame); + V4LFrame->stackedFrame=NULL; + } else if (stackMode == STACK_TAKE_DARK) { + if (V4LFrame->darkFrame != NULL) + free(V4LFrame->darkFrame); + V4LFrame->darkFrame = V4LFrame->stackedFrame; + V4LFrame->stackedFrame=NULL; + src=V4LFrame->darkFrame; + if (ImageDepthS[0].s == ISS_ON) { // depth 8 bits + unsigned char *dest=(unsigned char *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned char) ((*src++ * 255)); + } else { // depth 16 bits + unsigned short *dest=(unsigned short *)PrimaryCCD.getFrameBuffer(); + for (i=0; i < v4l_base->getWidth() * v4l_base->getHeight(); i++) + *dest++ = (unsigned short) ((*src++ * 65535)); + } + } + } + } else { + unsigned char *src, *dest; // Binning not supported in color images for now src = v4l_base->getColorBuffer(); dest = (unsigned char *)PrimaryCCD.getFrameBuffer(); unsigned char *red = dest; - unsigned char *green = dest + v4l_base->getWidth() * v4l_base->getHeight(); - unsigned char *blue = dest + v4l_base->getWidth() * v4l_base->getHeight() * 2; + unsigned char *green = dest + v4l_base->getWidth() * v4l_base->getHeight() * (v4l_base->getBpp() / 8); + unsigned char *blue = dest + v4l_base->getWidth() * v4l_base->getHeight() * (v4l_base->getBpp() / 8) * 2; for (int i=0; i < frameBytes; i+=4) { @@ -978,59 +1362,105 @@ *(red++) = *(src+i+2); } } - + //IDLog("Copy frame finished.\n"); frameCount+=1; + if (lx->isenabled()) { //if (!stackMode) //{ - v4l_base->stop_capturing(errmsg); - DEBUGF(INDI::Logger::DBG_SESSION, "Capture of LX frame took %ld.%06ld seconds.\n", current_exposure.tv_sec, current_exposure.tv_usec); + if (!is_streaming && !is_recording) stop_capturing(); + DEBUGF(INDI::Logger::DBG_SESSION, "Capture of LX frame took %ld.%06ld seconds.", current_exposure.tv_sec, current_exposure.tv_usec); ExposureComplete(&PrimaryCCD); PrimaryCCD.setFrameBufferSize(frameBytes); //} } else { - if (!stackMode || timercmp(¤t_exposure, &exposure_duration, >)) - { - v4l_base->stop_capturing(errmsg); - DEBUGF(INDI::Logger::DBG_SESSION, "Capture of ONE frame (%d stacked frames) took %ld.%06ld seconds.\n", frameCount, current_exposure.tv_sec, current_exposure.tv_usec); - ExposureComplete(&PrimaryCCD); - PrimaryCCD.setFrameBufferSize(frameBytes); - } + if (!is_streaming && !is_recording) stop_capturing(); + DEBUGF(INDI::Logger::DBG_SESSION, "Capture of one frame (%d stacked frames) took %ld.%06ld seconds.", subframeCount, current_exposure.tv_sec, current_exposure.tv_usec); + ExposureComplete(&PrimaryCCD); + PrimaryCCD.setFrameBufferSize(frameBytes); } + is_exposing=false; } } -void V4L2_Driver::recordStream() +void V4L2_Driver::updateExposure() { - if (RecordS[0].s == ISS_OFF) return; - if (ImageTypeS[0].s == ISS_ON) + + ExposureComplete(&PrimaryCCD); + PrimaryCCD.setFrameBufferSize(frameBytes); +} + +void V4L2_Driver::recordStream(double deltams) +{ + if (!is_recording) return; + if (ImageColorS[0].s == ISS_ON) recorder->writeFrameMono(v4l_base->getY()); else recorder->writeFrameColor(v4l_base->getRGBBuffer()); + recordDuration+=deltams; + recordframeCount+=1; + if ((RecordStreamSP.sp[1].s == ISS_ON) && (recordDuration >= (RecordOptionsNP.np[0].value * 1000.0))) { + DEBUGF(INDI::Logger::DBG_SESSION,"Ending record after %g millisecs", recordDuration); + stop_recording(); + RecordStreamSP.sp[1].s = ISS_OFF; RecordStreamSP.sp[3].s = ISS_ON; RecordStreamSP.s = IPS_IDLE; + IDSetSwitch(&RecordStreamSP, NULL); + } + if ((RecordStreamSP.sp[2].s == ISS_ON) && (recordframeCount >= (RecordOptionsNP.np[1].value))) { + DEBUGF(INDI::Logger::DBG_SESSION,"Ending record after %d frames", recordframeCount); + stop_recording(); + RecordStreamSP.sp[2].s = ISS_OFF; RecordStreamSP.sp[3].s = ISS_ON; RecordStreamSP.s = IPS_IDLE; + IDSetSwitch(&RecordStreamSP, NULL); + } } void V4L2_Driver::updateStream() { int width = v4l_base->getWidth(); int height = v4l_base->getHeight(); + int bpp = v4l_base->getBpp(); + int dbpp=8; // Streaming bpp is always 8 ? uLongf compressedBytes = 0; uLong totalBytes; unsigned char *targetFrame; int r; if (StreamS[0].s == ISS_OFF) return; + // v4l_base->getBpp() is capture bpp, PrimaryCCD.getBPP() is desired bpp + //IDLog("V4LFrame %dx%d bpp %d\n", V4LFrame->width, V4LFrame->height, V4LFrame->bpp); + //IDLog("Primary CCD %dx%d bpp %d\n", PrimaryCCD.getSubW(), PrimaryCCD.getSubH(), PrimaryCCD.getBPP()); - if (ImageTypeS[0].s == ISS_ON) + if (ImageColorS[0].s == ISS_ON) V4LFrame->Y = v4l_base->getY(); else V4LFrame->colorBuffer = v4l_base->getColorBuffer(); - totalBytes = ImageTypeS[0].s == ISS_ON ? width * height : width * height * 4; - targetFrame = ImageTypeS[0].s == ISS_ON ? V4LFrame->Y : V4LFrame->colorBuffer; + totalBytes = ImageColorS[0].s == ISS_ON ? width * height * (dbpp / 8) : width * height * (dbpp / 8) * 4; + targetFrame = ImageColorS[0].s == ISS_ON ? V4LFrame->Y : V4LFrame->colorBuffer; + // downscale Y10 Y12 Y16 + if (bpp > dbpp) { + unsigned int i; + unsigned short *src=(unsigned short *)targetFrame; + unsigned char *dest=targetFrame; + unsigned char shift=0; + if (bpp < 16) { + switch (bpp) { + case 10: shift=2; break; + case 12: shift=4; break; + } + for (i = 0; i < totalBytes; i++) { + *dest++ = *(src++) >> shift; + } + } else { + unsigned char *src=(unsigned char *)targetFrame + 1; // Y16 is little endian + for (i = 0; i < totalBytes; i++) { + *dest++ = *src; src+=2; + } + } + } /* Do we want to compress ? */ if (CompressS[0].s == ISS_ON) { @@ -1074,7 +1504,7 @@ if (lx->isenabled()) lx->stopLx(); else - v4l_base->stop_capturing(errmsg); + if (!is_streaming && !is_recording) stop_capturing(); return true; } @@ -1099,7 +1529,7 @@ if (!(strcmp((const char *)v4l_base->cap.driver, "pwc"))) - DEBUG(INDI::Logger::DBG_SESSION,"To use SPCLED Long exposure mode, load pwc module with \"modprobe pwc leds=0,255\""); + DEBUG(INDI::Logger::DBG_SESSION,"To use LED Long exposure mode with recent kernels, see https://code.google.com/p/pwc-lxled/"); } @@ -1109,8 +1539,8 @@ bool V4L2_Driver::Disconnect() { if (isConnected()) { - v4l_base->disconnectCam((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordSP.s == IPS_BUSY)); - if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordSP.s == IPS_BUSY)) + v4l_base->disconnectCam((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)); + if ((StreamSP.s == IPS_BUSY) || (ExposeTimeNP->s == IPS_BUSY) || (RecordStreamSP.s == IPS_BUSY)) recorder->close(); } return true; @@ -1140,6 +1570,7 @@ h = v4l_base->getHeight(); V4LFrame->width = w; V4LFrame->height= h; + V4LFrame->bpp=v4l_base->getBpp(); inputindex=IUFindOnSwitchIndex(&InputsSP); formatindex=IUFindOnSwitchIndex(&CaptureFormatsSP); @@ -1153,7 +1584,12 @@ IUSaveText(&camNameT[0], v4l_base->getDeviceName()); IDSetText(&camNameTP, NULL); - +#ifdef WITH_V4L2_EXPERIMENTS + IUSaveText(&CaptureColorSpaceT[0], getColorSpaceName(&v4l_base->fmt)); + IUSaveText(&CaptureColorSpaceT[1], getYCbCrEncodingName(&v4l_base->fmt)); + IUSaveText(&CaptureColorSpaceT[2], getQuantizationName(&v4l_base->fmt)); + IDSetText(&CaptureColorSpaceTP, NULL); +#endif if (Options) free(Options); Options=NULL; v4loptions=0; @@ -1162,8 +1598,9 @@ PrimaryCCD.setResolution(w, h); PrimaryCCD.setFrame(0,0, w,h); - frameBytes = (ImageTypeS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH()): - (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * 4); + PrimaryCCD.setBPP(V4LFrame->bpp); + frameBytes = (ImageColorS[0].s == ISS_ON) ? (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8)): + (PrimaryCCD.getSubW() * PrimaryCCD.getSubH() * (PrimaryCCD.getBPP() / 8) * 4); PrimaryCCD.setFrameBufferSize(frameBytes); direct_record=recorder->setpixelformat(v4l_base->fmt.fmt.pix.pixelformat); @@ -1229,6 +1666,8 @@ V4LFrame->V = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->colorBuffer = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1); + V4LFrame->stackedFrame = NULL; + V4LFrame->darkFrame = NULL; } void V4L2_Driver::releaseBuffers() @@ -1242,4 +1681,68 @@ free (V4LFrame); } +int V4L2_Driver::mkpath(std::string s, mode_t mode) { + size_t pre=0,pos; + std::string dir; + int mdret=0; + struct stat st; + + if(s[s.size()-1]!='/') s+='/'; + + while((pos=s.find_first_of('/',pre)) != std::string::npos){ + dir=s.substr(0,pos++); + pre=pos; + if(dir.size()==0) continue; + if (stat(dir.c_str(), &st)) { + if (errno != ENOENT || ((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST)) { + DEBUGF(INDI::Logger::DBG_WARNING,"mkpath: can not create %s", dir.c_str()); + return mdret; + } + } else { + if (!S_ISDIR(st.st_mode)) { + DEBUGF(INDI::Logger::DBG_WARNING,"mkpath: %s is not a directory", dir.c_str()); + return -1; + } + } + } + return mdret; +} + +std::string V4L2_Driver::expand(std::string fname, const std::map& patterns) { + std::string res = fname; + std::size_t pos; + time_t now; + struct tm *tm_now; + char val[20]; + *(val+19) = '\0'; + + time(&now); + tm_now = gmtime(&now); + + pos=res.find("_D_"); + if (pos != std::string::npos) { + strftime(val, 11, "%F", tm_now); + res.replace(pos, 3, val); + } + + pos=res.find("_T_"); + if (pos != std::string::npos) { + strftime(val, 20, "%F@%T", tm_now); + res.replace(pos, 3, val); + } + + pos=res.find("_H_"); + if (pos != std::string::npos) { + strftime(val, 9, "%T", tm_now); + res.replace(pos, 3, val); + } + for (std::map::const_iterator it=patterns.begin(); it!=patterns.end(); ++it) { + pos=res.find(it->first); + if (pos != std::string::npos) { + res.replace(pos, it->first.size(), it->second); + } + } + + return res; +} diff -Nru libindi-1.0.0/drivers/video/v4l2driver.h libindi-1.1.0/drivers/video/v4l2driver.h --- libindi-1.0.0/drivers/video/v4l2driver.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4l2driver.h 2015-09-06 13:17:35.000000000 +0000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,16 +42,19 @@ #include #include #include - +#include + #include "indidevapi.h" #include "indicom.h" #include #include "eventloop.h" + #include #include "webcam/v4l2_base.h" +#include "webcam/v4l2_colorspace.h" #include "webcam/v4l2_record/v4l2_record.h" #include "indiccd.h" @@ -84,6 +88,7 @@ virtual void initCamBase(); static void newFrame(void *p); + void stackFrame(); void updateFrame(); protected: @@ -100,34 +105,44 @@ typedef struct { int width; int height; - //int expose; + int bpp; + //int expose; double expose; unsigned char *Y; unsigned char *U; unsigned char *V; unsigned char *colorBuffer; unsigned char *compressedFrame; - unsigned char *stackedFrame; + float *stackedFrame; + float *darkFrame; } img_t; + enum stackmodes { STACK_NONE=0, STACK_MEAN=1, STACK_ADDITIVE=2, STACK_TAKE_DARK=3, STACK_RESET_DARK=4}; /* Switches */ ISwitch StreamS[2]; ISwitch *CompressS; - ISwitch ImageTypeS[2]; - ISwitch StackModeS[2]; - ISwitch RecordS[2]; + ISwitch ImageColorS[2]; + ISwitch ImageDepthS[2]; + ISwitch StackModeS[5]; + ISwitch RecordS[4]; ISwitch DropFrameS[2]; + ISwitch ColorProcessingS[3]; /* Texts */ IText PortT[1]; IText camNameT[1]; - IText RecordFileT[1]; + IText RecordFileT[2]; + IText CaptureColorSpaceT[3]; /* Numbers */ INumber *ExposeTimeN; INumber FrameRateN[1]; INumber *FrameN; + INumber FramestoDropN[1]; + INumber StreamOptionsN[1]; + INumber FpsN[2]; + INumber RecordOptionsN[2]; /* BLOBs */ IBLOBVectorProperty *imageBP; @@ -136,7 +151,8 @@ /* Switch vectors */ ISwitchVectorProperty StreamSP; /* Stream switch */ ISwitchVectorProperty *CompressSP; /* Compress stream switch */ - ISwitchVectorProperty ImageTypeSP; /* Color or grey switch */ + ISwitchVectorProperty ImageColorSP; /* Color or grey switch */ + ISwitchVectorProperty ImageDepthSP; /* 8 bits or 16 bits switch */ ISwitchVectorProperty StackModeSP; /* StackMode switch */ ISwitchVectorProperty InputsSP; /* Select input switch */ ISwitchVectorProperty CaptureFormatsSP; /* Select Capture format switch */ @@ -144,23 +160,28 @@ ISwitchVectorProperty FrameRatesSP; /* Select Frame rate (Discrete) */ ISwitchVectorProperty *Options; ISwitchVectorProperty DropFrameSP; + ISwitchVectorProperty ColorProcessingSP; unsigned int v4loptions; unsigned int v4ladjustments; bool useExtCtrl; - ISwitchVectorProperty RecordSP; /* Record switch */ + ISwitchVectorProperty RecordStreamSP; /* Record switch */ /* Number vectors */ - INumberVectorProperty *ExposeTimeNP; /* Exposure */ + INumberVectorProperty *ExposeTimeNP; /* Exposure */ + INumberVectorProperty StreamOptionsNP; /* Streaming Options */ + INumberVectorProperty FpsNP; /* Measured FPS */ INumberVectorProperty CaptureSizesNP; /* Select Capture size switch (Step/Continuous)*/ INumberVectorProperty FrameRateNP; /* Frame rate (Step/Continuous) */ INumberVectorProperty *FrameNP; /* Frame dimenstion */ INumberVectorProperty ImageAdjustNP; /* Image controls */ - + INumberVectorProperty FramestoDropNP; + INumberVectorProperty RecordOptionsNP; /* Record Options */ /* Text vectors */ ITextVectorProperty PortTP; ITextVectorProperty camNameTP; ITextVectorProperty RecordFileTP; + ITextVectorProperty CaptureColorSpaceTP; /* Pointers to optional properties */ INumber *AbsExposureN; @@ -169,23 +190,45 @@ /* Initilization functions */ //virtual void connectCamera(void); virtual void getBasicData(void); - + void allocateBuffers(); + void releaseBuffers(); + /* Stream/FITS functions */ + void updateExposure(); void updateStream(); - void recordStream(); + void recordStream(double deltams); - void allocateBuffers(); - void releaseBuffers(); + /* Shutter control */ + bool setShutter(double duration); bool setManualExposure(double duration); + bool startlongexposure(double timeinsec); + static void lxtimerCallback(void *userpointer); + + /* Post processing */ void binFrame(); + /* start/stop functions */ + void start_capturing(); + void stop_capturing(); + bool start_recording(); + bool stop_recording(); + virtual void updateV4L2Controls(); + /* Utility for record file */ + int mkpath(std::string s, mode_t mode); + std::string expand(std::string fname, const std::map& patterns); + + /* Variables */ V4L2_Base *v4l_base; char device_name[MAXINDIDEVICE]; unsigned char *fitsData; /* Buffer to hold the FITS file */ - int frameCount; /* For debugging */ + int streamframeCount; + int recordframeCount; + double recordDuration; + int subframeCount; /* For stacking */ + int frameCount; double divider; /* For limits */ img_t * V4LFrame; /* Video frame */ @@ -194,18 +237,30 @@ struct timeval exposure_duration; unsigned int stackMode; ulong frameBytes; + + bool is_capturing; + bool is_exposing; + bool is_streaming; + bool is_recording; //Long Exposure Lx *lx; int lxtimer; - bool startlongexposure(double timeinsec); - static void lxtimerCallback(void *userpointer); + short lxstate; // Record frames V4L2_Record *v4l2_record; V4L2_Recorder *recorder; bool direct_record; + std::string recordfiledir, recordfilename; /* in case we should move it */ + + // Measure FPS + // timer_t fpstimer; + // struct itimerspec tframe1, tframe2; + // use bsd timers + struct itimerval tframe1, tframe2; + double mssum, framecountsec; }; #endif diff -Nru libindi-1.0.0/drivers/video/v4ldriver.cpp libindi-1.1.0/drivers/video/v4ldriver.cpp --- libindi-1.0.0/drivers/video/v4ldriver.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4ldriver.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,846 +0,0 @@ -#if 0 - V4L INDI Driver - INDI Interface for V4L devices - Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#include "v4ldriver.h" - -V4L_Driver::V4L_Driver() -{ - allocateBuffers(); - - camNameT[0].text = NULL; - PortT[0].text = NULL; - IUSaveText(&PortT[0], "/dev/video0"); - - divider = 128.; -} - -V4L_Driver::~V4L_Driver() -{ - releaseBuffers(); -} - - -void V4L_Driver::initProperties(const char *dev) -{ - - strncpy(device_name, dev, MAXINDIDEVICE); - - /* Connection */ - IUFillSwitch(&PowerS[0], "CONNECT", "Connect", ISS_OFF); - IUFillSwitch(&PowerS[1], "DISCONNECT", "Disconnect", ISS_ON); - IUFillSwitchVector(&PowerSP, PowerS, NARRAY(PowerS), dev, "CONNECTION", "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); - - /* Port */ - IUFillText(&PortT[0], "PORT", "Port", "/dev/video0"); - IUFillTextVector(&PortTP, PortT, NARRAY(PortT), dev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE); - - /* Video Stream */ - IUFillSwitch(&StreamS[0], "ON", "Stream On", ISS_OFF); - IUFillSwitch(&StreamS[1], "OFF", "Stream Off", ISS_ON); - IUFillSwitchVector(&StreamSP, StreamS, NARRAY(StreamS), dev, "VIDEO_STREAM", "Video Stream", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - /* Compression */ - IUFillSwitch(&CompressS[0], "ON", "", ISS_ON); - IUFillSwitch(&CompressS[1], "OFF", "", ISS_OFF); - IUFillSwitchVector(&CompressSP, CompressS, NARRAY(StreamS), dev, "Compression", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - /* Image type */ - IUFillSwitch(&ImageTypeS[0], "Grey", "", ISS_ON); - IUFillSwitch(&ImageTypeS[1], "Color", "", ISS_OFF); - IUFillSwitchVector(&ImageTypeSP, ImageTypeS, NARRAY(ImageTypeS), dev, "Image Type", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - /* Camera Name */ - IUFillText(&camNameT[0], "Model", "", ""); - IUFillTextVector(&camNameTP, camNameT, NARRAY(camNameT), dev, "Camera Model", "", COMM_GROUP, IP_RO, 0, IPS_IDLE); - - /* Expose */ - IUFillNumber(&ExposeTimeN[0], "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., 0.5, 1.); - IUFillNumberVector(&ExposeTimeNP, ExposeTimeN, NARRAY(ExposeTimeN), dev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE); - -/* Frame Rate */ - IUFillNumber(&FrameRateN[0], "RATE", "Rate", "%0.f", 1., 50., 1., 10.); - IUFillNumberVector(&FrameRateNP, FrameRateN, NARRAY(FrameRateN), dev, "FRAME_RATE", "Frame Rate", COMM_GROUP, IP_RW, 60, IPS_IDLE); - - /* Frame dimension */ - IUFillNumber(&FrameN[0], "X", "X", "%.0f", 0., 0., 0., 0.); - IUFillNumber(&FrameN[1], "Y", "Y", "%.0f", 0., 0., 0., 0.); - IUFillNumber(&FrameN[2], "WIDTH", "Width", "%.0f", 0., 0., 10., 0.); - IUFillNumber(&FrameN[3], "HEIGHT", "Height", "%.0f", 0., 0., 10., 0.); - IUFillNumberVector(&FrameNP, FrameN, NARRAY(FrameN), dev, "CCD_FRAME", "Frame", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); - - /*IUFillNumber(&ImageSizeN[0], "WIDTH", "Width", "%0.f", 0., 0., 10., 0.); - IUFillNumber(&ImageSizeN[1], "HEIGHT", "Height", "%0.f", 0., 0., 10., 0.); - IUFillNumberVector(&ImageSizeNP, ImageSizeN, NARRAY(ImageSizeN), dev, "IMAGE_SIZE", "Image Size", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);*/ - - #ifndef HAVE_LINUX_VIDEODEV2_H - IUFillNumber(&ImageAdjustN[0], "Contrast", "", "%0.f", 0., 256., 1., 0.); - IUFillNumber(&ImageAdjustN[1], "Brightness", "", "%0.f", 0., 256., 1., 0.); - IUFillNumber(&ImageAdjustN[2], "Hue", "", "%0.f", 0., 256., 1., 0.); - IUFillNumber(&ImageAdjustN[3], "Color", "", "%0.f", 0., 256., 1., 0.); - IUFillNumber(&ImageAdjustN[4], "Whiteness", "", "%0.f", 0., 256., 1., 0.); - IUFillNumberVector(&ImageAdjustNP, ImageAdjustN, NARRAY(ImageAdjustN), dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); - #else - IUFillNumberVector(&ImageAdjustNP, NULL, 0, dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); - #endif - - // We need to setup the BLOB (Binary Large Object) below. Using this property, we can send FITS to our client - strcpy(imageB.name, "RAW_BLOB"); - strcpy(imageB.label, "Feed"); - strcpy(imageB.format, ""); - imageB.blob = 0; - imageB.bloblen = 0; - imageB.size = 0; - imageB.bvp = 0; - imageB.aux0 = 0; - imageB.aux1 = 0; - imageB.aux2 = 0; - - strcpy(imageBP.device, dev); - strcpy(imageBP.name, "RAW_STREAM"); - strcpy(imageBP.label, "Video"); - strcpy(imageBP.group, COMM_GROUP); - strcpy(imageBP.timestamp, ""); - imageBP.p = IP_RO; - imageBP.timeout = 0; - imageBP.s = IPS_IDLE; - imageBP.bp = &imageB; - imageBP.nbp = 1; - imageBP.aux = 0; - -} - -void V4L_Driver::initCamBase() -{ - v4l_base = new V4L2_Base(); -} - -void V4L_Driver::ISGetProperties (const char *dev) -{ - - if (dev && strcmp (device_name, dev)) - return; - - /* COMM_GROUP */ - IDDefSwitch(&PowerSP, NULL); - IDDefText(&PortTP, NULL); - IDDefText(&camNameTP, NULL); - IDDefSwitch(&StreamSP, NULL); - #ifndef HAVE_LINUX_VIDEODEV2_H - IDDefNumber(&FrameRateNP, NULL); - #endif - IDDefNumber(&ExposeTimeNP, NULL); - IDDefBLOB(&imageBP, NULL); - - /* Image properties */ - IDDefSwitch(&CompressSP, NULL); - IDDefSwitch(&ImageTypeSP, NULL); - IDDefNumber(&FrameNP, NULL); - - #ifndef HAVE_LINUX_VIDEODEV2_H - IDDefNumber(&ImageAdjustNP, NULL); - #endif - - - -} - -void V4L_Driver::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - char errmsg[ERRMSGSIZ]; - - /* ignore if not ours */ - if (dev && strcmp (device_name, dev)) - return; - - /* Connection */ - if (!strcmp (name, PowerSP.name)) - { - IUResetSwitch(&PowerSP); - IUUpdateSwitch(&PowerSP, states, names, n); - connectCamera(); - return; - } - - /* Compression */ - if (!strcmp(name, CompressSP.name)) - { - IUResetSwitch(&CompressSP); - IUUpdateSwitch(&CompressSP, states, names, n); - CompressSP.s = IPS_OK; - - IDSetSwitch(&CompressSP, NULL); - return; - } - - /* Image Type */ - if (!strcmp(name, ImageTypeSP.name)) - { - IUResetSwitch(&ImageTypeSP); - IUUpdateSwitch(&ImageTypeSP, states, names, n); - ImageTypeSP.s = IPS_OK; - - IDSetSwitch(&ImageTypeSP, NULL); - return; - } - - /* Video Stream */ - if (!strcmp(name, StreamSP.name)) - { - - if (checkPowerS(&StreamSP)) - return; - - IUResetSwitch(&StreamSP); - IUUpdateSwitch(&StreamSP, states, names, n); - StreamSP.s = IPS_IDLE; - - - v4l_base->stop_capturing(errmsg); - - if (StreamS[0].s == ISS_ON) - { - frameCount = 0; - IDLog("Starting the video stream.\n"); - StreamSP.s = IPS_BUSY; - v4l_base->start_capturing(errmsg); - } - else - { - IDLog("The video stream has been disabled. Frame count %d\n", frameCount); - v4l_base->stop_capturing(errmsg); - } - - IDSetSwitch(&StreamSP, NULL); - return; - } - -} - -void V4L_Driver::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int /*n*/) -{ - IText *tp; - - - /* ignore if not ours */ - if (dev && strcmp (device_name, dev)) - return; - - if (!strcmp(name, PortTP.name) ) - { - PortTP.s = IPS_OK; - tp = IUFindText( &PortTP, names[0] ); - if (!tp) - return; - - IUSaveText(tp, texts[0]); - IDSetText (&PortTP, NULL); - return; - } -} - -void V4L_Driver::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - char errmsg[ERRMSGSIZ]; - - /* ignore if not ours */ - if (dev && strcmp (device_name, dev)) - return; - - - /* Frame Size */ - if (!strcmp (FrameNP.name, name)) - { - if (checkPowerN(&FrameNP)) - return; - - int oldW = (int) FrameN[2].value; - int oldH = (int) FrameN[3].value; - - FrameNP.s = IPS_OK; - - if (IUUpdateNumber(&FrameNP, values, names, n) < 0) - return; - - if (v4l_base->setSize( (int) FrameN[2].value, (int) FrameN[3].value) != -1) - { - FrameN[2].value = v4l_base->getWidth(); - FrameN[3].value = v4l_base->getHeight(); - V4LFrame->width = (int) FrameN[2].value; - V4LFrame->height= (int) FrameN[3].value; - IDSetNumber(&FrameNP, NULL); - return; - } - else - { - FrameN[2].value = oldW; - FrameN[3].value = oldH; - FrameNP.s = IPS_ALERT; - IDSetNumber(&FrameNP, "Failed to set a new image size."); - } - - return; - } - - #ifndef HAVE_LINUX_VIDEODEV2_H - /* Frame rate */ - if (!strcmp (FrameRateNP.name, name)) - { - if (checkPowerN(&FrameRateNP)) - return; - - FrameRateNP.s = IPS_IDLE; - - if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0) - return; - - v4l_base->setFPS( (int) FrameRateN[0].value ); - - FrameRateNP.s = IPS_OK; - IDSetNumber(&FrameRateNP, NULL); - return; - } - #endif - - - if (!strcmp (ImageAdjustNP.name, name)) - { - if (checkPowerN(&ImageAdjustNP)) - return; - - ImageAdjustNP.s = IPS_IDLE; - - if (IUUpdateNumber(&ImageAdjustNP, values, names, n) < 0) - return; - - #ifndef HAVE_LINUX_VIDEODEV2_H - v4l_base->setContrast( (int) (ImageAdjustN[0].value * divider)); - v4l_base->setBrightness( (int) (ImageAdjustN[1].value * divider)); - v4l_base->setHue( (int) (ImageAdjustN[2].value * divider)); - v4l_base->setColor( (int) (ImageAdjustN[3].value * divider)); - v4l_base->setWhiteness( (int) (ImageAdjustN[4].value * divider)); - - ImageAdjustN[0].value = v4l_base->getContrast() / divider; - ImageAdjustN[1].value = v4l_base->getBrightness() / divider; - ImageAdjustN[2].value = v4l_base->getHue() / divider; - ImageAdjustN[3].value = v4l_base->getColor() / divider; - ImageAdjustN[4].value = v4l_base->getWhiteness() / divider; - - #else - unsigned int ctrl_id; - for (int i=0; i < ImageAdjustNP.nnp; i++) - { - ctrl_id = *((unsigned int *) ImageAdjustNP.np[i].aux0); - if (v4l_base->setINTControl( ctrl_id , ImageAdjustNP.np[i].value, errmsg) < 0) - { - ImageAdjustNP.s = IPS_ALERT; - IDSetNumber(&ImageAdjustNP, "Unable to adjust setting. %s", errmsg); - return; - } - } - #endif - - ImageAdjustNP.s = IPS_OK; - IDSetNumber(&ImageAdjustNP, NULL); - return; - } - - - /* Exposure */ - if (!strcmp (ExposeTimeNP.name, name)) - { - - if (checkPowerN(&ExposeTimeNP)) - return; - - //if (StreamS[0].s == ISS_ON) - v4l_base->stop_capturing(errmsg); - - StreamS[0].s = ISS_OFF; - StreamS[1].s = ISS_ON; - StreamSP.s = IPS_IDLE; - IDSetSwitch(&StreamSP, NULL); - - V4LFrame->expose = 1000; - - ExposeTimeNP.s = IPS_BUSY; - IDSetNumber(&ExposeTimeNP, NULL); - - time(&capture_start); - v4l_base->start_capturing(errmsg); - - return; - } - - - -} - -void V4L_Driver::newFrame(void *p) -{ - ((V4L_Driver *) (p))->updateFrame(); -} - -void V4L_Driver::updateFrame() -{ - char errmsg[ERRMSGSIZ]; - static const unsigned int FRAME_DROP = 2; - static int dropLarge = FRAME_DROP; - - if (StreamSP.s == IPS_BUSY) - { - // Ad hoc way of dropping frames - frameCount++; - dropLarge--; - if (dropLarge == 0) - { - dropLarge = (int) (((ImageTypeS[0].s == ISS_ON) ? FRAME_DROP : FRAME_DROP*3) * (FrameN[2].value / 160.0)); - updateStream(); - return; - } - } - else if (ExposeTimeNP.s == IPS_BUSY) - { - V4LFrame->Y = v4l_base->getY(); - v4l_base->stop_capturing(errmsg); - time(&capture_end); - IDLog("Capture of ONE frame took %g seconds.\n", difftime(capture_end, capture_start)); - grabImage(); - } - -} - -void V4L_Driver::updateStream() -{ - - int width = v4l_base->getWidth(); - int height = v4l_base->getHeight(); - uLongf compressedBytes = 0; - uLong totalBytes; - unsigned char *targetFrame; - int r; - - if (PowerS[0].s == ISS_OFF || StreamS[0].s == ISS_OFF) return; - - if (ImageTypeS[0].s == ISS_ON) - V4LFrame->Y = v4l_base->getY(); - else - V4LFrame->colorBuffer = v4l_base->getColorBuffer(); - - totalBytes = ImageTypeS[0].s == ISS_ON ? width * height : width * height * 4; - targetFrame = ImageTypeS[0].s == ISS_ON ? V4LFrame->Y : V4LFrame->colorBuffer; - - /* Do we want to compress ? */ - if (CompressS[0].s == ISS_ON) - { - /* Compress frame */ - V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); - - compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3; - - r = compress2(V4LFrame->compressedFrame, &compressedBytes, targetFrame, totalBytes, 4); - if (r != Z_OK) - { - /* this should NEVER happen */ - IDLog("internal error - compression failed: %d\n", r); - return; - } - - /* #3.A Send it compressed */ - imageB.blob = V4LFrame->compressedFrame; - imageB.bloblen = compressedBytes; - imageB.size = totalBytes; - strcpy(imageB.format, ".stream.z"); - } - else - { - /* #3.B Send it uncompressed */ - imageB.blob = targetFrame; - imageB.bloblen = totalBytes; - imageB.size = totalBytes; - strcpy(imageB.format, ".stream"); - } - - imageBP.s = IPS_OK; - IDSetBLOB (&imageBP, NULL); - - #ifndef HAVE_LINUX_VIDEODEV2_H - char errmsg[ERRMSGSIZ]; - v4l_base->start_capturing(errmsg); - #endif -} - -/* Downloads the image from the CCD row by row and store them - in a raw file. - N.B. No processing is done on the image */ -int V4L_Driver::grabImage() -{ - int err, fd; - char errmsg[ERRMSG_SIZE]; - char temp_filename[TEMPFILE_LEN] = "/tmp/fitsXXXXXX"; - - - if ((fd = mkstemp(temp_filename)) < 0) - { - IDMessage(device_name, "Error making temporary filename."); - IDLog("Error making temporary filename.\n"); - return -1; - } - close(fd); - - - err = writeFITS(temp_filename, errmsg); - if (err) - { - IDMessage(device_name, errmsg, NULL); - return -1; - } - - return 0; -} - -int V4L_Driver::writeFITS(const char * filename, char errmsg[]) -{ - fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */ - int status; - long fpixel = 1, naxis = 2, nelements; - long naxes[2]; - char filename_rw[TEMPFILE_LEN+1]; - - INDI_UNUSED(errmsg); - - // Append ! to file name to over write it. - snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename); - - naxes[0] = v4l_base->getWidth(); - naxes[1] = v4l_base->getHeight(); - - status = 0; /* initialize status before calling fitsio routines */ - fits_create_file(&fptr, filename_rw, &status); /* create new file */ - - /* Create the primary array image (16-bit short integer pixels */ - fits_create_img(fptr, BYTE_IMG, naxis, naxes, &status); - - addFITSKeywords(fptr); - - nelements = naxes[0] * naxes[1]; /* number of pixels to write */ - - /* Write the array of integers to the image */ - fits_write_img(fptr, TBYTE, fpixel, nelements, V4LFrame->Y, &status); - - fits_close_file(fptr, &status); /* close the file */ - - fits_report_error(stderr, status); /* print out any error messages */ - - /* Success */ - ExposeTimeNP.s = IPS_OK; - IDSetNumber(&ExposeTimeNP, NULL); - uploadFile(filename); - unlink(filename); - - return status; -} - -void V4L_Driver::addFITSKeywords(fitsfile *fptr) -{ - int status=0; - - char keyname[32], comment[64]; - - strncpy(keyname, "EXPOSURE", 32); - strncpy(comment, "Total Exposure Time (ms)", 64); - fits_update_key(fptr, TLONG, keyname , &(V4LFrame->expose), comment, &status); - - strncpy(keyname, "INSTRUME", 32); - strncpy(comment, "Webcam Name", 64); - fits_update_key(fptr, TSTRING, keyname, v4l_base->getDeviceName(), comment, &status); - - fits_write_date(fptr, &status); -} - -void V4L_Driver::uploadFile(const char * filename) -{ - - FILE * fitsFile; - int r=0; - unsigned int nr = 0; - uLong totalBytes; - uLongf compressedBytes = 0; - struct stat stat_p; - - if ( -1 == stat (filename, &stat_p)) - { - IDLog(" Error occurred attempting to stat %s\n", filename); - return; - } - - totalBytes = stat_p.st_size; - - fitsFile = fopen(filename, "r"); - - if (fitsFile == NULL) - return; - - fitsData = (fitsData == NULL) ? (unsigned char *) malloc(sizeof(unsigned char) * totalBytes) : - (unsigned char *) realloc(fitsData, sizeof(unsigned char) * totalBytes); - /* #1 Read file from disk */ - for (unsigned int i=0; i < totalBytes; i+= nr) - { - nr = fread(fitsData + i, 1, totalBytes - i, fitsFile); - - if (nr <= 0) - { - IDLog("Error reading temporary FITS file.\n"); - fclose(fitsFile); - return; - } - } - fclose(fitsFile); - - if (CompressS[0].s == ISS_ON) - { - /* #2 Compress it */ - V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); - - compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3; - - - r = compress2(V4LFrame->compressedFrame, &compressedBytes, fitsData, totalBytes, 9); - if (r != Z_OK) - { - /* this should NEVER happen */ - IDLog("internal error - compression failed: %d\n", r); - return; - } - - /* #3.A Send it compressed */ - imageB.blob = V4LFrame->compressedFrame; - imageB.bloblen = compressedBytes; - imageB.size = totalBytes; - strcpy(imageB.format, ".fits.z"); - } - else - { - imageB.blob = fitsData; - imageB.bloblen = totalBytes; - imageB.size = totalBytes; - strcpy(imageB.format, ".fits"); - } - - imageBP.s = IPS_OK; - IDSetBLOB (&imageBP, NULL); - -} - -void V4L_Driver::connectCamera() -{ - char errmsg[ERRMSGSIZ]; - - - switch (PowerS[0].s) - { - case ISS_ON: - if (v4l_base->connectCam(PortT[0].text, errmsg) < 0) - { - PowerSP.s = IPS_IDLE; - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - IDSetSwitch(&PowerSP, "Error: unable to open device"); - IDLog("Error: %s\n", errmsg); - return; - } - - /* Sucess! */ - PowerS[0].s = ISS_ON; - PowerS[1].s = ISS_OFF; - PowerSP.s = IPS_OK; - IDSetSwitch(&PowerSP, "Video4Linux Legacy Device is online. Retrieving basic data."); - - v4l_base->registerCallback(newFrame, this); - - IDLog("V4L Device is online. Retrieving basic data.\n"); - getBasicData(); - - break; - - case ISS_OFF: - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - PowerSP.s = IPS_IDLE; - - v4l_base->disconnectCam(true); - - IDSetSwitch(&PowerSP, "Video4Linux Legacy Device is offline."); - - break; - } -} - -/* Retrieves basic data from the device upon connection.*/ -void V4L_Driver::getBasicData() -{ - - int xmax, ymax, xmin, ymin; - - v4l_base->getMaxMinSize(xmax, ymax, xmin, ymin); - - /* Width */ - FrameN[2].value = v4l_base->getWidth(); - FrameN[2].min = xmin; - FrameN[2].max = xmax; - V4LFrame->width = (int) FrameN[2].value; - - /* Height */ - FrameN[3].value = v4l_base->getHeight(); - FrameN[3].min = ymin; - FrameN[3].max = ymax; - V4LFrame->height = (int) FrameN[3].value; - - IUUpdateMinMax(&FrameNP); - IDSetNumber(&FrameNP, NULL); - - IUSaveText(&camNameT[0], v4l_base->getDeviceName()); - IDSetText(&camNameTP, NULL); - - #ifndef HAVE_LINUX_VIDEODEV2_H - updateV4L1Controls(); - #else - updateV4L2Controls(); - #endif - -} - -#ifdef HAVE_LINUX_VIDEODEV2_H -void V4L_Driver::updateV4L2Controls() -{ - // #1 Query for INTEGER controls, and fill up the structure - free(ImageAdjustNP.np); - ImageAdjustNP.nnp = 0; - - if (v4l_base->queryINTControls(&ImageAdjustNP) > 0) - IDDefNumber(&ImageAdjustNP, NULL); -} -#else -void V4L_Driver::updateV4L1Controls() -{ - - if ( (v4l_base->getContrast() / divider) > ImageAdjustN[0].max) - divider *=2; - - if ( (v4l_base->getHue() / divider) > ImageAdjustN[2].max) - divider *=2; - - ImageAdjustN[0].value = v4l_base->getContrast() / divider; - ImageAdjustN[1].value = v4l_base->getBrightness() / divider; - ImageAdjustN[2].value = v4l_base->getHue() / divider; - ImageAdjustN[3].value = v4l_base->getColor() / divider; - ImageAdjustN[4].value = v4l_base->getWhiteness() / divider; - - ImageAdjustNP.s = IPS_OK; - IDSetNumber(&ImageAdjustNP, NULL); - -} -#endif - -int V4L_Driver::checkPowerS(ISwitchVectorProperty *sp) -{ - if (PowerSP.s != IPS_OK) - { - if (!strcmp(sp->label, "")) - IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->name); - else - IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->label); - - sp->s = IPS_IDLE; - IDSetSwitch(sp, NULL); - return -1; - } - - return 0; -} - -int V4L_Driver::checkPowerN(INumberVectorProperty *np) -{ - - if (PowerSP.s != IPS_OK) - { - if (!strcmp(np->label, "")) - IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->name); - else - IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->label); - - np->s = IPS_IDLE; - IDSetNumber(np, NULL); - return -1; - } - - return 0; -} - -int V4L_Driver::checkPowerT(ITextVectorProperty *tp) -{ - - if (PowerSP.s != IPS_OK) - { - if (!strcmp(tp->label, "")) - IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->name); - else - IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->label); - - tp->s = IPS_IDLE; - IDSetText(tp, NULL); - return -1; - } - - return 0; - -} - -void V4L_Driver::allocateBuffers() -{ - V4LFrame = (img_t *) malloc (sizeof(img_t)); - - if (V4LFrame == NULL) - { - IDMessage(NULL, "Error: unable to initialize driver. Low memory."); - IDLog("Error: unable to initialize driver. Low memory."); - exit(-1); - } - - fitsData = (unsigned char *) malloc (sizeof(unsigned char) * 1); - V4LFrame->Y = (unsigned char *) malloc (sizeof(unsigned char) * 1); - V4LFrame->U = (unsigned char *) malloc (sizeof(unsigned char) * 1); - V4LFrame->V = (unsigned char *) malloc (sizeof(unsigned char) * 1); - V4LFrame->colorBuffer = (unsigned char *) malloc (sizeof(unsigned char) * 1); - V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1); -} - -void V4L_Driver::releaseBuffers() -{ - free(fitsData); - free(V4LFrame->Y); - free(V4LFrame->U); - free(V4LFrame->V); - free(V4LFrame->colorBuffer); - free(V4LFrame->compressedFrame); - free (V4LFrame); -} - - diff -Nru libindi-1.0.0/drivers/video/v4ldriver.h libindi-1.1.0/drivers/video/v4ldriver.h --- libindi-1.0.0/drivers/video/v4ldriver.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4ldriver.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,177 +0,0 @@ -#if 0 - V4L INDI Driver - INDI Interface for V4L devices - Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) - - 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 - -#endif - -#ifndef V4L_DRIVER_H -#define V4L_DRIVER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "indidevapi.h" -#include "indicom.h" -#include -#include "eventloop.h" - -#include - -#ifdef HAVE_LINUX_VIDEODEV2_H -#include "webcam/v4l2_base.h" -#else -#include "webcam/v4l1_base.h" -#endif - -#define COMM_GROUP "Main Control" -#define IMAGE_CONTROL "Image Control" -#define IMAGE_GROUP "Image Settings" - -#define MAX_PIXELS 4096 /* Max number of pixels in one dimension */ -#define ERRMSGSIZ 1024 - -#define TEMPFILE_LEN 16 - - -class V4L_Driver -{ - public: - V4L_Driver(); - virtual ~V4L_Driver(); - - /* INDI Functions that must be called from indidrivermain */ - virtual void ISGetProperties (const char *dev); - virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - - virtual void initCamBase(); - virtual void initProperties(const char *dev); - - static void newFrame(void *p); - void updateFrame(); - - protected: - - /* Structs */ - typedef struct { - int width; - int height; - int expose; - unsigned char *Y; - unsigned char *U; - unsigned char *V; - unsigned char *colorBuffer; - unsigned char *compressedFrame; - } img_t; - - - /* Switches */ - ISwitch PowerS[2]; - ISwitch StreamS[2]; - ISwitch CompressS[2]; - ISwitch ImageTypeS[2]; - - /* Texts */ - IText PortT[1]; - IText camNameT[1]; - - /* Numbers */ - INumber ExposeTimeN[1]; - INumber FrameRateN[1]; - INumber FrameN[4]; - #ifndef HAVE_LINUX_VIDEODEV2_H - INumber ImageAdjustN[5]; - #endif - - /* BLOBs */ - IBLOB imageB; - - /* Switch vectors */ - ISwitchVectorProperty PowerSP; /* Connection switch */ - ISwitchVectorProperty StreamSP; /* Stream switch */ - ISwitchVectorProperty CompressSP; /* Compress stream switch */ - ISwitchVectorProperty ImageTypeSP; /* Color or grey switch */ - - /* Number vectors */ - INumberVectorProperty ExposeTimeNP; /* Exposure */ - INumberVectorProperty FrameRateNP; /* Frame rate */ - INumberVectorProperty FrameNP; /* Stream dimenstion */ - INumberVectorProperty ImageAdjustNP; /* Image controls */ - - /* Text vectors */ - ITextVectorProperty PortTP; - ITextVectorProperty camNameTP; - - /* BLOB vectors */ - IBLOBVectorProperty imageBP; /* Data stream */ - - /* Initilization functions */ - virtual void connectCamera(void); - virtual void getBasicData(void); - - /* Stream/FITS functions */ - void updateStream(); - void uploadFile(const char * filename); - int writeFITS(const char *filename, char errmsg[]); - int grabImage(void); - void addFITSKeywords(fitsfile *fptr); - void allocateBuffers(); - void releaseBuffers(); - - /* Helper functions */ - int checkPowerN(INumberVectorProperty *np); - int checkPowerS(ISwitchVectorProperty *sp); - int checkPowerT(ITextVectorProperty *tp); - - #ifndef HAVE_LINUX_VIDEODEV2_H - virtual void updateV4L1Controls(); - V4L1_Base *v4l_base; - #else - virtual void updateV4L2Controls(); - V4L2_Base *v4l_base; - #endif - - char device_name[MAXINDIDEVICE]; - unsigned char *fitsData; /* Buffer to hold the FITS file */ - int frameCount; /* For debugging */ - double divider; /* For limits */ - img_t * V4LFrame; /* Video frame */ - - time_t capture_start; /* To calculate how long a frame take */ - time_t capture_end; - -}; - -#endif diff -Nru libindi-1.0.0/drivers/video/v4lphilips.cpp libindi-1.1.0/drivers/video/v4lphilips.cpp --- libindi-1.0.0/drivers/video/v4lphilips.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4lphilips.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,667 +0,0 @@ -/* - Phlips webcam INDI driver - Copyright (C) 2003-2005 by 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 - - 2005.04.29 JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility. - -*/ - -#include "v4lphilips.h" -#include "webcam/pwc-ioctl.h" - -V4L_Philips::V4L_Philips() : V4L_Driver() -{ - -} - -V4L_Philips::~V4L_Philips() -{ - -} - -void V4L_Philips::initCamBase() -{ - #ifdef HAVE_LINUX_VIDEODEV2_H - v4l_base = new V4L2_Base(); - #else - v4l_pwc = new V4L1_PWC(); - v4l_base = (V4L1_Base *) v4l_pwc; - #endif -} - -void V4L_Philips::initProperties(const char *dev) -{ - - // Call parent - V4L_Driver::initProperties(dev); - - IUFillSwitch(&BackLightS[0], "ON", "", ISS_OFF); - IUFillSwitch(&BackLightS[1], "OFF", "", ISS_ON); - IUFillSwitchVector(&BackLightSP, BackLightS, NARRAY(BackLightS), dev, "Back Light", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE); - - IUFillSwitch(&AntiFlickerS[0], "ON", "", ISS_OFF); - IUFillSwitch(&AntiFlickerS[1], "OFF", "", ISS_ON); - IUFillSwitchVector(&AntiFlickerSP, AntiFlickerS, NARRAY(AntiFlickerS), dev, "Anti Flicker", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE); - - IUFillSwitch(&NoiseReductionS[0], "None", "", ISS_ON); - IUFillSwitch(&NoiseReductionS[1], "Low", "", ISS_OFF); - IUFillSwitch(&NoiseReductionS[2], "Medium", "", ISS_OFF); - IUFillSwitch(&NoiseReductionS[3], "High", "", ISS_OFF); - IUFillSwitchVector(&NoiseReductionSP, NoiseReductionS, NARRAY(NoiseReductionS), dev, "Noise Reduction", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - IUFillSwitch(&CamSettingS[0], "Save", "", ISS_OFF); - IUFillSwitch(&CamSettingS[1], "Restore", "", ISS_OFF); - IUFillSwitch(&CamSettingS[2], "Factory", "", ISS_OFF); - IUFillSwitchVector(&CamSettingSP, CamSettingS, NARRAY(CamSettingS), dev, "Settings", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - IUFillSwitch(&WhiteBalanceModeS[0], "Auto" , "", ISS_ON); - IUFillSwitch(&WhiteBalanceModeS[1], "Manual" , "", ISS_OFF); - IUFillSwitch(&WhiteBalanceModeS[2], "Indoor" , "", ISS_OFF); - IUFillSwitch(&WhiteBalanceModeS[3], "Outdoor" , "", ISS_OFF); - IUFillSwitch(&WhiteBalanceModeS[4], "Fluorescent" , "", ISS_OFF); - - IUFillSwitchVector(&WhiteBalanceModeSP, WhiteBalanceModeS, NARRAY(WhiteBalanceModeS), dev, "White Balance Mode", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); - - IUFillNumber(&WhiteBalanceN[0], "Manual Red", "", "%0.f", 0., 256., 1., 0.); - IUFillNumber(&WhiteBalanceN[1], "Manual Blue", "", "%0.f", 0., 256., 1., 0.); - IUFillNumberVector(&WhiteBalanceNP, WhiteBalanceN, NARRAY(WhiteBalanceN), dev, "White Balance", "", IMAGE_CONTROL, IP_RW, 60, IPS_IDLE); - - IUFillNumber(&ShutterSpeedN[0], "Speed", "", "%0.f", 0., 65535., 100., 0.); - IUFillNumberVector(&ShutterSpeedNP, ShutterSpeedN, NARRAY(ShutterSpeedN), dev, "Shutter Speed", "", COMM_GROUP, IP_RW, 60, IPS_IDLE); - -} - -void V4L_Philips::ISGetProperties (const char *dev) -{ - - if (dev && strcmp (device_name, dev)) - return; - - #ifdef HAVE_LINUX_VIDEODEV2_H - V4L_Driver::ISGetProperties(dev); - return; - #endif - - /* COMM_GROUP */ - IDDefSwitch(&PowerSP, NULL); - IDDefText(&PortTP, NULL); - IDDefText(&camNameTP, NULL); - IDDefSwitch(&StreamSP, NULL); - IDDefNumber(&FrameRateNP, NULL); - IDDefNumber(&ExposeTimeNP, NULL); - IDDefNumber(&ShutterSpeedNP, NULL); - IDDefBLOB(&imageBP, NULL); - - /* Image Groups */ - IDDefSwitch(&CompressSP, NULL); - IDDefSwitch(&ImageTypeSP, NULL); - IDDefNumber(&FrameNP, NULL); - IDDefNumber(&ImageAdjustNP, NULL); - - /* Image Control */ - IDDefSwitch(&WhiteBalanceModeSP, NULL); - IDDefNumber(&WhiteBalanceNP, NULL); - IDDefSwitch(&BackLightSP, NULL); - IDDefSwitch(&AntiFlickerSP, NULL); - IDDefSwitch(&NoiseReductionSP, NULL); - IDDefSwitch(&CamSettingSP, NULL); - -} - -void V4L_Philips::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - /* ignore if not ours */ - if (dev && strcmp (device_name, dev)) - return; - - /* Connection */ - if (!strcmp (name, PowerSP.name)) - { - IUResetSwitch(&PowerSP); - IUUpdateSwitch(&PowerSP, states, names, n); - connectCamera(); - return; - } - - - #ifndef HAVE_LINUX_VIDEODEV2_H - /* Anti Flicker control */ - if (!strcmp (AntiFlickerSP.name, name)) - { - if (checkPowerS(&AntiFlickerSP)) - return; - - AntiFlickerSP.s = IPS_IDLE; - - IUResetSwitch(&AntiFlickerSP); - IUUpdateSwitch(&AntiFlickerSP, states, names, n); - - if (AntiFlickerS[0].s == ISS_ON) - { - if (v4l_pwc->setFlicker(true, errmsg) < 0) - { - AntiFlickerS[0].s = ISS_OFF; - AntiFlickerS[1].s = ISS_ON; - IDSetSwitch(&AntiFlickerSP, "%s", errmsg); - return; - } - - AntiFlickerSP.s = IPS_OK; - IDSetSwitch(&AntiFlickerSP, NULL); - } - else - { - if (v4l_pwc->setFlicker(false, errmsg) < 0) - { - AntiFlickerS[0].s = ISS_ON; - AntiFlickerS[1].s = ISS_OFF; - IDSetSwitch(&AntiFlickerSP, "%s", errmsg); - return; - } - - IDSetSwitch(&AntiFlickerSP, NULL); - } - - return; - } - - /* Back light compensation */ - if (!strcmp (BackLightSP.name, name)) - { - if (checkPowerS(&BackLightSP)) - return; - - BackLightSP.s = IPS_IDLE; - - IUResetSwitch(&BackLightSP); - IUUpdateSwitch(&BackLightSP, states, names, n); - - if (BackLightS[0].s == ISS_ON) - { - if (v4l_pwc->setBackLight(true, errmsg) < 0) - { - BackLightS[0].s = ISS_OFF; - BackLightS[1].s = ISS_ON; - IDSetSwitch(&BackLightSP, "%s", errmsg); - return; - } - - BackLightSP.s = IPS_OK; - IDSetSwitch(&BackLightSP, NULL); - } - else - { - if (v4l_pwc->setBackLight(false, errmsg) < 0) - { - BackLightS[0].s = ISS_ON; - BackLightS[1].s = ISS_OFF; - IDSetSwitch(&BackLightSP, "%s", errmsg); - return; - } - - IDSetSwitch(&BackLightSP, NULL); - } - - return; - } - - /* Noise reduction control */ - if (!strcmp (NoiseReductionSP.name, name)) - { - if (checkPowerS(&NoiseReductionSP)) - return; - - NoiseReductionSP.s = IPS_IDLE; - - IUResetSwitch(&NoiseReductionSP); - IUUpdateSwitch(&NoiseReductionSP, states, names, n); - - for (int i=0; i < 4; i++) - if (NoiseReductionS[i].s == ISS_ON) - { - index = i; - break; - } - - if (v4l_pwc->setNoiseRemoval(index, errmsg) < 0) - { - IUResetSwitch(&NoiseReductionSP); - NoiseReductionS[0].s = ISS_ON; - IDSetSwitch(&NoiseReductionSP, "%s", errmsg); - return; - } - - NoiseReductionSP.s = IPS_OK; - - IDSetSwitch(&NoiseReductionSP, NULL); - return; - } - - /* White balace mode */ - if (!strcmp (WhiteBalanceModeSP.name, name)) - { - if (checkPowerS(&WhiteBalanceModeSP)) - return; - - WhiteBalanceModeSP.s = IPS_IDLE; - - IUResetSwitch(&WhiteBalanceModeSP); - IUUpdateSwitch(&WhiteBalanceModeSP, states, names, n); - - for (int i=0; i < 5; i++) - if (WhiteBalanceModeS[i].s == ISS_ON) - { - index = i; - break; - } - - switch (index) - { - // Auto - case 0: - if (v4l_pwc->setWhiteBalanceMode(PWC_WB_AUTO, errmsg) < 0) - { - IUResetSwitch(&WhiteBalanceModeSP), - WhiteBalanceModeS[0].s = ISS_ON; - IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); - return; - } - break; - - // Manual - case 1: - if (v4l_pwc->setWhiteBalanceMode(PWC_WB_MANUAL, errmsg) < 0) - { - IUResetSwitch(&WhiteBalanceModeSP), - WhiteBalanceModeS[0].s = ISS_ON; - IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); - return; - } - break; - - // Indoor - case 2: - if (v4l_pwc->setWhiteBalanceMode(PWC_WB_INDOOR, errmsg) < 0) - { - IUResetSwitch(&WhiteBalanceModeSP), - WhiteBalanceModeS[0].s = ISS_ON; - IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); - return; - } - break; - - // Outdoor - case 3: - if (v4l_pwc->setWhiteBalanceMode(PWC_WB_OUTDOOR, errmsg) < 0) - { - IUResetSwitch(&WhiteBalanceModeSP), - WhiteBalanceModeS[0].s = ISS_ON; - IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); - return; - } - break; - - // Flurescent - case 4: - if (v4l_pwc->setWhiteBalanceMode(PWC_WB_FL, errmsg) < 0) - { - IUResetSwitch(&WhiteBalanceModeSP), - WhiteBalanceModeS[0].s = ISS_ON; - IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); - return; - } - break; - - } - - WhiteBalanceModeSP.s = IPS_OK; - IDSetSwitch(&WhiteBalanceModeSP, NULL); - return; - - } - - /* Camera setttings */ - if (!strcmp (CamSettingSP.name, name)) - { - - if (checkPowerS(&CamSettingSP)) - return; - - CamSettingSP.s = IPS_IDLE; - - IUResetSwitch(&CamSettingSP); - IUUpdateSwitch(&CamSettingSP, states, names, n); - - if (CamSettingS[0].s == ISS_ON) - { - if (v4l_pwc->saveSettings(errmsg) < 0) - { - IUResetSwitch(&CamSettingSP); - IDSetSwitch(&CamSettingSP, "%s", errmsg); - return; - } - - CamSettingSP.s = IPS_OK; - IDSetSwitch(&CamSettingSP, "Settings saved."); - return; - } - - if (CamSettingS[1].s == ISS_ON) - { - v4l_pwc->restoreSettings(); - IUResetSwitch(&CamSettingSP); - CamSettingSP.s = IPS_OK; - IDSetSwitch(&CamSettingSP, "Settings restored."); - updateV4L1Controls(); - return; - } - - if (CamSettingS[2].s == ISS_ON) - { - v4l_pwc->restoreFactorySettings(); - IUResetSwitch(&CamSettingSP); - CamSettingSP.s = IPS_OK; - IDSetSwitch(&CamSettingSP, "Factory settings restored."); - updateV4L1Controls(); - return; - } - } - #endif - - // Call parent - V4L_Driver::ISNewSwitch(dev, name, states, names, n); - - - -} - -void V4L_Philips::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) -{ - - V4L_Driver::ISNewText(dev, name, texts, names, n); - -} - -void V4L_Philips::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) -{ - - // Nothing for V4L 2 to do here - #ifndef HAVE_LINUX_VIDEODEV2_H - char errmsg[ERRMSGSIZ]; - - /* Frame rate */ - if (!strcmp (FrameRateNP.name, name)) - { - if (checkPowerN(&FrameRateNP)) - return; - - FrameRateNP.s = IPS_IDLE; - - int oldFP = (int) FrameRateN[0].value; - - if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0) - return; - - if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0) - { - FrameRateN[0].value = oldFP; - IDSetNumber(&FrameRateNP, "%s", errmsg); - return; - } - - FrameRateNP.s = IPS_OK; - IDSetNumber(&FrameRateNP, NULL); - return; - } - - if (!strcmp (ShutterSpeedNP.name, name)) - { - if (checkPowerN(&ShutterSpeedNP)) - return; - - ShutterSpeedNP.s = IPS_IDLE; - - if (v4l_pwc->setExposure( (int) values[0], errmsg) < 0) - { - IDSetNumber(&ShutterSpeedNP, "%s", errmsg); - return; - } - - ShutterSpeedN[0].value = values[0]; - ShutterSpeedNP.s = IPS_OK; - IDSetNumber(&ShutterSpeedNP, NULL); - return; - } - - /* White balance */ - if (!strcmp (WhiteBalanceNP.name, name)) - { - if (checkPowerN(&WhiteBalanceNP)) - return; - - WhiteBalanceNP.s = IPS_IDLE; - - int oldBalance[2]; - oldBalance[0] = (int) WhiteBalanceN[0].value; - oldBalance[1] = (int) WhiteBalanceN[1].value; - - if (IUUpdateNumber(&WhiteBalanceNP, values, names, n) < 0) - return; - - if (v4l_pwc->setWhiteBalanceRed( (int) WhiteBalanceN[0].value * 256, errmsg)) - { - WhiteBalanceN[0].value = oldBalance[0]; - WhiteBalanceN[1].value = oldBalance[1]; - IDSetNumber(&WhiteBalanceNP, "%s", errmsg); - return; - } - if (v4l_pwc->setWhiteBalanceBlue( (int) WhiteBalanceN[1].value * 256, errmsg)) - { - WhiteBalanceN[0].value = oldBalance[0]; - WhiteBalanceN[1].value = oldBalance[1]; - IDSetNumber(&WhiteBalanceNP, "%s", errmsg); - return; - } - - IUResetSwitch(&WhiteBalanceModeSP); - WhiteBalanceModeS[1].s = ISS_ON; - WhiteBalanceModeSP.s = IPS_OK; - WhiteBalanceNP.s = IPS_OK; - IDSetSwitch(&WhiteBalanceModeSP, NULL); - IDSetNumber(&WhiteBalanceNP, NULL); - return; - } - - #endif - - // Call parent - V4L_Driver::ISNewNumber(dev, name, values, names, n); - -} - -void V4L_Philips::connectCamera() -{ - char errmsg[ERRMSGSIZ]; - - - switch (PowerS[0].s) - { - case ISS_ON: - #ifdef HAVE_LINUX_VIDEODEV2_H - if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_YUV420) < 0) - #else - if (v4l_base->connectCam(PortT[0].text, errmsg) < 0) - #endif - { - PowerSP.s = IPS_IDLE; - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - IDSetSwitch(&PowerSP, "Error: unable to open device"); - IDLog("Error: %s\n", errmsg); - return; - } - - /* Sucess! */ - PowerS[0].s = ISS_ON; - PowerS[1].s = ISS_OFF; - PowerSP.s = IPS_OK; - IDSetSwitch(&PowerSP, "Philips Webcam is online. Retrieving basic data."); - - v4l_base->registerCallback(newFrame, this); - - IDLog("Philips Webcam is online. Retrieving basic data.\n"); - getBasicData(); - - break; - - case ISS_OFF: - PowerS[0].s = ISS_OFF; - PowerS[1].s = ISS_ON; - PowerSP.s = IPS_IDLE; - - v4l_base->disconnectCam(true); - - IDSetSwitch(&PowerSP, "Philips Webcam is offline."); - - break; - } -} - -#ifndef HAVE_LINUX_VIDEODEV2_H -/* Retrieves basic data from the device upon connection.*/ -void V4L_Philips::getBasicData() -{ - - char errmsg[ERRMSGSIZ]; - bool result; - int xmax, ymax, xmin, ymin, index; - - v4l_pwc->getMaxMinSize(xmax, ymax, xmin, ymin); - - IDLog("X (%d,%d), Y (%d,%d)\n", xmin, xmax, ymin, ymax); - - /* Width */ - FrameN[2].value = v4l_pwc->getWidth(); - FrameN[2].min = xmin; - FrameN[2].max = xmax; - - /* Height */ - FrameN[3].value = v4l_pwc->getHeight(); - FrameN[3].min = ymin; - FrameN[3].max = ymax; - - IDSetNumber(&FrameNP, NULL); - IUUpdateMinMax(&FrameNP); - - IUSaveText(&camNameT[0], v4l_pwc->getDeviceName()); - IDSetText(&camNameTP, NULL); - - IDLog("Raw values\n Contrast: %d \n Brightness %d \n Color %d \n Sharpness %d \n Gain %d \n Gamma %d \n", v4l_pwc->getContrast(), v4l_pwc->getBrightness(), v4l_pwc->getColor(), v4l_pwc->getSharpness(), v4l_pwc->getGain(), v4l_pwc->getGama()); - - updateV4L1Controls(); - - if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0) - { - FrameRateNP.s = IPS_ALERT; - IDSetNumber(&FrameRateNP, "%s", errmsg); - } - else - { - FrameRateNP.s = IPS_OK; - IDSetNumber(&FrameRateNP, NULL); - } - - result = v4l_pwc->getBackLight(); - if (result) - { - BackLightS[0].s = ISS_ON; - BackLightS[1].s = ISS_OFF; - } - else - { - BackLightS[0].s = ISS_OFF; - BackLightS[1].s = ISS_ON; - } - IDSetSwitch(&BackLightSP, NULL); - - result = v4l_pwc->getFlicker(); - if (result) - { - AntiFlickerS[0].s = ISS_ON; - AntiFlickerS[1].s = ISS_OFF; - } - else - { - AntiFlickerS[0].s = ISS_OFF; - AntiFlickerS[1].s = ISS_ON; - } - IDSetSwitch(&AntiFlickerSP, NULL); - - index = v4l_pwc->getNoiseRemoval(); - IUResetSwitch(&NoiseReductionSP); - NoiseReductionS[index].s = ISS_ON; - IDSetSwitch(&NoiseReductionSP, NULL); - - index = v4l_pwc->getWhiteBalance(); - IUResetSwitch(&WhiteBalanceModeSP); - switch (index) - { - case PWC_WB_AUTO: - WhiteBalanceModeS[0].s = ISS_ON; - break; - case PWC_WB_MANUAL: - WhiteBalanceModeS[1].s = ISS_ON; - break; - case PWC_WB_INDOOR: - WhiteBalanceModeS[2].s = ISS_ON; - break; - case PWC_WB_OUTDOOR: - WhiteBalanceModeS[3].s = ISS_ON; - break; - case PWC_WB_FL: - WhiteBalanceModeS[3].s = ISS_ON; - break; - } - IDSetSwitch(&WhiteBalanceModeSP, NULL); - -} -#endif - -#ifndef HAVE_LINUX_VIDEODEV2_H -void V4L_Philips::updateV4L1Controls() -{ - int index =0; - - ImageAdjustN[0].value = v4l_pwc->getContrast() / 256.; - ImageAdjustN[1].value = v4l_pwc->getBrightness() / 256.; - ImageAdjustN[2].value = v4l_pwc->getColor() / 256.; - index = v4l_pwc->getSharpness(); - if (index < 0) - ImageAdjustN[3].value = -1; - else - ImageAdjustN[3].value = v4l_pwc->getSharpness() / 256.; - - ImageAdjustN[4].value = v4l_pwc->getGain() / 256.; - ImageAdjustN[5].value = v4l_pwc->getGama() / 256.; - - ImageAdjustNP.s = IPS_OK; - IDSetNumber(&ImageAdjustNP, NULL); - - -} -#endif - diff -Nru libindi-1.0.0/drivers/video/v4lphilips.h libindi-1.1.0/drivers/video/v4lphilips.h --- libindi-1.0.0/drivers/video/v4lphilips.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers/video/v4lphilips.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/* - Phlips webcam INDI driver - Copyright (C) 2003-2005 by 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 - - 2005.04.29 JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility. - -*/ - -#ifndef V4LPHILIPS_H -#define V4LPHILIPS_H - - - -#ifndef HAVE_LINUX_VIDEODEV2_H -#include "webcam/v4l1_pwc.h" -#endif - -#include "v4ldriver.h" - -class V4L_Philips : public V4L_Driver -{ - public: - V4L_Philips(); - ~V4L_Philips(); - - /* INDI Functions that must be called from indidrivermain */ - void ISGetProperties (const char *dev); - void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - - void initCamBase(); - void initProperties(const char *dev); - void connectCamera(void); - - private: - - /* Switches */ - ISwitch BackLightS[2]; - ISwitch AntiFlickerS[2]; - ISwitch NoiseReductionS[4]; - ISwitch CamSettingS[3]; - ISwitch WhiteBalanceModeS[5]; - - - /* Nmubers */ - INumber WhiteBalanceN[2]; - INumber ShutterSpeedN[1]; - - /* Switch Vectors */ - ISwitchVectorProperty BackLightSP; - ISwitchVectorProperty AntiFlickerSP; - ISwitchVectorProperty NoiseReductionSP; - ISwitchVectorProperty CamSettingSP; - ISwitchVectorProperty WhiteBalanceModeSP; - - /* Number Vectors */ - INumberVectorProperty WhiteBalanceNP; - INumberVectorProperty ShutterSpeedNP; - - #ifndef HAVE_LINUX_VIDEODEV2_H - V4L1_PWC * v4l_pwc; - void updateV4L1Controls(); - void getBasicData(void); - #endif - -}; - -#endif - diff -Nru libindi-1.0.0/drivers/weather/gason.cpp libindi-1.1.0/drivers/weather/gason.cpp --- libindi-1.0.0/drivers/weather/gason.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/weather/gason.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,357 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2015 Ivan Vashchaev + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "gason.h" +#include + +#define JSON_ZONE_SIZE 4096 +#define JSON_STACK_SIZE 32 + +const char *jsonStrError(int err) { + switch (err) { +#define XX(no, str) \ + case JSON_##no: \ + return str; + JSON_ERRNO_MAP(XX) +#undef XX + default: + return "unknown"; + } +} + +void *JsonAllocator::allocate(size_t size) { + size = (size + 7) & ~7; + + if (head && head->used + size <= JSON_ZONE_SIZE) { + char *p = (char *)head + head->used; + head->used += size; + return p; + } + + size_t allocSize = sizeof(Zone) + size; + Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); + if (zone == nullptr) + return nullptr; + zone->used = allocSize; + if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { + zone->next = head; + head = zone; + } else { + zone->next = head->next; + head->next = zone; + } + return (char *)zone + sizeof(Zone); +} + +void JsonAllocator::deallocate() { + while (head) { + Zone *next = head->next; + free(head); + head = next; + } +} + +static inline bool isspace(char c) { + return c == ' ' || (c >= '\t' && c <= '\r'); +} + +static inline bool isdelim(char c) { + return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c; +} + +static inline bool isdigit(char c) { + return c >= '0' && c <= '9'; +} + +static inline bool isxdigit(char c) { + return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); +} + +static inline int char2int(char c) { + if (c <= '9') + return c - '0'; + return (c & ~' ') - 'A' + 10; +} + +static double string2double(char *s, char **endptr) { + char ch = *s; + if (ch == '-') + ++s; + + double result = 0; + while (isdigit(*s)) + result = (result * 10) + (*s++ - '0'); + + if (*s == '.') { + ++s; + + double fraction = 1; + while (isdigit(*s)) { + fraction *= 0.1; + result += (*s++ - '0') * fraction; + } + } + + if (*s == 'e' || *s == 'E') { + ++s; + + double base = 10; + if (*s == '+') + ++s; + else if (*s == '-') { + ++s; + base = 0.1; + } + + unsigned int exponent = 0; + while (isdigit(*s)) + exponent = (exponent * 10) + (*s++ - '0'); + + double power = 1; + for (; exponent; exponent >>= 1, base *= base) + if (exponent & 1) + power *= base; + + result *= power; + } + + *endptr = s; + return ch == '-' ? -result : result; +} + +static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { + if (!tail) + return node->next = node; + node->next = tail->next; + tail->next = node; + return node; +} + +static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { + if (tail) { + auto head = tail->next; + tail->next = nullptr; + return JsonValue(tag, head); + } + return JsonValue(tag, nullptr); +} + +int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) { + JsonNode *tails[JSON_STACK_SIZE]; + JsonTag tags[JSON_STACK_SIZE]; + char *keys[JSON_STACK_SIZE]; + JsonValue o; + int pos = -1; + bool separator = true; + JsonNode *node; + *endptr = s; + + while (*s) { + while (isspace(*s)) { + ++s; + if (!*s) break; + } + *endptr = s++; + switch (**endptr) { + case '-': + if (!isdigit(*s) && *s != '.') { + *endptr = s; + return JSON_BAD_NUMBER; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + o = JsonValue(string2double(*endptr, &s)); + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_NUMBER; + } + break; + case '"': + o = JsonValue(JSON_STRING, s); + for (char *it = s; *s; ++it, ++s) { + int c = *it = *s; + if (c == '\\') { + c = *++s; + switch (c) { + case '\\': + case '"': + case '/': + *it = c; + break; + case 'b': + *it = '\b'; + break; + case 'f': + *it = '\f'; + break; + case 'n': + *it = '\n'; + break; + case 'r': + *it = '\r'; + break; + case 't': + *it = '\t'; + break; + case 'u': + c = 0; + for (int i = 0; i < 4; ++i) { + if (isxdigit(*++s)) { + c = c * 16 + char2int(*s); + } else { + *endptr = s; + return JSON_BAD_STRING; + } + } + if (c < 0x80) { + *it = c; + } else if (c < 0x800) { + *it++ = 0xC0 | (c >> 6); + *it = 0x80 | (c & 0x3F); + } else { + *it++ = 0xE0 | (c >> 12); + *it++ = 0x80 | ((c >> 6) & 0x3F); + *it = 0x80 | (c & 0x3F); + } + break; + default: + *endptr = s; + return JSON_BAD_STRING; + } + } else if ((unsigned int)c < ' ' || c == '\x7F') { + *endptr = s; + return JSON_BAD_STRING; + } else if (c == '"') { + *it = 0; + ++s; + break; + } + } + if (!isdelim(*s)) { + *endptr = s; + return JSON_BAD_STRING; + } + break; + case 't': + if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_TRUE); + s += 3; + break; + case 'f': + if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_FALSE); + s += 4; + break; + case 'n': + if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) + return JSON_BAD_IDENTIFIER; + o = JsonValue(JSON_NULL); + s += 3; + break; + case ']': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_ARRAY) + return JSON_MISMATCH_BRACKET; + o = listToValue(JSON_ARRAY, tails[pos--]); + break; + case '}': + if (pos == -1) + return JSON_STACK_UNDERFLOW; + if (tags[pos] != JSON_OBJECT) + return JSON_MISMATCH_BRACKET; + if (keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + o = listToValue(JSON_OBJECT, tails[pos--]); + break; + case '[': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_ARRAY; + keys[pos] = nullptr; + separator = true; + continue; + case '{': + if (++pos == JSON_STACK_SIZE) + return JSON_STACK_OVERFLOW; + tails[pos] = nullptr; + tags[pos] = JSON_OBJECT; + keys[pos] = nullptr; + separator = true; + continue; + case ':': + if (separator || keys[pos] == nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case ',': + if (separator || keys[pos] != nullptr) + return JSON_UNEXPECTED_CHARACTER; + separator = true; + continue; + case '\0': + continue; + default: + return JSON_UNEXPECTED_CHARACTER; + } + + separator = false; + + if (pos == -1) { + *endptr = s; + *value = o; + return JSON_OK; + } + + if (tags[pos] == JSON_OBJECT) { + if (!keys[pos]) { + if (o.getTag() != JSON_STRING) + return JSON_UNQUOTED_KEY; + keys[pos] = o.toString(); + continue; + } + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + tails[pos]->key = keys[pos]; + keys[pos] = nullptr; + } else { + if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr) + return JSON_ALLOCATION_FAILURE; + tails[pos] = insertAfter(tails[pos], node); + } + tails[pos]->value = o; + } + return JSON_BREAKING_BAD; +} diff -Nru libindi-1.0.0/drivers/weather/gason.h libindi-1.1.0/drivers/weather/gason.h --- libindi-1.0.0/drivers/weather/gason.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/weather/gason.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,158 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2015 Ivan Vashchaev + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include + +enum JsonTag { + JSON_NUMBER = 0, + JSON_STRING, + JSON_ARRAY, + JSON_OBJECT, + JSON_TRUE, + JSON_FALSE, + JSON_NULL = 0xF +}; + +struct JsonNode; + +#define JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL +#define JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL +#define JSON_VALUE_TAG_MASK 0xF +#define JSON_VALUE_TAG_SHIFT 47 + +union JsonValue { + uint64_t ival; + double fval; + + JsonValue(double x) + : fval(x) { + } + JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { + assert((uint64_t)payload <= JSON_VALUE_PAYLOAD_MASK); + ival = JSON_VALUE_NAN_MASK | ((uint64_t)tag << JSON_VALUE_TAG_SHIFT) | (uintptr_t)payload; + } + bool isDouble() const { + return (int64_t)ival <= (int64_t)JSON_VALUE_NAN_MASK; + } + JsonTag getTag() const { + return isDouble() ? JSON_NUMBER : JsonTag((ival >> JSON_VALUE_TAG_SHIFT) & JSON_VALUE_TAG_MASK); + } + uint64_t getPayload() const { + assert(!isDouble()); + return ival & JSON_VALUE_PAYLOAD_MASK; + } + double toNumber() const { + assert(getTag() == JSON_NUMBER); + return fval; + } + char *toString() const { + assert(getTag() == JSON_STRING); + return (char *)getPayload(); + } + JsonNode *toNode() const { + assert(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); + return (JsonNode *)getPayload(); + } +}; + +struct JsonNode { + JsonValue value; + JsonNode *next; + char *key; +}; + +struct JsonIterator { + JsonNode *p; + + void operator++() { + p = p->next; + } + bool operator!=(const JsonIterator &x) const { + return p != x.p; + } + JsonNode *operator*() const { + return p; + } + JsonNode *operator->() const { + return p; + } +}; + +inline JsonIterator begin(JsonValue o) { + return JsonIterator{o.toNode()}; +} +inline JsonIterator end(JsonValue) { + return JsonIterator{nullptr}; +} + +#define JSON_ERRNO_MAP(XX) \ + XX(OK, "ok") \ + XX(BAD_NUMBER, "bad number") \ + XX(BAD_STRING, "bad string") \ + XX(BAD_IDENTIFIER, "bad identifier") \ + XX(STACK_OVERFLOW, "stack overflow") \ + XX(STACK_UNDERFLOW, "stack underflow") \ + XX(MISMATCH_BRACKET, "mismatch bracket") \ + XX(UNEXPECTED_CHARACTER, "unexpected character") \ + XX(UNQUOTED_KEY, "unquoted key") \ + XX(BREAKING_BAD, "breaking bad") \ + XX(ALLOCATION_FAILURE, "allocation failure") + +enum JsonErrno { +#define XX(no, str) JSON_##no, + JSON_ERRNO_MAP(XX) +#undef XX +}; + +const char *jsonStrError(int err); + +class JsonAllocator { + struct Zone { + Zone *next; + size_t used; + } *head = nullptr; + +public: + JsonAllocator() = default; + JsonAllocator(const JsonAllocator &) = delete; + JsonAllocator &operator=(const JsonAllocator &) = delete; + JsonAllocator(JsonAllocator &&x) : head(x.head) { + x.head = nullptr; + } + JsonAllocator &operator=(JsonAllocator &&x) { + head = x.head; + x.head = nullptr; + return *this; + } + ~JsonAllocator() { + deallocate(); + } + void *allocate(size_t size); + void deallocate(); +}; + +int jsonParse(char *str, char **endptr, JsonValue *value, JsonAllocator &allocator); diff -Nru libindi-1.0.0/drivers/weather/wunderground.cpp libindi-1.1.0/drivers/weather/wunderground.cpp --- libindi-1.0.0/drivers/weather/wunderground.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/weather/wunderground.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,293 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI Weather Underground (TM) Weather Driver + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#include +#include +#include +#include + +#include "gason.h" +#include "wunderground.h" + +// We declare an auto pointer to WunderGround. +std::auto_ptr wunderGround(0); + +static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} + +void ISInit() +{ + static int isInit =0; + + if (isInit == 1) + return; + + isInit = 1; + if(wunderGround.get() == 0) wunderGround.reset(new WunderGround()); + +} + +void ISGetProperties(const char *dev) +{ + ISInit(); + wunderGround->ISGetProperties(dev); +} + +void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) +{ + ISInit(); + wunderGround->ISNewSwitch(dev, name, states, names, num); +} + +void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) +{ + ISInit(); + wunderGround->ISNewText(dev, name, texts, names, num); +} + +void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) +{ + ISInit(); + wunderGround->ISNewNumber(dev, name, values, names, num); +} + +void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +{ + INDI_UNUSED(dev); + INDI_UNUSED(name); + INDI_UNUSED(sizes); + INDI_UNUSED(blobsizes); + INDI_UNUSED(blobs); + INDI_UNUSED(formats); + INDI_UNUSED(names); + INDI_UNUSED(n); +} +void ISSnoopDevice (XMLEle *root) +{ + wunderGround->ISSnoopDevice(root); +} + + +WunderGround::WunderGround() +{ + setVersion(1,0); + + wunderLat=-1000; + wunderLong=-1000; +} + +WunderGround::~WunderGround() +{ + +} + +const char * WunderGround::getDefaultName() +{ + return (char *)"WunderGround"; +} + +bool WunderGround::Connect() +{ + if (wunderAPIKeyT[0].text == NULL) + { + DEBUG(INDI::Logger::DBG_ERROR, "Weather Underground API Key is not available. Please register your API key at www.wunderground.com and save it under Options."); + return false; + } + + return true; +} + +bool WunderGround::Disconnect() +{ + return true; +} + +bool WunderGround::initProperties() +{ + INDI::Weather::initProperties(); + + IUFillText(&wunderAPIKeyT[0], "API_KEY", "API Key", NULL); + IUFillTextVector(&wunderAPIKeyTP, wunderAPIKeyT, 1, getDeviceName(), "WUNDER_API_KEY", "Wunder", OPTIONS_TAB, IP_RW, 60, IPS_IDLE); + + weatherN = addParameter("Weather", 0, 0, 0, 1); + temperatureN = addParameter("Temperature (C)", -10, 30, -20, 40); + windN = addParameter("Wind (kph)", 0, 20, 0, 40); + windGustN = addParameter("Wind Gust (kph)", 0, 20, 0, 50); + precipN = addParameter("Percip (mm)", 0, 0, 0, 0); + + setCriticalParameter("Weather"); + setCriticalParameter("Temperature (C)"); + setCriticalParameter("Wind (kph)"); + setCriticalParameter("Percip (mm)"); + + syncParameters(); + + addDebugControl(); + + return true; + +} + +void WunderGround::ISGetProperties(const char *dev) +{ + INDI::Weather::ISGetProperties(dev); + + defineText(&wunderAPIKeyTP); + + loadConfig(true, "WUNDER_API_KEY"); +} + +bool WunderGround::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) +{ + if(!strcmp(dev,getDeviceName())) + { + if (!strcmp(wunderAPIKeyTP.name, name)) + { + IUUpdateText(&wunderAPIKeyTP, texts, names, n); + wunderAPIKeyTP.s = IPS_OK; + IDSetText(&wunderAPIKeyTP, NULL); + return true; + } + + } + + return INDI::Weather::ISNewText(dev,name,texts,names,n); +} + +bool WunderGround::updateLocation(double latitude, double longitude, double elevation) +{ + INDI_UNUSED(elevation); + + wunderLat = latitude; + wunderLong= (longitude > 180) ? (longitude - 360) : longitude; + + return true; +} + +IPState WunderGround::updateWeather() +{ + CURL *curl; + CURLcode res; + std::string readBuffer; + char requestURL[MAXRBUF]; + + // If location is not updated yet, return busy + if (wunderLat == -1000 || wunderLong == -1000) + return IPS_BUSY; + + snprintf(requestURL, MAXRBUF, "http://api.wunderground.com/api/%s/conditions/q/%g,%g.json", wunderAPIKeyT[0].text, wunderLat, wunderLong); + + curl = curl_easy_init(); + if(curl) + { + curl_easy_setopt(curl, CURLOPT_URL, requestURL); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + + char srcBuffer[readBuffer.size()]; + strncpy(srcBuffer, readBuffer.c_str(), readBuffer.size()); + char *source = srcBuffer; + // do not forget terminate source string with 0 + char *endptr; + JsonValue value; + JsonAllocator allocator; + int status = jsonParse(source, &endptr, &value, allocator); + if (status != JSON_OK) + { + DEBUGF(INDI::Logger::DBG_ERROR, "%s at %zd", jsonStrError(status), endptr - source); + DEBUGF(INDI::Logger::DBG_DEBUG, "%s", requestURL); + DEBUGF(INDI::Logger::DBG_DEBUG, "%s", readBuffer.c_str()); + return IPS_ALERT; + } + + JsonIterator it; + JsonIterator observationIterator; + + for (it = begin(value); it!= end(value); ++it) + { + if (!strcmp(it->key, "current_observation")) + { + for (observationIterator = begin(it->value); observationIterator!= end(it->value); ++observationIterator) + { + if (!strcmp(observationIterator->key, "weather")) + { + char *value = observationIterator->value.toString(); + + if (!strcmp(value, "Clear")) + weatherN->value = 0; + else if (!strcmp(value, "Unknown") || !strcmp(value, "Scattered Clouds") || !strcmp(value, "Partly Cloudy") || !strcmp(value, "Overcast") + || !strcmp(value, "Patches of Fog") || !strcmp(value, "Partial Fog") || !strcmp(value, "Light Haze")) + weatherN->value = 1; + else + weatherN->value = 2; + + DEBUGF(INDI::Logger::DBG_SESSION, "Weather condition: %s", value); + } + else if (!strcmp(observationIterator->key, "temp_c")) + { + temperatureN->value = observationIterator->value.toNumber(); + } + else if (!strcmp(observationIterator->key, "wind_kph")) + { + windN->value = observationIterator->value.toNumber(); + } + else if (!strcmp(observationIterator->key, "wind_gust_kph")) + { + windGustN->value = observationIterator->value.toNumber(); + } + else if (!strcmp(observationIterator->key, "precip_1hr_metric")) + { + char *value = observationIterator->value.toString(); + double mm=-1; + if (!strcmp(value, "--")) + precipN->value = 0; + else + { + mm = atof(value); + if (mm >= 0) + precipN->value = mm; + } + } + } + } + } + + return IPS_OK; +} + +bool WunderGround::saveConfigItems(FILE *fp) +{ + INDI::Weather::saveConfigItems(fp); + + IUSaveConfigText(fp, &wunderAPIKeyTP); + + return true; +} + diff -Nru libindi-1.0.0/drivers/weather/wunderground.h libindi-1.1.0/drivers/weather/wunderground.h --- libindi-1.0.0/drivers/weather/wunderground.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/drivers/weather/wunderground.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,67 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI Weather Underground (TM) Weather Driver + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#ifndef WUNDERGROUND_H +#define WUNDERGROUND_H + +#include "indiweather.h" + +class WunderGround : public INDI::Weather +{ + public: + WunderGround(); + virtual ~WunderGround(); + + // Generic indi device entries + bool Connect(); + bool Disconnect(); + const char *getDefaultName(); + + virtual bool initProperties(); + virtual void ISGetProperties (const char *dev); + virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); + + protected: + + virtual IPState updateWeather(); + + virtual bool saveConfigItems(FILE *fp); + virtual bool updateLocation(double latitude, double longitude, double elevation); + + INumber *weatherN; + INumber *temperatureN; + INumber *windN; + INumber *windGustN; + INumber *precipN; + +private: + + IText wunderAPIKeyT[1]; + ITextVectorProperty wunderAPIKeyTP; + + double wunderLat, wunderLong; + +}; + +#endif // WUNDERGROUND_H diff -Nru libindi-1.0.0/drivers.xml libindi-1.1.0/drivers.xml --- libindi-1.0.0/drivers.xml 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/drivers.xml 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,12 @@ indi_lx200basic - 1.0 + 2.0 + + indi_lx200gps + 2.0 + indi_lx200autostar 2.0 @@ -10,46 +14,42 @@ indi_lx200classic 2.0 - - - indi_lx200gps - 2.0 - + indi_lx200_16 2.0 - indi_lx200autostar + indi_lx200gps 2.0 - indi_lx200autostar + indi_lx200gps 2.0 - indi_lx200autostar + indi_lx200gps 2.0 - indi_lx200autostar + indi_lx200gps 2.0 - indi_lx200ap + indi_lx200ap 1.0 indi_celestron_gps - 2.0 + 3.0 indi_celestron_gps - 2.0 + 3.0 - indi_lx200basic - 1.0 + indi_lx200fs2 + 2.0 indi_synscan @@ -59,10 +59,10 @@ indi_synscan 0.1 - - indi_lx200basic - 1.0 - + + indi_lx200gemini + 1.0 + indi_lx200basic 1.0 @@ -107,13 +107,13 @@ indi_magellan1 1.0 - - indi_ieq45_8406 - 0.1 - - - indi_ieq45_8407 - 0.1 + + indi_ieq_telescope + 1.5 + + + indi_ieq_telescope + 1.5 indi_simulator_telescope @@ -134,7 +134,7 @@ 1.0 - indi_nfocus + indi_nfocus 1.0 @@ -153,6 +153,14 @@ indi_tcfs3_focus 0.1 + + indi_lynx_focus + 0.1 + + + indi_perfectstar_focus + 0.1 + @@ -161,11 +169,11 @@ indi_v4l2_ccd - 0.1 + 1.0 indi_v4l2_ccd - 0.1 + 1.0 @@ -179,10 +187,6 @@ - - indi_meade_lpi - 0.1 - indi_sbig_stv 0.1 @@ -199,6 +203,10 @@ indi_joystick + 0.2 + + + indi_simulator_gps 0.1 @@ -212,6 +220,12 @@ 1.0 + + + indi_wunderground_weather + 1.0 + + indi_imager_agent diff -Nru libindi-1.0.0/examples/tutorial_seven/simple_telescope_simulator.cpp libindi-1.1.0/examples/tutorial_seven/simple_telescope_simulator.cpp --- libindi-1.0.0/examples/tutorial_seven/simple_telescope_simulator.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/examples/tutorial_seven/simple_telescope_simulator.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -272,7 +272,7 @@ addDebugControl(); // Add alignment properties - InitProperties(this); + InitAlignmentProperties(this); return true; } @@ -282,7 +282,7 @@ if(strcmp(dev,getDeviceName())==0) { // Process alignment properties - ProcessBlobProperties(this, name, sizes, blobsizes, blobs, formats, names, n); + 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); @@ -295,7 +295,7 @@ if(strcmp(dev,getDeviceName())==0) { // Process alignment properties - ProcessNumberProperties(this, name, values, names, n); + ProcessAlignmentNumberProperties(this, name, values, names, n); } @@ -309,7 +309,7 @@ if(strcmp(dev,getDeviceName())==0) { // Process alignment properties - ProcessSwitchProperties(this, name, states, names, n); + ProcessAlignmentSwitchProperties(this, name, states, names, n); } // Nobody has claimed this, so, ignore it @@ -321,15 +321,15 @@ if(strcmp(dev,getDeviceName())==0) { // Process alignment properties - ProcessTextProperties(this, name, texts, names, n); + ProcessAlignmentTextProperties(this, name, texts, names, n); } // Pass it up the chain return INDI::Telescope::ISNewText(dev, name, texts, names, n); } -bool ScopeSim::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool ScopeSim::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { - AxisDirection axisDir = (dir == MOTION_NORTH) ? FORWARD : REVERSE; + AxisDirection axisDir = (dir == DIRECTION_NORTH) ? FORWARD : REVERSE; AxisStatus axisStat = (command == MOTION_START) ? SLEWING : STOPPED; AxisSlewRateDEC = DEFAULT_SLEW_RATE; @@ -339,10 +339,10 @@ return true; } -bool ScopeSim::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool ScopeSim::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { - AxisDirection axisDir = (dir == MOTION_WEST) ? FORWARD : REVERSE; + AxisDirection axisDir = (dir == DIRECTION_WEST) ? FORWARD : REVERSE; AxisStatus axisStat = (command == MOTION_START) ? SLEWING : STOPPED; AxisSlewRateRA = DEFAULT_SLEW_RATE; diff -Nru libindi-1.0.0/examples/tutorial_seven/simple_telescope_simulator.h libindi-1.1.0/examples/tutorial_seven/simple_telescope_simulator.h --- libindi-1.0.0/examples/tutorial_seven/simple_telescope_simulator.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/examples/tutorial_seven/simple_telescope_simulator.h 2015-09-06 13:17:35.000000000 +0000 @@ -37,8 +37,8 @@ virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); friend void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); virtual bool ReadScopeStatus(); bool Sync(double ra, double dec); virtual void TimerHit(); @@ -66,12 +66,12 @@ long GotoTargetMicrostepsRA; // Previous motion direction - typedef enum { PREVIOUS_NS_MOTION_NORTH = MOTION_NORTH, - PREVIOUS_NS_MOTION_SOUTH = MOTION_SOUTH, + typedef enum { PREVIOUS_NS_MOTION_NORTH = DIRECTION_NORTH, + PREVIOUS_NS_MOTION_SOUTH = DIRECTION_SOUTH, PREVIOUS_NS_MOTION_UNKNOWN = -1} PreviousNSMotion_t; PreviousNSMotion_t PreviousNSMotion; - typedef enum { PREVIOUS_WE_MOTION_WEST = MOTION_WEST, - PREVIOUS_WE_MOTION_EAST = MOTION_EAST, + typedef enum { PREVIOUS_WE_MOTION_WEST = DIRECTION_WEST, + PREVIOUS_WE_MOTION_EAST = DIRECTION_EAST, PREVIOUS_WE_MOTION_UNKNOWN = -1} PreviousWEMotion_t; PreviousWEMotion_t PreviousWEMotion; diff -Nru libindi-1.0.0/examples/tutorial_six/tutorial_client.h libindi-1.1.0/examples/tutorial_six/tutorial_client.h --- libindi-1.0.0/examples/tutorial_six/tutorial_client.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/examples/tutorial_six/tutorial_client.h 2015-09-06 13:17:35.000000000 +0000 @@ -52,6 +52,7 @@ protected: virtual void newDevice(INDI::BaseDevice *dp); + virtual void removeDevice(INDI::BaseDevice *dp) {} virtual void newProperty(INDI::Property *property); virtual void removeProperty(INDI::Property *property) {} virtual void newBLOB(IBLOB *bp); diff -Nru libindi-1.0.0/examples/tutorial_two/simplescope.cpp libindi-1.1.0/examples/tutorial_two/simplescope.cpp --- libindi-1.0.0/examples/tutorial_two/simplescope.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/examples/tutorial_two/simplescope.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -113,6 +113,8 @@ cap.canPark = false; cap.canSync = false; cap.canAbort = true; + cap.hasLocation = false; + cap.hasTime = true; SetTelescopeCapability(&cap); } @@ -126,6 +128,7 @@ addDebugControl(); + return true; } /************************************************************************************** diff -Nru libindi-1.0.0/indiapi.h libindi-1.1.0/indiapi.h --- libindi-1.0.0/indiapi.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/indiapi.h 2015-09-06 13:17:35.000000000 +0000 @@ -94,7 +94,9 @@ /* INDI Library version */ -#define INDI_LIBV 0.9 +#define INDI_VERSION_MAJOR 1 +#define INDI_VERSION_MINOR 1 +#define INDI_VERSION_RELEASE 0 /******************************************************************************* * Manifest constants diff -Nru libindi-1.0.0/indidriver.c libindi-1.1.0/indidriver.c --- libindi-1.0.0/indidriver.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/indidriver.c 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,8 @@ #if 0 - INDI - Copyright (C) 2003-2006 Elwood C. Downey + INDI Driver Functions - Updated by Jasem Mutlaq (2003-2010) + Copyright (C) 2003-2015 Jasem Mutlaq + Copyright (C) 2003-2006 Elwood C. Downey This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -466,6 +466,7 @@ strncpy(svp->name, escapedName, MAXINDINAME); strncpy(svp->label, escapedLabel, MAXINDILABEL); strncpy(svp->group, group, MAXINDIGROUP); + strcpy(svp->timestamp, ""); svp->p = p; svp->r = r; diff -Nru libindi-1.0.0/indidriver.h libindi-1.1.0/indidriver.h --- libindi-1.0.0/indidriver.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/indidriver.h 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,8 @@ #if 0 - INDI - Copyright (C) 2003-2006 Elwood C. Downey + INDI Driver Functions - Updated by Jasem Mutlaq (2003-2010) + Copyright (C) 2003-2015 Jasem Mutlaq + Copyright (C) 2003-2006 Elwood C. Downey This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -66,7 +66,7 @@ \author Jasem Mutlaq \note Drivers subclassing INDI::DefaultDevice do not need to call the configuration functions directly as it is handled internally by the class. -\version libindi 0.7+ +\version libindi 1.1+ */ diff -Nru libindi-1.0.0/indiserver.c libindi-1.1.0/indiserver.c --- libindi-1.0.0/indiserver.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/indiserver.c 2015-09-06 13:17:35.000000000 +0000 @@ -326,7 +326,7 @@ { fprintf (stderr, "Usage: %s [options] driver [driver ...]\n", me); fprintf (stderr, "Purpose: server for local and remote INDI drivers\n"); - fprintf (stderr, "INDI Library: %s\nCode %s. Protocol %g.\n", CMAKE_INDI_VERSION_STRING, "$Revision: 726523 $", INDIV); + fprintf (stderr, "INDI Library: %s\nCode %s. Protocol %g.\n", CMAKE_INDI_VERSION_STRING, "$Rev: 2039 $", INDIV); fprintf (stderr, "Options:\n"); fprintf (stderr, " -l d : log driver messages to /YYYY-MM-DD.islog\n"); fprintf (stderr, " -m m : kill client if gets more than this many MB behind, default %d\n", DEFMAXQSIZ); diff -Nru libindi-1.0.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.cpp libindi-1.1.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.cpp --- libindi-1.0.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -25,34 +25,34 @@ // Public methods -void AlignmentSubsystemForDrivers::InitProperties(Telescope* pTelescope) +void AlignmentSubsystemForDrivers::InitAlignmentProperties(Telescope* pTelescope) { MapPropertiesToInMemoryDatabase::InitProperties(pTelescope); MathPluginManagement::InitProperties(pTelescope); } -void AlignmentSubsystemForDrivers::ProcessBlobProperties(Telescope* pTelescope, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) +void AlignmentSubsystemForDrivers::ProcessAlignmentBLOBProperties(Telescope* pTelescope, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { MapPropertiesToInMemoryDatabase::ProcessBlobProperties(pTelescope, name, sizes, blobsizes, blobs, formats, names, n); } -void AlignmentSubsystemForDrivers::ProcessNumberProperties(Telescope* pTelescope, const char *name, double values[], char *names[], int n) +void AlignmentSubsystemForDrivers::ProcessAlignmentNumberProperties(Telescope* pTelescope, const char *name, double values[], char *names[], int n) { MapPropertiesToInMemoryDatabase::ProcessNumberProperties(pTelescope, name, values, names, n); } -void AlignmentSubsystemForDrivers::ProcessSwitchProperties(Telescope* pTelescope, const char *name, ISState *states, char *names[], int n) +void AlignmentSubsystemForDrivers::ProcessAlignmentSwitchProperties(Telescope* pTelescope, const char *name, ISState *states, char *names[], int n) { MapPropertiesToInMemoryDatabase::ProcessSwitchProperties(pTelescope, name, states, names, n); MathPluginManagement::ProcessSwitchProperties(pTelescope, name, states, names, n); } -void AlignmentSubsystemForDrivers::ProcessTextProperties(Telescope* pTelescope, const char *name, char *texts[], char *names[], int n) +void AlignmentSubsystemForDrivers::ProcessAlignmentTextProperties(Telescope* pTelescope, const char *name, char *texts[], char *names[], int n) { MathPluginManagement::ProcessTextProperties(pTelescope, name, texts, names, n); } -void AlignmentSubsystemForDrivers::SaveConfigProperties(FILE *fp) +void AlignmentSubsystemForDrivers::SaveAlignmentConfigProperties(FILE *fp) { MathPluginManagement::SaveConfigProperties(fp); } diff -Nru libindi-1.0.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.h libindi-1.1.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.h --- libindi-1.0.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/AlignmentSubsystemForDrivers.h 2015-09-06 13:17:35.000000000 +0000 @@ -36,7 +36,7 @@ /** \brief Initilize alignment subsystem properties. It is recommended to call this function within initProperties() of your primary device * \param[in] pTelescope Pointer to the child INDI::Telecope class */ - void InitProperties(Telescope* pTelescope); + void InitAlignmentProperties(Telescope* pTelescope); /** \brief Call this function from within the ISNewBlob processing path. The function will * handle any alignment subsystem related properties. @@ -49,7 +49,7 @@ * \param[in] names * \param[in] n */ - void ProcessBlobProperties(Telescope* pTelescope, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); + void ProcessAlignmentBLOBProperties(Telescope* pTelescope, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); /** \brief Call this function from within the ISNewNumber processing path. The function will * handle any alignment subsystem related properties. @@ -59,7 +59,7 @@ * \param[in] names names as passed by the client * \param[in] n number of values and names pair to process. */ - void ProcessNumberProperties(Telescope* pTelescope, const char *name, double values[], char *names[], int n); + void ProcessAlignmentNumberProperties(Telescope* pTelescope, const char *name, double values[], char *names[], int n); /** \brief Call this function from within the ISNewSwitch processing path. The function will * handle any alignment subsystem related properties. @@ -69,7 +69,7 @@ * \param[in] names names as passed by the client * \param[in] n number of values and names pair to process. */ - void ProcessSwitchProperties(Telescope* pTelescope, const char *name, ISState *states, char *names[], int n); + void ProcessAlignmentSwitchProperties(Telescope* pTelescope, const char *name, ISState *states, char *names[], int n); /** \brief Call this function from within the ISNewText processing path. The function will * handle any alignment subsystem related properties. This only text property at the moment is contained in the @@ -80,13 +80,13 @@ * \param[in] names names as passed by the client * \param[in] n number of values and names pair to process. */ - void ProcessTextProperties(Telescope* pTelescope, const char *name, char *texts[], char *names[], int n); + void ProcessAlignmentTextProperties(Telescope* pTelescope, const char *name, char *texts[], char *names[], int n); /** \brief Call this function to save persistent alignment related properties. * This function should be called from within the saveConfigItems function of your driver. * \param[in] fp File pointer passed into saveConfigItems */ - void SaveConfigProperties(FILE *fp); + void SaveAlignmentConfigProperties(FILE *fp); private: /** \brief This static function is registered as a load database callback with diff -Nru libindi-1.0.0/libs/indibase/alignment/CMakeLists.txt libindi-1.1.0/libs/indibase/alignment/CMakeLists.txt --- libindi-1.0.0/libs/indibase/alignment/CMakeLists.txt 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/CMakeLists.txt 2015-09-06 13:17:35.000000000 +0000 @@ -49,6 +49,10 @@ endif (GSL_FOUND) set_target_properties(AlignmentDriver PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION} OUTPUT_NAME indiAlignmentDriver) install(TARGETS AlignmentDriver LIBRARY DESTINATION ${LIB_DESTINATION}) +install(FILES AlignmentSubsystemForMathPlugins.h AlignmentSubsystemForDrivers.h BasicMathPlugin.h BuiltInMathPlugin.h + ClientAPIForAlignmentDatabase.h ClientAPIForMathPluginManagement.h Common.h ConvexHull.h DriverCommon.h InMemoryDatabase.h MathPlugin.h + MathPluginManagement.h SVDMathPlugin.h TelescopeDirectionVectorSupportFunctions.h MapPropertiesToInMemoryDatabase.h + DESTINATION ${INCLUDE_INSTALL_DIR}/libindi/alignment COMPONENT Devel) ################################################## ####### INDI AlignmentClient static library ###### diff -Nru libindi-1.0.0/libs/indibase/alignment/Common.h libindi-1.1.0/libs/indibase/alignment/Common.h --- libindi-1.0.0/libs/indibase/alignment/Common.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/Common.h 2015-09-06 13:17:35.000000000 +0000 @@ -165,6 +165,8 @@ PrivateData.reset(new unsigned char[PrivateDataSize]); memcpy(PrivateData.get(), RHS.PrivateData.get(), PrivateDataSize); } + + return *this; } double ObservationJulianDate; diff -Nru libindi-1.0.0/libs/indibase/alignment/MapPropertiesToInMemoryDatabase.h libindi-1.1.0/libs/indibase/alignment/MapPropertiesToInMemoryDatabase.h --- libindi-1.0.0/libs/indibase/alignment/MapPropertiesToInMemoryDatabase.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/MapPropertiesToInMemoryDatabase.h 2015-09-06 13:17:35.000000000 +0000 @@ -9,7 +9,7 @@ #ifndef INDI_ALIGNMENTSUBSYSTEM_MAPPROPERTIESTOINMEMORYDATABASE_H #define INDI_ALIGNMENTSUBSYSTEM_MAPPROPERTIESTOINMEMORYDATABASE_H -#include "indibase/inditelescope.h" +#include "../inditelescope.h" #include "InMemoryDatabase.h" namespace INDI { diff -Nru libindi-1.0.0/libs/indibase/alignment/MathPluginManagement.h libindi-1.1.0/libs/indibase/alignment/MathPluginManagement.h --- libindi-1.0.0/libs/indibase/alignment/MathPluginManagement.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/alignment/MathPluginManagement.h 2015-09-06 13:17:35.000000000 +0000 @@ -9,7 +9,7 @@ #ifndef INDI_ALIGNMENTSUBSYSTEM_MATHPLUGINMANAGEMENT_H #define INDI_ALIGNMENTSUBSYSTEM_MATHPLUGINMANAGEMENT_H -#include "indibase/inditelescope.h" +#include "../inditelescope.h" #include "BuiltInMathPlugin.h" diff -Nru libindi-1.0.0/libs/indibase/baseclient.cpp libindi-1.1.0/libs/indibase/baseclient.cpp --- libindi-1.0.0/libs/indibase/baseclient.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/baseclient.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -408,10 +408,10 @@ } // delete the whole device else - return removeDevice(dp->getDeviceName(), errmsg); + return deleteDevice(dp->getDeviceName(), errmsg); } -int INDI::BaseClient::removeDevice( const char * devName, char * errmsg ) +int INDI::BaseClient::deleteDevice( const char * devName, char * errmsg ) { std::vector::iterator devicei; @@ -420,6 +420,7 @@ if (!strcmp(devName, (*devicei)->getDeviceName())) { + removeDevice(*devicei); delete *devicei; devicei = cDevices.erase(devicei); return 0; diff -Nru libindi-1.0.0/libs/indibase/baseclient.h libindi-1.1.0/libs/indibase/baseclient.h --- libindi-1.0.0/libs/indibase/baseclient.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/baseclient.h 2015-09-06 13:17:35.000000000 +0000 @@ -160,7 +160,7 @@ int dispatchCommand(XMLEle *root, char* errmsg); /** \brief Remove device */ - int removeDevice( const char * devName, char * errmsg ); + int deleteDevice( const char * devName, char * errmsg ); /** \brief Delete property command */ int delPropertyCmd (XMLEle *root, char * errmsg); diff -Nru libindi-1.0.0/libs/indibase/basedevice.cpp libindi-1.1.0/libs/indibase/basedevice.cpp --- libindi-1.0.0/libs/indibase/basedevice.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/basedevice.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -106,7 +106,7 @@ IPState INDI::BaseDevice::getPropertyState(const char *name) { IPState state = IPS_IDLE; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; INumberVectorProperty *nvp; @@ -172,7 +172,7 @@ { IPerm perm = IP_RO; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; INumberVectorProperty *nvp; @@ -227,9 +227,9 @@ } -void * INDI::BaseDevice::getRawProperty(const char *name, INDI_TYPE type) +void * INDI::BaseDevice::getRawProperty(const char *name, INDI_PROPERTY_TYPE type) { - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; bool pRegistered = false; @@ -300,9 +300,9 @@ return NULL; } -INDI::Property * INDI::BaseDevice::getProperty(const char *name, INDI_TYPE type) +INDI::Property * INDI::BaseDevice::getProperty(const char *name, INDI_PROPERTY_TYPE type) { - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; bool pRegistered = false; @@ -377,7 +377,7 @@ { std::vector::iterator orderi; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; INumberVectorProperty *nvp; @@ -1245,7 +1245,7 @@ return messageLog.back(); } -void INDI::BaseDevice::registerProperty(void *p, INDI_TYPE type) +void INDI::BaseDevice::registerProperty(void *p, INDI_PROPERTY_TYPE type) { INDI::Property *pContainer; diff -Nru libindi-1.0.0/libs/indibase/basedevice.h libindi-1.1.0/libs/indibase/basedevice.h --- libindi-1.0.0/libs/indibase/basedevice.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/basedevice.h 2015-09-06 13:17:35.000000000 +0000 @@ -72,7 +72,7 @@ /** \return Return property permission */ IPerm getPropertyPermission(const char *name); - void registerProperty(void *p, INDI_TYPE type); + void registerProperty(void *p, INDI_PROPERTY_TYPE type); /** \brief Remove a property \param name name of property to be removed @@ -91,7 +91,7 @@ is the property type (Number, Text, Switch..etc). */ - void * getRawProperty(const char *name, INDI_TYPE type = INDI_UNKNOWN); + void * getRawProperty(const char *name, INDI_PROPERTY_TYPE type = INDI_UNKNOWN); /** \brief Return a property and its type given its name. \param name of property to be found. @@ -99,7 +99,7 @@ \return If property is found, it is returned. To be used you must use static_cast with given the type of property returned. */ - INDI::Property * getProperty(const char *name, INDI_TYPE type = INDI_UNKNOWN); + INDI::Property * getProperty(const char *name, INDI_PROPERTY_TYPE type = INDI_UNKNOWN); /** \brief Return a list of all properties in the device. */ diff -Nru libindi-1.0.0/libs/indibase/defaultdevice.cpp libindi-1.1.0/libs/indibase/defaultdevice.cpp --- libindi-1.0.0/libs/indibase/defaultdevice.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/defaultdevice.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -93,7 +93,7 @@ { std::vector::iterator orderi; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; ISwitchVectorProperty *svp=NULL; @@ -453,7 +453,7 @@ void INDI::DefaultDevice::ISGetProperties (const char *dev) { std::vector::iterator orderi; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; if(isInit == 0) @@ -506,7 +506,7 @@ void INDI::DefaultDevice::resetProperties() { std::vector::iterator orderi; - INDI_TYPE pType; + INDI_PROPERTY_TYPE pType; void *pPtr; for (orderi = pAll.begin(); orderi != pAll.end(); orderi++) diff -Nru libindi-1.0.0/libs/indibase/hidapi.h libindi-1.1.0/libs/indibase/hidapi.h --- libindi-1.0.0/libs/indibase/hidapi.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/hidapi.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,390 @@ +/* + HIDAPI - Multi-Platform library for communication with HID devices. + + Copyright (c) 2009 by Alan Ott, Signal 11 Software (8/22/2009) + All Rights Reserved. + + Changes for use with SX Filter Wheel INDI Driver by CloudMakers - 11/6/2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + These files may also be found in the public source code repository located: + http://github.com/signal11/hidapi +*/ + +/** @file + * @defgroup API hidapi API + */ + +#ifndef HIDAPI_H__ +#define HIDAPI_H__ + +#include + +#ifdef _WIN32 + #define HID_API_EXPORT __declspec(dllexport) + #define HID_API_CALL +#else + #define HID_API_EXPORT /**< API export macro */ + #define HID_API_CALL /**< API call macro */ +#endif + +#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct hid_device_; + typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ + + /** hidapi info structure */ + struct hid_device_info { + /** Platform-specific device path */ + char *path; + /** Device Vendor ID */ + unsigned short vendor_id; + /** Device Product ID */ + unsigned short product_id; + /** Serial Number */ + wchar_t *serial_number; + /** Device Release Number in binary-coded decimal, + also known as Device Version Number */ + unsigned short release_number; + /** Manufacturer String */ + wchar_t *manufacturer_string; + /** Product string */ + wchar_t *product_string; + /** Usage Page for this Device/Interface + (Windows/Mac only). */ + unsigned short usage_page; + /** Usage for this Device/Interface + (Windows/Mac only).*/ + unsigned short usage; + /** The USB interface which this logical device + represents. Valid on both Linux implementations + in all cases, and valid on the Windows implementation + only if the device contains more than one interface. */ + int interface_number; + + /** Pointer to the next device */ + struct hid_device_info *next; + }; + + + /** @brief Initialize the HIDAPI library. + + This function initializes the HIDAPI library. Calling it is not + strictly necessary, as it will be called automatically by + hid_enumerate() and any of the hid_open_*() functions if it is + needed. This function should be called at the beginning of + execution however, if there is a chance of HIDAPI handles + being opened by different threads simultaneously. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_init(void); + + /** @brief Finalize the HIDAPI library. + + This function frees all of the static data associated with + HIDAPI. It should be called at the end of execution to avoid + memory leaks. + + @ingroup API + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_exit(void); + + /** @brief Enumerate the HID Devices. + + This function returns a linked list of all the HID devices + attached to the system which match vendor_id and product_id. + If @p vendor_id and @p product_id are both set to 0, then + all HID devices will be returned. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the types of device + to open. + @param product_id The Product ID (PID) of the types of + device to open. + + @returns + This function returns a pointer to a linked list of type + struct #hid_device, containing information about the HID devices + attached to the system, or NULL in the case of failure. Free + this linked list by calling hid_free_enumeration(). + */ + struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); + + /** @brief Free an enumeration Linked List + + This function frees a linked list created by hid_enumerate(). + + @ingroup API + @param devs Pointer to a list of struct_device returned from + hid_enumerate(). + */ + void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); + + /** @brief Open a HID device using a Vendor ID (VID), Product ID + (PID) and optionally a serial number. + + If @p serial_number is NULL, the first device with the + specified VID and PID is opened. + + @ingroup API + @param vendor_id The Vendor ID (VID) of the device to open. + @param product_id The Product ID (PID) of the device to open. + @param serial_number The Serial Number of the device to open + (Optionally NULL). + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); + + /** @brief Open a HID device by its path name. + + The path name be determined by calling hid_enumerate(), or a + platform-specific path name can be used (eg: /dev/hidraw0 on + Linux). + + @ingroup API + @param path The path name of the device to open + + @returns + This function returns a pointer to a #hid_device object on + success or NULL on failure. + */ + HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); + + /** @brief Write an Output report to a HID device. + + The first byte of @p data[] must contain the Report ID. For + devices which only support a single report, this must be set + to 0x0. The remaining bytes contain the report data. Since + the Report ID is mandatory, calls to hid_write() will always + contain one more byte than the report contains. For example, + if a hid report is 16 bytes long, 17 bytes must be passed to + hid_write(), the Report ID (or 0x0, for devices with a + single report), followed by the report data (16 bytes). In + this example, the length passed in would be 17. + + hid_write() will send the data on the first OUT endpoint, if + one exists. If it does not, it will send the data through + the Control Endpoint (Endpoint 0). + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Read an Input report from a HID device with timeout. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + @param milliseconds timeout in milliseconds or -1 for blocking wait. + + @returns + This function returns the actual number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); + + /** @brief Read an Input report from a HID device. + + Input reports are returned + to the host through the INTERRUPT IN endpoint. The first byte will + contain the Report number if the device uses numbered reports. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into. + @param length The number of bytes to read. For devices with + multiple reports, make sure to read an extra byte for + the report number. + + @returns + This function returns the actual number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); + + /** @brief Set the device handle to be non-blocking. + + In non-blocking mode calls to hid_read() will return + immediately with a value of 0 if there is no data to be + read. In blocking mode, hid_read() will wait (block) until + there is data to read before returning. + + Nonblocking can be turned on and off at any time. + + @ingroup API + @param device A device handle returned from hid_open(). + @param nonblock enable or not the nonblocking reads + - 1 to enable nonblocking + - 0 to disable nonblocking. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); + + /** @brief Send a Feature report to the device. + + Feature reports are sent over the Control endpoint as a + Set_Report transfer. The first byte of @p data[] must + contain the Report ID. For devices which only support a + single report, this must be set to 0x0. The remaining bytes + contain the report data. Since the Report ID is mandatory, + calls to hid_send_feature_report() will always contain one + more byte than the report contains. For example, if a hid + report is 16 bytes long, 17 bytes must be passed to + hid_send_feature_report(): the Report ID (or 0x0, for + devices which do not use numbered reports), followed by the + report data (16 bytes). In this example, the length passed + in would be 17. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data The data to send, including the report number as + the first byte. + @param length The length in bytes of the data to send, including + the report number. + + @returns + This function returns the actual number of bytes written and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); + + /** @brief Get a feature report from a HID device. + + Make sure to set the first byte of @p data[] to the Report + ID of the report to be read. Make sure to allow space for + this extra byte in @p data[]. + + @ingroup API + @param device A device handle returned from hid_open(). + @param data A buffer to put the read data into, including + the Report ID. Set the first byte of @p data[] to the + Report ID of the report to be read. + @param length The number of bytes to read, including an + extra byte for the report ID. The buffer can be longer + than the actual report. + + @returns + This function returns the number of bytes read and + -1 on error. + */ + int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); + + /** @brief Close a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + */ + void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); + + /** @brief Get The Manufacturer String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Product String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get The Serial Number String from a HID device. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); + + /** @brief Get a string from a HID device, based on its string index. + + @ingroup API + @param device A device handle returned from hid_open(). + @param string_index The index of the string to get. + @param string A wide string buffer to put the data into. + @param maxlen The length of the buffer in multiples of wchar_t. + + @returns + This function returns 0 on success and -1 on error. + */ + int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); + + /** @brief Get a string describing the last error which occurred. + + @ingroup API + @param device A device handle returned from hid_open(). + + @returns + This function returns a string containing the last error + which occurred or NULL if none has occurred. + */ + HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff -Nru libindi-1.0.0/libs/indibase/hid_libusb.c libindi-1.1.0/libs/indibase/hid_libusb.c --- libindi-1.0.0/libs/indibase/hid_libusb.c 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/hid_libusb.c 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,1432 @@ +/* + HIDAPI - Multi-Platform library for communication with HID devices. + + Copyright (c) 2009 by Alan Ott, Signal 11 Software (8/22/2009) + All Rights Reserved. + + Linux Version - 6/2/2010 + Libusb Version - 8/13/2010 + FreeBSD Version - 11/1/2011 + + Changes for use with SX Filter Wheel INDI Driver by CloudMakers - 11/6/2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + These files may also be found in the public source code repository located: + http://github.com/signal11/hidapi +*/ + +#define _GNU_SOURCE // needed for wcsdup() before glibc 2.10 + +/* C */ +#include +#include +#include +#include +#include +#include + +/* Unix */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* GNU / LibUSB */ +#include "libusb-1.0/libusb.h" +#include "iconv.h" + +#include "hidapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef DEBUG_PRINTF +#define LOG(...) fprintf(stderr, __VA_ARGS__) +#else +#define LOG(...) do {} while (0) +#endif + +#ifndef __FreeBSD__ +#define DETACH_KERNEL_DRIVER +#endif + +/* Uncomment to enable the retrieval of Usage and Usage Page in +hid_enumerate(). Warning, on platforms different from FreeBSD +this is very invasive as it requires the detach +and re-attach of the kernel driver. See comments inside hid_enumerate(). +libusb HIDAPI programs are encouraged to use the interface number +instead to differentiate between interfaces on a composite HID device. */ +/*#define INVASIVE_GET_USAGE*/ + +/* Linked List of input reports received from the device. */ +struct input_report { + uint8_t *data; + size_t len; + struct input_report *next; +}; + + +struct hid_device_ { + /* Handle to the actual device. */ + libusb_device_handle *device_handle; + + /* Endpoint information */ + int input_endpoint; + int output_endpoint; + int input_ep_max_packet_size; + + /* The interface number of the HID */ + int interface; + + /* Indexes of Strings */ + int manufacturer_index; + int product_index; + int serial_index; + + /* Whether blocking reads are used */ + int blocking; /* boolean */ + + /* Read thread objects */ + pthread_t thread; + pthread_mutex_t mutex; /* Protects input_reports */ + pthread_cond_t condition; + pthread_barrier_t barrier; /* Ensures correct startup sequence */ + int shutdown_thread; + struct libusb_transfer *transfer; + + /* List of received input reports. */ + struct input_report *input_reports; +}; + +static libusb_context *usb_context = NULL; + +uint16_t get_usb_code_for_current_locale(void); +static int return_data(hid_device *dev, unsigned char *data, size_t length); + +static hid_device *new_hid_device(void) +{ + hid_device *dev = calloc(1, sizeof(hid_device)); + dev->blocking = 1; + + pthread_mutex_init(&dev->mutex, NULL); + pthread_cond_init(&dev->condition, NULL); + pthread_barrier_init(&dev->barrier, NULL, 2); + + return dev; +} + +static void free_hid_device(hid_device *dev) +{ + /* Clean up the thread objects */ + pthread_barrier_destroy(&dev->barrier); + pthread_cond_destroy(&dev->condition); + pthread_mutex_destroy(&dev->mutex); + + /* Free the device itself */ + free(dev); +} + +#if 0 +//TODO: Implement this funciton on hidapi/libusb.. +static void register_error(hid_device *device, const char *op) +{ + +} +#endif + +#ifdef INVASIVE_GET_USAGE +/* Get bytes from a HID Report Descriptor. + Only call with a num_bytes of 0, 1, 2, or 4. */ +static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur) +{ + /* Return if there aren't enough bytes. */ + if (cur + num_bytes >= len) + return 0; + + if (num_bytes == 0) + return 0; + else if (num_bytes == 1) { + return rpt[cur+1]; + } + else if (num_bytes == 2) { + return (rpt[cur+2] * 256 + rpt[cur+1]); + } + else if (num_bytes == 4) { + return (rpt[cur+4] * 0x01000000 + + rpt[cur+3] * 0x00010000 + + rpt[cur+2] * 0x00000100 + + rpt[cur+1] * 0x00000001); + } + else + return 0; +} + +/* Retrieves the device's Usage Page and Usage from the report + descriptor. The algorithm is simple, as it just returns the first + Usage and Usage Page that it finds in the descriptor. + The return value is 0 on success and -1 on failure. */ +static int get_usage(uint8_t *report_descriptor, size_t size, + unsigned short *usage_page, unsigned short *usage) +{ + int i = 0; + int size_code; + int data_len, key_size; + int usage_found = 0, usage_page_found = 0; + + while (i < size) { + int key = report_descriptor[i]; + int key_cmd = key & 0xfc; + + //printf("key: %02hhx\n", key); + + if ((key & 0xf0) == 0xf0) { + /* This is a Long Item. The next byte contains the + length of the data section (value) for this key. + See the HID specification, version 1.11, section + 6.2.2.3, titled "Long Items." */ + if (i+1 < size) + data_len = report_descriptor[i+1]; + else + data_len = 0; /* malformed report */ + key_size = 3; + } + else { + /* This is a Short Item. The bottom two bits of the + key contain the size code for the data section + (value) for this key. Refer to the HID + specification, version 1.11, section 6.2.2.2, + titled "Short Items." */ + size_code = key & 0x3; + switch (size_code) { + case 0: + case 1: + case 2: + data_len = size_code; + break; + case 3: + data_len = 4; + break; + default: + /* Can't ever happen since size_code is & 0x3 */ + data_len = 0; + break; + }; + key_size = 1; + } + + if (key_cmd == 0x4) { + *usage_page = get_bytes(report_descriptor, size, data_len, i); + usage_page_found = 1; + //printf("Usage Page: %x\n", (uint32_t)*usage_page); + } + if (key_cmd == 0x8) { + *usage = get_bytes(report_descriptor, size, data_len, i); + usage_found = 1; + //printf("Usage: %x\n", (uint32_t)*usage); + } + + if (usage_page_found && usage_found) + return 0; /* success */ + + /* Skip over this key and it's associated data */ + i += data_len + key_size; + } + + return -1; /* failure */ +} +#endif // INVASIVE_GET_USAGE + +#ifdef __FreeBSD__ +/* The FreeBSD version of libusb doesn't have this funciton. In mainline + libusb, it's inlined in libusb.h. This function will bear a striking + resemblence to that one, because there's about one way to code it. + + Note that the data parameter is Unicode in UTF-16LE encoding. + Return value is the number of bytes in data, or LIBUSB_ERROR_*. + */ +static inline int libusb_get_string_descriptor(libusb_device_handle *dev, + uint8_t descriptor_index, uint16_t lang_id, + unsigned char *data, int length) +{ + return libusb_control_transfer(dev, + LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */ + LIBUSB_REQUEST_GET_DESCRIPTOR, + (LIBUSB_DT_STRING << 8) | descriptor_index, + lang_id, data, (uint16_t) length, 1000); +} + +#endif + + +/* Get the first language the device says it reports. This comes from + USB string #0. */ +static uint16_t get_first_language(libusb_device_handle *dev) +{ + uint16_t buf[32]; + int len; + + /* Get the string from libusb. */ + len = libusb_get_string_descriptor(dev, + 0x0, /* String ID */ + 0x0, /* Language */ + (unsigned char*)buf, + sizeof(buf)); + if (len < 4) + return 0x0; + + return buf[1]; // First two bytes are len and descriptor type. +} + +static int is_language_supported(libusb_device_handle *dev, uint16_t lang) +{ + uint16_t buf[32]; + int len; + int i; + + /* Get the string from libusb. */ + len = libusb_get_string_descriptor(dev, + 0x0, /* String ID */ + 0x0, /* Language */ + (unsigned char*)buf, + sizeof(buf)); + if (len < 4) + return 0x0; + + + len /= 2; /* language IDs are two-bytes each. */ + /* Start at index 1 because there are two bytes of protocol data. */ + for (i = 1; i < len; i++) { + if (buf[i] == lang) + return 1; + } + + return 0; +} + + +/* This function returns a newly allocated wide string containing the USB + device string numbered by the index. The returned string must be freed + by using free(). */ +static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) +{ + char buf[512]; + int len; + wchar_t *str = NULL; + wchar_t wbuf[256]; + + /* iconv variables */ + iconv_t ic; + size_t inbytes; + size_t outbytes; + size_t res; +#ifdef __FreeBSD__ + const char *inptr; +#else + char *inptr; +#endif + char *outptr; + + /* Determine which language to use. */ + uint16_t lang; + lang = get_usb_code_for_current_locale(); + if (!is_language_supported(dev, lang)) + lang = get_first_language(dev); + + /* Get the string from libusb. */ + len = libusb_get_string_descriptor(dev, + idx, + lang, + (unsigned char*)buf, + sizeof(buf)); + if (len < 0) + return NULL; + + /* buf does not need to be explicitly NULL-terminated because + it is only passed into iconv() which does not need it. */ + + /* Initialize iconv. */ + ic = iconv_open("WCHAR_T", "UTF-16LE"); + if (ic == (iconv_t)-1) { + LOG("iconv_open() failed\n"); + return NULL; + } + + /* Convert to native wchar_t (UTF-32 on glibc/BSD systems). + Skip the first character (2-bytes). */ + inptr = buf+2; + inbytes = len-2; + outptr = (char*) wbuf; + outbytes = sizeof(wbuf); + res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes); + if (res == (size_t)-1) { + LOG("iconv() failed\n"); + goto err; + } + + /* Write the terminating NULL. */ + wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000; + if (outbytes >= sizeof(wbuf[0])) + *((wchar_t*)outptr) = 0x00000000; + + /* Allocate and copy the string. */ + str = wcsdup(wbuf); + +err: + iconv_close(ic); + + return str; +} + +static char *make_path(libusb_device *dev, int interface_number) +{ + char str[64]; + snprintf(str, sizeof(str), "%04x:%04x:%02x", + libusb_get_bus_number(dev), + libusb_get_device_address(dev), + interface_number); + str[sizeof(str)-1] = '\0'; + + return strdup(str); +} + + +int HID_API_EXPORT hid_init(void) +{ + if (!usb_context) { + const char *locale; + + /* Init Libusb */ + if (libusb_init(&usb_context)) + return -1; + + /* Set the locale if it's not set. */ + locale = setlocale(LC_CTYPE, NULL); + if (!locale) + setlocale(LC_CTYPE, ""); + } + + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ + if (usb_context) { + libusb_exit(usb_context); + usb_context = NULL; + } + + return 0; +} + +struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + libusb_device **devs; + libusb_device *dev; + libusb_device_handle *handle; + ssize_t num_devs; + int i = 0; + + struct hid_device_info *root = NULL; // return object + struct hid_device_info *cur_dev = NULL; + + hid_init(); + + num_devs = libusb_get_device_list(usb_context, &devs); + if (num_devs < 0) + return NULL; + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + struct libusb_config_descriptor *conf_desc = NULL; + int j, k; + int interface_num = 0; + + int res = libusb_get_device_descriptor(dev, &desc); + unsigned short dev_vid = desc.idVendor; + unsigned short dev_pid = desc.idProduct; + + /* HID's are defined at the interface level. */ + if (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) + continue; + + res = libusb_get_active_config_descriptor(dev, &conf_desc); + if (res < 0) + libusb_get_config_descriptor(dev, 0, &conf_desc); + if (conf_desc) { + for (j = 0; j < conf_desc->bNumInterfaces; j++) { + const struct libusb_interface *intf = &conf_desc->interface[j]; + for (k = 0; k < intf->num_altsetting; k++) { + const struct libusb_interface_descriptor *intf_desc; + intf_desc = &intf->altsetting[k]; + if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { + interface_num = intf_desc->bInterfaceNumber; + + /* Check the VID/PID against the arguments */ + if ((vendor_id == 0x0 && product_id == 0x0) || + (vendor_id == dev_vid && product_id == dev_pid)) { + struct hid_device_info *tmp; + + /* VID/PID match. Create the record. */ + tmp = calloc(1, sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + /* Fill out the record */ + cur_dev->next = NULL; + cur_dev->path = make_path(dev, interface_num); + + res = libusb_open(dev, &handle); + + if (res >= 0) { + /* Serial Number */ + if (desc.iSerialNumber > 0) + cur_dev->serial_number = + get_usb_string(handle, desc.iSerialNumber); + + /* Manufacturer and Product strings */ + if (desc.iManufacturer > 0) + cur_dev->manufacturer_string = + get_usb_string(handle, desc.iManufacturer); + if (desc.iProduct > 0) + cur_dev->product_string = + get_usb_string(handle, desc.iProduct); + +#ifdef INVASIVE_GET_USAGE + /* + This section is removed because it is too + invasive on the system. Getting a Usage Page + and Usage requires parsing the HID Report + descriptor. Getting a HID Report descriptor + involves claiming the interface. Claiming the + interface involves detaching the kernel driver. + Detaching the kernel driver is hard on the system + because it will unclaim interfaces (if another + app has them claimed) and the re-attachment of + the driver will sometimes change /dev entry names. + It is for these reasons that this section is + #if 0. For composite devices, use the interface + field in the hid_device_info struct to distinguish + between interfaces. */ + unsigned char data[256]; +#ifdef DETACH_KERNEL_DRIVER + int detached = 0; + /* Usage Page and Usage */ + res = libusb_kernel_driver_active(handle, interface_num); + if (res == 1) { + res = libusb_detach_kernel_driver(handle, interface_num); + if (res < 0) + LOG("Couldn't detach kernel driver, even though a kernel driver was attached."); + else + detached = 1; + } +#endif + res = libusb_claim_interface(handle, interface_num); + if (res >= 0) { + /* Get the HID Report Descriptor. */ + res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000); + if (res >= 0) { + unsigned short page=0, usage=0; + /* Parse the usage and usage page + out of the report descriptor. */ + get_usage(data, res, &page, &usage); + cur_dev->usage_page = page; + cur_dev->usage = usage; + } + else + LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res); + + /* Release the interface */ + res = libusb_release_interface(handle, interface_num); + if (res < 0) + LOG("Can't release the interface.\n"); + } + else + LOG("Can't claim interface %d\n", res); +#ifdef DETACH_KERNEL_DRIVER + /* Re-attach kernel driver if necessary. */ + if (detached) { + res = libusb_attach_kernel_driver(handle, interface_num); + if (res < 0) + LOG("Couldn't re-attach kernel driver.\n"); + } +#endif + +#endif // INVASIVE_GET_USAGE + + libusb_close(handle); + } + /* VID/PID */ + cur_dev->vendor_id = dev_vid; + cur_dev->product_id = dev_pid; + + /* Release Number */ + cur_dev->release_number = desc.bcdDevice; + + /* Interface Number */ + cur_dev->interface_number = interface_num; + } + } + } /* altsettings */ + } /* interfaces */ + libusb_free_config_descriptor(conf_desc); + } + } + + libusb_free_device_list(devs, 1); + + return root; +} + +void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +{ + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + +hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +static void read_callback(struct libusb_transfer *transfer) +{ + hid_device *dev = transfer->user_data; + int res; + + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { + + struct input_report *rpt = malloc(sizeof(*rpt)); + rpt->data = malloc(transfer->actual_length); + memcpy(rpt->data, transfer->buffer, transfer->actual_length); + rpt->len = transfer->actual_length; + rpt->next = NULL; + + pthread_mutex_lock(&dev->mutex); + + /* Attach the new report object to the end of the list. */ + if (dev->input_reports == NULL) { + /* The list is empty. Put it at the root. */ + dev->input_reports = rpt; + pthread_cond_signal(&dev->condition); + } + else { + /* Find the end of the list and attach. */ + struct input_report *cur = dev->input_reports; + int num_queued = 0; + while (cur->next != NULL) { + cur = cur->next; + num_queued++; + } + cur->next = rpt; + + /* Pop one off if we've reached 30 in the queue. This + way we don't grow forever if the user never reads + anything from the device. */ + if (num_queued > 30) { + return_data(dev, NULL, 0); + } + } + pthread_mutex_unlock(&dev->mutex); + } + else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + dev->shutdown_thread = 1; + return; + } + else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { + dev->shutdown_thread = 1; + return; + } + else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { + //LOG("Timeout (normal)\n"); + } + else { + LOG("Unknown transfer code: %d\n", transfer->status); + } + + /* Re-submit the transfer object. */ + res = libusb_submit_transfer(transfer); + if (res != 0) { + LOG("Unable to submit URB. libusb error code: %d\n", res); + dev->shutdown_thread = 1; + } +} + + +static void *read_thread(void *param) +{ + hid_device *dev = param; + unsigned char *buf; + const size_t length = dev->input_ep_max_packet_size; + + /* Set up the transfer object. */ + buf = malloc(length); + dev->transfer = libusb_alloc_transfer(0); + libusb_fill_interrupt_transfer(dev->transfer, + dev->device_handle, + dev->input_endpoint, + buf, + length, + read_callback, + dev, + 5000/*timeout*/); + + /* Make the first submission. Further submissions are made + from inside read_callback() */ + libusb_submit_transfer(dev->transfer); + + // Notify the main thread that the read thread is up and running. + pthread_barrier_wait(&dev->barrier); + + /* Handle all the events. */ + while (!dev->shutdown_thread) { + int res; + res = libusb_handle_events(usb_context); + if (res < 0) { + /* There was an error. */ + LOG("read_thread(): libusb reports error # %d\n", res); + + /* Break out of this loop only on fatal error.*/ + if (res != LIBUSB_ERROR_BUSY && + res != LIBUSB_ERROR_TIMEOUT && + res != LIBUSB_ERROR_OVERFLOW && + res != LIBUSB_ERROR_INTERRUPTED) { + break; + } + } + } + + /* Cancel any transfer that may be pending. This call will fail + if no transfers are pending, but that's OK. */ + if (libusb_cancel_transfer(dev->transfer) == 0) { + /* The transfer was cancelled, so wait for its completion. */ + libusb_handle_events(usb_context); + } + + /* Now that the read thread is stopping, Wake any threads which are + waiting on data (in hid_read_timeout()). Do this under a mutex to + make sure that a thread which is about to go to sleep waiting on + the condition acutally will go to sleep before the condition is + signaled. */ + pthread_mutex_lock(&dev->mutex); + pthread_cond_broadcast(&dev->condition); + pthread_mutex_unlock(&dev->mutex); + + /* The dev->transfer->buffer and dev->transfer objects are cleaned up + in hid_close(). They are not cleaned up here because this thread + could end either due to a disconnect or due to a user + call to hid_close(). In both cases the objects can be safely + cleaned up after the call to pthread_join() (in hid_close()), but + since hid_close() calls libusb_cancel_transfer(), on these objects, + they can not be cleaned up here. */ + + return NULL; +} + + +hid_device * HID_API_EXPORT hid_open_path(const char *path) +{ + hid_device *dev = NULL; + + dev = new_hid_device(); + + libusb_device **devs; + libusb_device *usb_dev; + ssize_t num_devs; + int res; + int d = 0; + int good_open = 0; + + hid_init(); + + num_devs = libusb_get_device_list(usb_context, &devs); + while ((usb_dev = devs[d++]) != NULL) { + struct libusb_device_descriptor desc; + struct libusb_config_descriptor *conf_desc = NULL; + int i,j,k; + libusb_get_device_descriptor(usb_dev, &desc); + + if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0) + continue; + for (j = 0; j < conf_desc->bNumInterfaces; j++) { + const struct libusb_interface *intf = &conf_desc->interface[j]; + for (k = 0; k < intf->num_altsetting; k++) { + const struct libusb_interface_descriptor *intf_desc; + intf_desc = &intf->altsetting[k]; + if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { + char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber); + if (!strcmp(dev_path, path)) { + /* Matched Paths. Open this device */ + + // OPEN HERE // + res = libusb_open(usb_dev, &dev->device_handle); + if (res < 0) { + LOG("can't open device\n"); + free(dev_path); + break; + } + good_open = 1; +#ifdef DETACH_KERNEL_DRIVER + /* Detach the kernel driver, but only if the + device is managed by the kernel */ + if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) { + res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber); + if (res < 0) { + libusb_close(dev->device_handle); + LOG("Unable to detach Kernel Driver\n"); + free(dev_path); + good_open = 0; + break; + } + } +#endif + res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber); + if (res < 0) { + LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res); + free(dev_path); + libusb_close(dev->device_handle); + good_open = 0; + break; + } + + /* Store off the string descriptor indexes */ + dev->manufacturer_index = desc.iManufacturer; + dev->product_index = desc.iProduct; + dev->serial_index = desc.iSerialNumber; + + /* Store off the interface number */ + dev->interface = intf_desc->bInterfaceNumber; + + /* Find the INPUT and OUTPUT endpoints. An + OUTPUT endpoint is not required. */ + for (i = 0; i < intf_desc->bNumEndpoints; i++) { + const struct libusb_endpoint_descriptor *ep + = &intf_desc->endpoint[i]; + + /* Determine the type and direction of this + endpoint. */ + int is_interrupt = + (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) + == LIBUSB_TRANSFER_TYPE_INTERRUPT; + int is_output = + (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) + == LIBUSB_ENDPOINT_OUT; + int is_input = + (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) + == LIBUSB_ENDPOINT_IN; + + /* Decide whether to use it for intput or output. */ + if (dev->input_endpoint == 0 && + is_interrupt && is_input) { + /* Use this endpoint for INPUT */ + dev->input_endpoint = ep->bEndpointAddress; + dev->input_ep_max_packet_size = ep->wMaxPacketSize; + } + if (dev->output_endpoint == 0 && + is_interrupt && is_output) { + /* Use this endpoint for OUTPUT */ + dev->output_endpoint = ep->bEndpointAddress; + } + } + + pthread_create(&dev->thread, NULL, read_thread, dev); + + // Wait here for the read thread to be initialized. + pthread_barrier_wait(&dev->barrier); + + } + free(dev_path); + } + } + } + libusb_free_config_descriptor(conf_desc); + + } + + libusb_free_device_list(devs, 1); + + // If we have a good handle, return it. + if (good_open) { + return dev; + } + else { + // Unable to open any devices. + free_hid_device(dev); + return NULL; + } +} + + +int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + int res; + int report_number = data[0]; + int skipped_report_id = 0; + + if (report_number == 0x0) { + data++; + length--; + skipped_report_id = 1; + } + + + if (dev->output_endpoint <= 0) { + /* No interrput out endpoint. Use the Control Endpoint */ + res = libusb_control_transfer(dev->device_handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, + 0x09/*HID Set_Report*/, + (2/*HID output*/ << 8) | report_number, + dev->interface, + (unsigned char *)data, length, + 1000/*timeout millis*/); + + if (res < 0) + return -1; + + if (skipped_report_id) + length++; + + return length; + } + else { + /* Use the interrupt out endpoint */ + int actual_length; + res = libusb_interrupt_transfer(dev->device_handle, + dev->output_endpoint, + (unsigned char*)data, + length, + &actual_length, 1000); + + if (res < 0) + return -1; + + if (skipped_report_id) + actual_length++; + + return actual_length; + } +} + +/* Helper function, to simplify hid_read(). + This should be called with dev->mutex locked. */ +static int return_data(hid_device *dev, unsigned char *data, size_t length) +{ + /* Copy the data out of the linked list item (rpt) into the + return buffer (data), and delete the liked list item. */ + struct input_report *rpt = dev->input_reports; + size_t len = (length < rpt->len)? length: rpt->len; + if (len > 0) + memcpy(data, rpt->data, len); + dev->input_reports = rpt->next; + free(rpt->data); + free(rpt); + return len; +} + +static void cleanup_mutex(void *param) +{ + hid_device *dev = param; + pthread_mutex_unlock(&dev->mutex); +} + + +int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + int bytes_read = -1; + +#if 0 + int transferred; + int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000); + LOG("transferred: %d\n", transferred); + return transferred; +#endif + + pthread_mutex_lock(&dev->mutex); + pthread_cleanup_push(&cleanup_mutex, dev); + + /* There's an input report queued up. Return it. */ + if (dev->input_reports) { + /* Return the first one */ + bytes_read = return_data(dev, data, length); + goto ret; + } + + if (dev->shutdown_thread) { + /* This means the device has been disconnected. + An error code of -1 should be returned. */ + bytes_read = -1; + goto ret; + } + + if (milliseconds == -1) { + /* Blocking */ + while (!dev->input_reports && !dev->shutdown_thread) { + pthread_cond_wait(&dev->condition, &dev->mutex); + } + if (dev->input_reports) { + bytes_read = return_data(dev, data, length); + } + } + else if (milliseconds > 0) { + /* Non-blocking, but called with timeout. */ + int res; + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += milliseconds / 1000; + ts.tv_nsec += (milliseconds % 1000) * 1000000; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + while (!dev->input_reports && !dev->shutdown_thread) { + res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts); + if (res == 0) { + if (dev->input_reports) { + bytes_read = return_data(dev, data, length); + break; + } + + /* If we're here, there was a spurious wake up + or the read thread was shutdown. Run the + loop again (ie: don't break). */ + } + else if (res == ETIMEDOUT) { + /* Timed out. */ + bytes_read = 0; + break; + } + else { + /* Error. */ + bytes_read = -1; + break; + } + } + } + else { + /* Purely non-blocking */ + bytes_read = 0; + } + +ret: + pthread_mutex_unlock(&dev->mutex); + pthread_cleanup_pop(0); + + return bytes_read; +} + +int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0); +} + +int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) +{ + dev->blocking = !nonblock; + + return 0; +} + + +int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + int res = -1; + int skipped_report_id = 0; + int report_number = data[0]; + + if (report_number == 0x0) { + data++; + length--; + skipped_report_id = 1; + } + + res = libusb_control_transfer(dev->device_handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, + 0x09/*HID set_report*/, + (3/*HID feature*/ << 8) | report_number, + dev->interface, + (unsigned char *)data, length, + 1000/*timeout millis*/); + + if (res < 0) + return -1; + + /* Account for the report ID */ + if (skipped_report_id) + length++; + + return length; +} + +int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + int res = -1; + int skipped_report_id = 0; + int report_number = data[0]; + + if (report_number == 0x0) { + /* Offset the return buffer by 1, so that the report ID + will remain in byte 0. */ + data++; + length--; + skipped_report_id = 1; + } + res = libusb_control_transfer(dev->device_handle, + LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN, + 0x01/*HID get_report*/, + (3/*HID feature*/ << 8) | report_number, + dev->interface, + (unsigned char *)data, length, + 1000/*timeout millis*/); + + if (res < 0) + return -1; + + if (skipped_report_id) + res++; + + return res; +} + + +void HID_API_EXPORT hid_close(hid_device *dev) +{ + if (!dev) + return; + + /* Cause read_thread() to stop. */ + dev->shutdown_thread = 1; + libusb_cancel_transfer(dev->transfer); + + /* Wait for read_thread() to end. */ + pthread_join(dev->thread, NULL); + + /* Clean up the Transfer objects allocated in read_thread(). */ + free(dev->transfer->buffer); + libusb_free_transfer(dev->transfer); + + /* release the interface */ + libusb_release_interface(dev->device_handle, dev->interface); + + /* Close the handle */ + libusb_close(dev->device_handle); + + /* Clear out the queue of received reports. */ + pthread_mutex_lock(&dev->mutex); + while (dev->input_reports) { + return_data(dev, NULL, 0); + } + pthread_mutex_unlock(&dev->mutex); + + free_hid_device(dev); +} + + +int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return hid_get_indexed_string(dev, dev->product_index, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return hid_get_indexed_string(dev, dev->serial_index, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + wchar_t *str; + + str = get_usb_string(dev->device_handle, string_index); + if (str) { + wcsncpy(string, str, maxlen); + string[maxlen-1] = L'\0'; + free(str); + return 0; + } + else + return -1; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + return NULL; +} + + +struct lang_map_entry { + const char *name; + const char *string_code; + uint16_t usb_code; +}; + +#define LANG(name,code,usb_code) { name, code, usb_code } +static struct lang_map_entry lang_map[] = { + LANG("Afrikaans", "af", 0x0436), + LANG("Albanian", "sq", 0x041C), + LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801), + LANG("Arabic - Bahrain", "ar_bh", 0x3C01), + LANG("Arabic - Algeria", "ar_dz", 0x1401), + LANG("Arabic - Egypt", "ar_eg", 0x0C01), + LANG("Arabic - Iraq", "ar_iq", 0x0801), + LANG("Arabic - Jordan", "ar_jo", 0x2C01), + LANG("Arabic - Kuwait", "ar_kw", 0x3401), + LANG("Arabic - Lebanon", "ar_lb", 0x3001), + LANG("Arabic - Libya", "ar_ly", 0x1001), + LANG("Arabic - Morocco", "ar_ma", 0x1801), + LANG("Arabic - Oman", "ar_om", 0x2001), + LANG("Arabic - Qatar", "ar_qa", 0x4001), + LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401), + LANG("Arabic - Syria", "ar_sy", 0x2801), + LANG("Arabic - Tunisia", "ar_tn", 0x1C01), + LANG("Arabic - Yemen", "ar_ye", 0x2401), + LANG("Armenian", "hy", 0x042B), + LANG("Azeri - Latin", "az_az", 0x042C), + LANG("Azeri - Cyrillic", "az_az", 0x082C), + LANG("Basque", "eu", 0x042D), + LANG("Belarusian", "be", 0x0423), + LANG("Bulgarian", "bg", 0x0402), + LANG("Catalan", "ca", 0x0403), + LANG("Chinese - China", "zh_cn", 0x0804), + LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04), + LANG("Chinese - Macau SAR", "zh_mo", 0x1404), + LANG("Chinese - Singapore", "zh_sg", 0x1004), + LANG("Chinese - Taiwan", "zh_tw", 0x0404), + LANG("Croatian", "hr", 0x041A), + LANG("Czech", "cs", 0x0405), + LANG("Danish", "da", 0x0406), + LANG("Dutch - Netherlands", "nl_nl", 0x0413), + LANG("Dutch - Belgium", "nl_be", 0x0813), + LANG("English - Australia", "en_au", 0x0C09), + LANG("English - Belize", "en_bz", 0x2809), + LANG("English - Canada", "en_ca", 0x1009), + LANG("English - Caribbean", "en_cb", 0x2409), + LANG("English - Ireland", "en_ie", 0x1809), + LANG("English - Jamaica", "en_jm", 0x2009), + LANG("English - New Zealand", "en_nz", 0x1409), + LANG("English - Phillippines", "en_ph", 0x3409), + LANG("English - Southern Africa", "en_za", 0x1C09), + LANG("English - Trinidad", "en_tt", 0x2C09), + LANG("English - Great Britain", "en_gb", 0x0809), + LANG("English - United States", "en_us", 0x0409), + LANG("Estonian", "et", 0x0425), + LANG("Farsi", "fa", 0x0429), + LANG("Finnish", "fi", 0x040B), + LANG("Faroese", "fo", 0x0438), + LANG("French - France", "fr_fr", 0x040C), + LANG("French - Belgium", "fr_be", 0x080C), + LANG("French - Canada", "fr_ca", 0x0C0C), + LANG("French - Luxembourg", "fr_lu", 0x140C), + LANG("French - Switzerland", "fr_ch", 0x100C), + LANG("Gaelic - Ireland", "gd_ie", 0x083C), + LANG("Gaelic - Scotland", "gd", 0x043C), + LANG("German - Germany", "de_de", 0x0407), + LANG("German - Austria", "de_at", 0x0C07), + LANG("German - Liechtenstein", "de_li", 0x1407), + LANG("German - Luxembourg", "de_lu", 0x1007), + LANG("German - Switzerland", "de_ch", 0x0807), + LANG("Greek", "el", 0x0408), + LANG("Hebrew", "he", 0x040D), + LANG("Hindi", "hi", 0x0439), + LANG("Hungarian", "hu", 0x040E), + LANG("Icelandic", "is", 0x040F), + LANG("Indonesian", "id", 0x0421), + LANG("Italian - Italy", "it_it", 0x0410), + LANG("Italian - Switzerland", "it_ch", 0x0810), + LANG("Japanese", "ja", 0x0411), + LANG("Korean", "ko", 0x0412), + LANG("Latvian", "lv", 0x0426), + LANG("Lithuanian", "lt", 0x0427), + LANG("F.Y.R.O. Macedonia", "mk", 0x042F), + LANG("Malay - Malaysia", "ms_my", 0x043E), + LANG("Malay - Brunei", "ms_bn", 0x083E), + LANG("Maltese", "mt", 0x043A), + LANG("Marathi", "mr", 0x044E), + LANG("Norwegian - Bokml", "no_no", 0x0414), + LANG("Norwegian - Nynorsk", "no_no", 0x0814), + LANG("Polish", "pl", 0x0415), + LANG("Portuguese - Portugal", "pt_pt", 0x0816), + LANG("Portuguese - Brazil", "pt_br", 0x0416), + LANG("Raeto-Romance", "rm", 0x0417), + LANG("Romanian - Romania", "ro", 0x0418), + LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818), + LANG("Russian", "ru", 0x0419), + LANG("Russian - Republic of Moldova", "ru_mo", 0x0819), + LANG("Sanskrit", "sa", 0x044F), + LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A), + LANG("Serbian - Latin", "sr_sp", 0x081A), + LANG("Setsuana", "tn", 0x0432), + LANG("Slovenian", "sl", 0x0424), + LANG("Slovak", "sk", 0x041B), + LANG("Sorbian", "sb", 0x042E), + LANG("Spanish - Spain (Traditional)", "es_es", 0x040A), + LANG("Spanish - Argentina", "es_ar", 0x2C0A), + LANG("Spanish - Bolivia", "es_bo", 0x400A), + LANG("Spanish - Chile", "es_cl", 0x340A), + LANG("Spanish - Colombia", "es_co", 0x240A), + LANG("Spanish - Costa Rica", "es_cr", 0x140A), + LANG("Spanish - Dominican Republic", "es_do", 0x1C0A), + LANG("Spanish - Ecuador", "es_ec", 0x300A), + LANG("Spanish - Guatemala", "es_gt", 0x100A), + LANG("Spanish - Honduras", "es_hn", 0x480A), + LANG("Spanish - Mexico", "es_mx", 0x080A), + LANG("Spanish - Nicaragua", "es_ni", 0x4C0A), + LANG("Spanish - Panama", "es_pa", 0x180A), + LANG("Spanish - Peru", "es_pe", 0x280A), + LANG("Spanish - Puerto Rico", "es_pr", 0x500A), + LANG("Spanish - Paraguay", "es_py", 0x3C0A), + LANG("Spanish - El Salvador", "es_sv", 0x440A), + LANG("Spanish - Uruguay", "es_uy", 0x380A), + LANG("Spanish - Venezuela", "es_ve", 0x200A), + LANG("Southern Sotho", "st", 0x0430), + LANG("Swahili", "sw", 0x0441), + LANG("Swedish - Sweden", "sv_se", 0x041D), + LANG("Swedish - Finland", "sv_fi", 0x081D), + LANG("Tamil", "ta", 0x0449), + LANG("Tatar", "tt", 0X0444), + LANG("Thai", "th", 0x041E), + LANG("Turkish", "tr", 0x041F), + LANG("Tsonga", "ts", 0x0431), + LANG("Ukrainian", "uk", 0x0422), + LANG("Urdu", "ur", 0x0420), + LANG("Uzbek - Cyrillic", "uz_uz", 0x0843), + LANG("Uzbek - Latin", "uz_uz", 0x0443), + LANG("Vietnamese", "vi", 0x042A), + LANG("Xhosa", "xh", 0x0434), + LANG("Yiddish", "yi", 0x043D), + LANG("Zulu", "zu", 0x0435), + LANG(NULL, NULL, 0x0), +}; + +uint16_t get_usb_code_for_current_locale(void) +{ + char *locale; + char search_string[64]; + char *ptr; + + /* Get the current locale. */ + locale = setlocale(0, NULL); + if (!locale) + return 0x0; + + /* Make a copy of the current locale string. */ + strncpy(search_string, locale, sizeof(search_string)); + search_string[sizeof(search_string)-1] = '\0'; + + /* Chop off the encoding part, and make it lower case. */ + ptr = search_string; + while (*ptr) { + *ptr = tolower(*ptr); + if (*ptr == '.') { + *ptr = '\0'; + break; + } + ptr++; + } + + /* Find the entry which matches the string code of our locale. */ + struct lang_map_entry *lang = lang_map; + while (lang->string_code) { + if (!strcmp(lang->string_code, search_string)) { + return lang->usb_code; + } + lang++; + } + + /* There was no match. Find with just the language only. */ + /* Chop off the variant. Chop it off at the '_'. */ + ptr = search_string; + while (*ptr) { + *ptr = tolower(*ptr); + if (*ptr == '_') { + *ptr = '\0'; + break; + } + ptr++; + } + +#if 0 // TODO: Do we need this? + /* Find the entry which matches the string code of our language. */ + lang = lang_map; + while (lang->string_code) { + if (!strcmp(lang->string_code, search_string)) { + return lang->usb_code; + } + lang++; + } +#endif + + /* Found nothing. */ + return 0x0; +} + +#ifdef __cplusplus +} +#endif diff -Nru libindi-1.0.0/libs/indibase/hid_mac.c libindi-1.1.0/libs/indibase/hid_mac.c --- libindi-1.0.0/libs/indibase/hid_mac.c 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/hid_mac.c 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,1107 @@ +/* + HIDAPI - Multi-Platform library for communication with HID devices. + + Copyright (c) 2009 by Alan Ott, Signal 11 Software (7/3/2010) + All Rights Reserved. + + Changes for use with SX Filter Wheel INDI Driver by CloudMakers - 11/6/2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + These files may also be found in the public source code repository located: + http://github.com/signal11/hidapi +*/ + +/* See Apple Technical Note TN2187 for details on IOHidManager. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hidapi.h" + +/* Barrier implementation because Mac OSX doesn't have pthread_barrier. + It also doesn't have clock_gettime(). So much for POSIX and SUSv2. + This implementation came from Brent Priddy and was posted on + StackOverflow. It is used with his permission. */ +typedef int pthread_barrierattr_t; +typedef struct pthread_barrier { + pthread_mutex_t mutex; + pthread_cond_t cond; + int count; + int trip_count; +} pthread_barrier_t; + +static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) +{ + if(count == 0) { + errno = EINVAL; + return -1; + } + + if(pthread_mutex_init(&barrier->mutex, 0) < 0) { + return -1; + } + if(pthread_cond_init(&barrier->cond, 0) < 0) { + pthread_mutex_destroy(&barrier->mutex); + return -1; + } + barrier->trip_count = count; + barrier->count = 0; + + return 0; +} + +static int pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +static int pthread_barrier_wait(pthread_barrier_t *barrier) +{ + pthread_mutex_lock(&barrier->mutex); + ++(barrier->count); + if(barrier->count >= barrier->trip_count) + { + barrier->count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return 1; + } + else + { + pthread_cond_wait(&barrier->cond, &(barrier->mutex)); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } +} + +static int return_data(hid_device *dev, unsigned char *data, size_t length); + +/* Linked List of input reports received from the device. */ +struct input_report { + uint8_t *data; + size_t len; + struct input_report *next; +}; + +struct hid_device_ { + IOHIDDeviceRef device_handle; + int blocking; + int uses_numbered_reports; + int disconnected; + CFStringRef run_loop_mode; + CFRunLoopRef run_loop; + CFRunLoopSourceRef source; + uint8_t *input_report_buf; + CFIndex max_input_report_len; + struct input_report *input_reports; + + pthread_t thread; + pthread_mutex_t mutex; /* Protects input_reports */ + pthread_cond_t condition; + pthread_barrier_t barrier; /* Ensures correct startup sequence */ + pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */ + int shutdown_thread; +}; + +static hid_device *new_hid_device(void) +{ + hid_device *dev = calloc(1, sizeof(hid_device)); + dev->device_handle = NULL; + dev->blocking = 1; + dev->uses_numbered_reports = 0; + dev->disconnected = 0; + dev->run_loop_mode = NULL; + dev->run_loop = NULL; + dev->source = NULL; + dev->input_report_buf = NULL; + dev->input_reports = NULL; + dev->shutdown_thread = 0; + + /* Thread objects */ + pthread_mutex_init(&dev->mutex, NULL); + pthread_cond_init(&dev->condition, NULL); + pthread_barrier_init(&dev->barrier, NULL, 2); + pthread_barrier_init(&dev->shutdown_barrier, NULL, 2); + + return dev; +} + +static void free_hid_device(hid_device *dev) +{ + if (!dev) + return; + + /* Delete any input reports still left over. */ + struct input_report *rpt = dev->input_reports; + while (rpt) { + struct input_report *next = rpt->next; + free(rpt->data); + free(rpt); + rpt = next; + } + + /* Free the string and the report buffer. The check for NULL + is necessary here as CFRelease() doesn't handle NULL like + free() and others do. */ + if (dev->run_loop_mode) + CFRelease(dev->run_loop_mode); + if (dev->source) + CFRelease(dev->source); + free(dev->input_report_buf); + + /* Clean up the thread objects */ + pthread_barrier_destroy(&dev->shutdown_barrier); + pthread_barrier_destroy(&dev->barrier); + pthread_cond_destroy(&dev->condition); + pthread_mutex_destroy(&dev->mutex); + + /* Free the structure itself. */ + free(dev); +} + +static IOHIDManagerRef hid_mgr = 0x0; + + +#if 0 +static void register_error(hid_device *device, const char *op) +{ + +} +#endif + + +static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) +{ + CFTypeRef ref; + int32_t value; + + ref = IOHIDDeviceGetProperty(device, key); + if (ref) { + if (CFGetTypeID(ref) == CFNumberGetTypeID()) { + CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value); + return value; + } + } + return 0; +} + +static unsigned short get_vendor_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDVendorIDKey)); +} + +static unsigned short get_product_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDProductIDKey)); +} + + +static int32_t get_max_report_length(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey)); +} + +static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len) +{ + CFStringRef str; + + if (!len) + return 0; + + str = IOHIDDeviceGetProperty(device, prop); + + buf[0] = 0; + + if (str) { + len --; + + CFIndex str_len = CFStringGetLength(str); + CFRange range; + range.location = 0; + range.length = (str_len > len)? len: str_len; + CFIndex used_buf_len; + CFIndex chars_copied; + chars_copied = CFStringGetBytes(str, + range, + kCFStringEncodingUTF32LE, + (char)'?', + FALSE, + (UInt8*)buf, + len, + &used_buf_len); + + buf[chars_copied] = 0; + return 0; + } + else + return -1; + +} + +static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len) +{ + CFStringRef str; + if (!len) + return 0; + + str = IOHIDDeviceGetProperty(device, prop); + + buf[0] = 0; + + if (str) { + len--; + + CFIndex str_len = CFStringGetLength(str); + CFRange range; + range.location = 0; + range.length = (str_len > len)? len: str_len; + CFIndex used_buf_len; + CFIndex chars_copied; + chars_copied = CFStringGetBytes(str, + range, + kCFStringEncodingUTF8, + (char)'?', + FALSE, + (UInt8*)buf, + len, + &used_buf_len); + + buf[chars_copied] = 0; + return used_buf_len; + } + else + return 0; +} + + +static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); +} + +static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len); +} + +static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len); +} + + +/* Implementation of wcsdup() for Mac. */ +static wchar_t *dup_wcs(const wchar_t *s) +{ + size_t len = wcslen(s); + wchar_t *ret = malloc((len+1)*sizeof(wchar_t)); + wcscpy(ret, s); + + return ret; +} + + +static int make_path(IOHIDDeviceRef device, char *buf, size_t len) +{ + int res; + unsigned short vid, pid; + char transport[32]; + + buf[0] = '\0'; + + res = get_string_property_utf8( + device, CFSTR(kIOHIDTransportKey), + transport, sizeof(transport)); + + if (!res) + return -1; + + vid = get_vendor_id(device); + pid = get_product_id(device); + + res = snprintf(buf, len, "%s_%04hx_%04hx_%p", + transport, vid, pid, device); + + + buf[len-1] = '\0'; + return res+1; +} + +/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */ +static int init_hid_manager(void) +{ + /* Initialize all the HID Manager Objects */ + hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hid_mgr) { + IOHIDManagerSetDeviceMatching(hid_mgr, NULL); + IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + return 0; + } + + return -1; +} + +/* Initialize the IOHIDManager if necessary. This is the public function, and + it is safe to call this function repeatedly. Return 0 for success and -1 + for failure. */ +int HID_API_EXPORT hid_init(void) +{ + if (!hid_mgr) { + return init_hid_manager(); + } + + /* Already initialized. */ + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ + if (hid_mgr) { + /* Close the HID manager. */ + IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone); + CFRelease(hid_mgr); + hid_mgr = NULL; + } + + return 0; +} + +static void process_pending_events(void) { + SInt32 res; + do { + res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE); + } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); +} + +struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + struct hid_device_info *root = NULL; // return object + struct hid_device_info *cur_dev = NULL; + CFIndex num_devices; + int i; + + /* Set up the HID Manager if it hasn't been done */ + if (hid_init() < 0) + return NULL; + + /* give the IOHIDManager a chance to update itself */ + process_pending_events(); + + /* Get a list of the Devices */ + CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); + + /* Convert the list into a C array so we can iterate easily. */ + num_devices = CFSetGetCount(device_set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(device_set, (const void **) device_array); + + /* Iterate over each device, making an entry for it. */ + for (i = 0; i < num_devices; i++) { + unsigned short dev_vid; + unsigned short dev_pid; + #define BUF_LEN 256 + wchar_t buf[BUF_LEN]; + char cbuf[BUF_LEN]; + + IOHIDDeviceRef dev = device_array[i]; + + if (!dev) { + continue; + } + dev_vid = get_vendor_id(dev); + dev_pid = get_product_id(dev); + + /* Check the VID/PID against the arguments */ + if ((vendor_id == 0x0 && product_id == 0x0) || + (vendor_id == dev_vid && product_id == dev_pid)) { + struct hid_device_info *tmp; + size_t len; + + /* VID/PID match. Create the record. */ + tmp = malloc(sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + // Get the Usage Page and Usage for this device. + cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey)); + cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey)); + + /* Fill out the record */ + cur_dev->next = NULL; + len = make_path(dev, cbuf, sizeof(cbuf)); + cur_dev->path = strdup(cbuf); + + /* Serial Number */ + get_serial_number(dev, buf, BUF_LEN); + cur_dev->serial_number = dup_wcs(buf); + + /* Manufacturer and Product strings */ + get_manufacturer_string(dev, buf, BUF_LEN); + cur_dev->manufacturer_string = dup_wcs(buf); + get_product_string(dev, buf, BUF_LEN); + cur_dev->product_string = dup_wcs(buf); + + /* VID/PID */ + cur_dev->vendor_id = dev_vid; + cur_dev->product_id = dev_pid; + + /* Release Number */ + cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); + + /* Interface Number (Unsupported on Mac)*/ + cur_dev->interface_number = -1; + } + } + + free(device_array); + CFRelease(device_set); + + return root; +} + +void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) +{ + /* This function is identical to the Linux version. Platform independent. */ + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + +hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + /* This function is identical to the Linux version. Platform independent. */ + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device * handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +static void hid_device_removal_callback(void *context, IOReturn result, + void *sender) +{ + /* Stop the Run Loop for this device. */ + hid_device *d = context; + + d->disconnected = 1; + CFRunLoopStop(d->run_loop); +} + +/* The Run Loop calls this function for each input report received. + This function puts the data into a linked list to be picked up by + hid_read(). */ +static void hid_report_callback(void *context, IOReturn result, void *sender, + IOHIDReportType report_type, uint32_t report_id, + uint8_t *report, CFIndex report_length) +{ + struct input_report *rpt; + hid_device *dev = context; + + /* Make a new Input Report object */ + rpt = calloc(1, sizeof(struct input_report)); + rpt->data = calloc(1, report_length); + memcpy(rpt->data, report, report_length); + rpt->len = report_length; + rpt->next = NULL; + + /* Lock this section */ + pthread_mutex_lock(&dev->mutex); + + /* Attach the new report object to the end of the list. */ + if (dev->input_reports == NULL) { + /* The list is empty. Put it at the root. */ + dev->input_reports = rpt; + } + else { + /* Find the end of the list and attach. */ + struct input_report *cur = dev->input_reports; + int num_queued = 0; + while (cur->next != NULL) { + cur = cur->next; + num_queued++; + } + cur->next = rpt; + + /* Pop one off if we've reached 30 in the queue. This + way we don't grow forever if the user never reads + anything from the device. */ + if (num_queued > 30) { + return_data(dev, NULL, 0); + } + } + + /* Signal a waiting thread that there is data. */ + pthread_cond_signal(&dev->condition); + + /* Unlock */ + pthread_mutex_unlock(&dev->mutex); + +} + +/* This gets called when the read_thred's run loop gets signaled by + hid_close(), and serves to stop the read_thread's run loop. */ +static void perform_signal_callback(void *context) +{ + hid_device *dev = context; + CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent() +} + +static void *read_thread(void *param) +{ + hid_device *dev = param; + + /* Move the device's run loop to this thread. */ + IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode); + + /* Create the RunLoopSource which is used to signal the + event loop to stop when hid_close() is called. */ + CFRunLoopSourceContext ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.version = 0; + ctx.info = dev; + ctx.perform = &perform_signal_callback; + dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx); + CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode); + + /* Store off the Run Loop so it can be stopped from hid_close() + and on device disconnection. */ + dev->run_loop = CFRunLoopGetCurrent(); + + /* Notify the main thread that the read thread is up and running. */ + pthread_barrier_wait(&dev->barrier); + + /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input + reports into the hid_report_callback(). */ + SInt32 code; + while (!dev->shutdown_thread && !dev->disconnected) { + code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE); + /* Return if the device has been disconnected */ + if (code == kCFRunLoopRunFinished) { + dev->disconnected = 1; + break; + } + + + /* Break if The Run Loop returns Finished or Stopped. */ + if (code != kCFRunLoopRunTimedOut && + code != kCFRunLoopRunHandledSource) { + /* There was some kind of error. Setting + shutdown seems to make sense, but + there may be something else more appropriate */ + dev->shutdown_thread = 1; + break; + } + } + + /* Now that the read thread is stopping, Wake any threads which are + waiting on data (in hid_read_timeout()). Do this under a mutex to + make sure that a thread which is about to go to sleep waiting on + the condition acutally will go to sleep before the condition is + signaled. */ + pthread_mutex_lock(&dev->mutex); + pthread_cond_broadcast(&dev->condition); + pthread_mutex_unlock(&dev->mutex); + + /* Wait here until hid_close() is called and makes it past + the call to CFRunLoopWakeUp(). This thread still needs to + be valid when that function is called on the other thread. */ + pthread_barrier_wait(&dev->shutdown_barrier); + + return NULL; +} + +hid_device * HID_API_EXPORT hid_open_path(const char *path) +{ + int i; + hid_device *dev = NULL; + CFIndex num_devices; + + dev = new_hid_device(); + + /* Set up the HID Manager if it hasn't been done */ + if (hid_init() < 0) + return NULL; + + /* give the IOHIDManager a chance to update itself */ + process_pending_events(); + + CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); + + num_devices = CFSetGetCount(device_set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(device_set, (const void **) device_array); + for (i = 0; i < num_devices; i++) { + char cbuf[BUF_LEN]; + size_t len; + IOHIDDeviceRef os_dev = device_array[i]; + + len = make_path(os_dev, cbuf, sizeof(cbuf)); + if (!strcmp(cbuf, path)) { + // Matched Paths. Open this Device. + IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone); + if (ret == kIOReturnSuccess) { + char str[32]; + + free(device_array); + CFRetain(os_dev); + CFRelease(device_set); + dev->device_handle = os_dev; + + /* Create the buffers for receiving data */ + dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev); + dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t)); + + /* Create the Run Loop Mode for this device. + printing the reference seems to work. */ + sprintf(str, "HIDAPI_%p", os_dev); + dev->run_loop_mode = + CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII); + + /* Attach the device to a Run Loop */ + IOHIDDeviceRegisterInputReportCallback( + os_dev, dev->input_report_buf, dev->max_input_report_len, + &hid_report_callback, dev); + IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev); + + /* Start the read thread */ + pthread_create(&dev->thread, NULL, read_thread, dev); + + /* Wait here for the read thread to be initialized. */ + pthread_barrier_wait(&dev->barrier); + + return dev; + } + else { + goto return_error; + } + } + } + +return_error: + free(device_array); + CFRelease(device_set); + free_hid_device(dev); + return NULL; +} + +static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length) +{ + const unsigned char *data_to_send; + size_t length_to_send; + IOReturn res; + + /* Return if the device has been disconnected. */ + if (dev->disconnected) + return -1; + + if (data[0] == 0x0) { + /* Not using numbered Reports. + Don't send the report number. */ + data_to_send = data+1; + length_to_send = length-1; + } + else { + /* Using numbered Reports. + Send the Report Number */ + data_to_send = data; + length_to_send = length; + } + + if (!dev->disconnected) { + res = IOHIDDeviceSetReport(dev->device_handle, + type, + data[0], /* Report ID*/ + data_to_send, length_to_send); + + if (res == kIOReturnSuccess) { + return length; + } + else + return -1; + } + + return -1; +} + +int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + return set_report(dev, kIOHIDReportTypeOutput, data, length); +} + +/* Helper function, so that this isn't duplicated in hid_read(). */ +static int return_data(hid_device *dev, unsigned char *data, size_t length) +{ + /* Copy the data out of the linked list item (rpt) into the + return buffer (data), and delete the liked list item. */ + struct input_report *rpt = dev->input_reports; + size_t len = (length < rpt->len)? length: rpt->len; + memcpy(data, rpt->data, len); + dev->input_reports = rpt->next; + free(rpt->data); + free(rpt); + return len; +} + +static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + while (!dev->input_reports) { + int res = pthread_cond_wait(cond, mutex); + if (res != 0) + return res; + + /* A res of 0 means we may have been signaled or it may + be a spurious wakeup. Check to see that there's acutally + data in the queue before returning, and if not, go back + to sleep. See the pthread_cond_timedwait() man page for + details. */ + + if (dev->shutdown_thread || dev->disconnected) + return -1; + } + + return 0; +} + +static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) +{ + while (!dev->input_reports) { + int res = pthread_cond_timedwait(cond, mutex, abstime); + if (res != 0) + return res; + + /* A res of 0 means we may have been signaled or it may + be a spurious wakeup. Check to see that there's acutally + data in the queue before returning, and if not, go back + to sleep. See the pthread_cond_timedwait() man page for + details. */ + + if (dev->shutdown_thread || dev->disconnected) + return -1; + } + + return 0; + +} + +int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + int bytes_read = -1; + + /* Lock the access to the report list. */ + pthread_mutex_lock(&dev->mutex); + + /* There's an input report queued up. Return it. */ + if (dev->input_reports) { + /* Return the first one */ + bytes_read = return_data(dev, data, length); + goto ret; + } + + /* Return if the device has been disconnected. */ + if (dev->disconnected) { + bytes_read = -1; + goto ret; + } + + if (dev->shutdown_thread) { + /* This means the device has been closed (or there + has been an error. An error code of -1 should + be returned. */ + bytes_read = -1; + goto ret; + } + + /* There is no data. Go to sleep and wait for data. */ + + if (milliseconds == -1) { + /* Blocking */ + int res; + res = cond_wait(dev, &dev->condition, &dev->mutex); + if (res == 0) + bytes_read = return_data(dev, data, length); + else { + /* There was an error, or a device disconnection. */ + bytes_read = -1; + } + } + else if (milliseconds > 0) { + /* Non-blocking, but called with timeout. */ + int res; + struct timespec ts; + struct timeval tv; + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + ts.tv_sec += milliseconds / 1000; + ts.tv_nsec += (milliseconds % 1000) * 1000000; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts); + if (res == 0) + bytes_read = return_data(dev, data, length); + else if (res == ETIMEDOUT) + bytes_read = 0; + else + bytes_read = -1; + } + else { + /* Purely non-blocking */ + bytes_read = 0; + } + +ret: + /* Unlock */ + pthread_mutex_unlock(&dev->mutex); + return bytes_read; +} + +int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) +{ + /* All Nonblocking operation is handled by the library. */ + dev->blocking = !nonblock; + + return 0; +} + +int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + return set_report(dev, kIOHIDReportTypeFeature, data, length); +} + +int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + CFIndex len = length; + IOReturn res; + + /* Return if the device has been unplugged. */ + if (dev->disconnected) + return -1; + + res = IOHIDDeviceGetReport(dev->device_handle, + kIOHIDReportTypeFeature, + data[0], /* Report ID */ + data, &len); + if (res == kIOReturnSuccess) + return len; + else + return -1; +} + + +void HID_API_EXPORT hid_close(hid_device *dev) +{ + if (!dev) + return; + + /* Disconnect the report callback before close. */ + if (!dev->disconnected) { + IOHIDDeviceRegisterInputReportCallback( + dev->device_handle, dev->input_report_buf, dev->max_input_report_len, + NULL, dev); + IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev); + IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode); + IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode); + } + + /* Cause read_thread() to stop. */ + dev->shutdown_thread = 1; + + /* Wake up the run thread's event loop so that the thread can exit. */ + CFRunLoopSourceSignal(dev->source); + CFRunLoopWakeUp(dev->run_loop); + + /* Notify the read thread that it can shut down now. */ + pthread_barrier_wait(&dev->shutdown_barrier); + + /* Wait for read_thread() to end. */ + pthread_join(dev->thread, NULL); + + /* Close the OS handle to the device, but only if it's not + been unplugged. If it's been unplugged, then calling + IOHIDDeviceClose() will crash. */ + if (!dev->disconnected) { + IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone); + } + + /* Clear out the queue of received reports. */ + pthread_mutex_lock(&dev->mutex); + while (dev->input_reports) { + return_data(dev, NULL, 0); + } + pthread_mutex_unlock(&dev->mutex); + CFRelease(dev->device_handle); + + free_hid_device(dev); +} + +int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_manufacturer_string(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_product_string(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + return get_serial_number(dev->device_handle, string, maxlen); +} + +int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + // TODO: + + return 0; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + // TODO: + + return NULL; +} + + + + + + +#if 0 +static int32_t get_location_id(IOHIDDeviceRef device) +{ + return get_int_property(device, CFSTR(kIOHIDLocationIDKey)); +} + +static int32_t get_usage(IOHIDDeviceRef device) +{ + int32_t res; + res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey)); + if (!res) + res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)); + return res; +} + +static int32_t get_usage_page(IOHIDDeviceRef device) +{ + int32_t res; + res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey)); + if (!res) + res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey)); + return res; +} + +static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len) +{ + return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len); +} + + +int main(void) +{ + IOHIDManagerRef mgr; + int i; + + mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + IOHIDManagerSetDeviceMatching(mgr, NULL); + IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone); + + CFSetRef device_set = IOHIDManagerCopyDevices(mgr); + + CFIndex num_devices = CFSetGetCount(device_set); + IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); + CFSetGetValues(device_set, (const void **) device_array); + + for (i = 0; i < num_devices; i++) { + IOHIDDeviceRef dev = device_array[i]; + printf("Device: %p\n", dev); + printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev)); + + wchar_t serial[256], buf[256]; + char cbuf[256]; + get_serial_number(dev, serial, 256); + + + printf(" Serial: %ls\n", serial); + printf(" Loc: %ld\n", get_location_id(dev)); + get_transport(dev, buf, 256); + printf(" Trans: %ls\n", buf); + make_path(dev, cbuf, 256); + printf(" Path: %s\n", cbuf); + + } + + return 0; +} +#endif diff -Nru libindi-1.0.0/libs/indibase/hid_win.c libindi-1.1.0/libs/indibase/hid_win.c --- libindi-1.0.0/libs/indibase/hid_win.c 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/hid_win.c 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,927 @@ +/* + HIDAPI - Multi-Platform library for communication with HID devices. + + Copyright (c) 2009 by Alan Ott, Signal 11 Software (8/22/2009) + All Rights Reserved. + + Changes for use with SX Filter Wheel INDI Driver by CloudMakers - 11/6/2012 + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. + + These files may also be found in the public source code repository located: + http://github.com/signal11/hidapi +*/ + +#include + +#ifndef _NTDEF_ +typedef LONG NTSTATUS; +#endif + +#ifdef __MINGW32__ +#include +#include +#endif + +#ifdef __CYGWIN__ +#include +#define _wcsdup wcsdup +#endif + +//#define HIDAPI_USE_DDK + +#ifdef __cplusplus +extern "C" { +#endif + #include + #include + #ifdef HIDAPI_USE_DDK + #include + #endif + + // Copied from inc/ddk/hidclass.h, part of the Windows DDK. + #define HID_OUT_CTL_CODE(id) \ + CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) + +#ifdef __cplusplus +} // extern "C" +#endif + +#include +#include + + +#include "hidapi.h" + +#ifdef _MSC_VER + // Thanks Microsoft, but I know how to use strncpy(). + #pragma warning(disable:4996) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HIDAPI_USE_DDK + // Since we're not building with the DDK, and the HID header + // files aren't part of the SDK, we have to define all this + // stuff here. In lookup_functions(), the function pointers + // defined below are set. + typedef struct _HIDD_ATTRIBUTES{ + ULONG Size; + USHORT VendorID; + USHORT ProductID; + USHORT VersionNumber; + } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; + + typedef USHORT USAGE; + typedef struct _HIDP_CAPS { + USAGE Usage; + USAGE UsagePage; + USHORT InputReportByteLength; + USHORT OutputReportByteLength; + USHORT FeatureReportByteLength; + USHORT Reserved[17]; + USHORT fields_not_used_by_hidapi[10]; + } HIDP_CAPS, *PHIDP_CAPS; + typedef void* PHIDP_PREPARSED_DATA; + #define HIDP_STATUS_SUCCESS 0x110000 + + typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); + typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); + typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); + typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data); + typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data); + typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps); + + static HidD_GetAttributes_ HidD_GetAttributes; + static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; + static HidD_GetManufacturerString_ HidD_GetManufacturerString; + static HidD_GetProductString_ HidD_GetProductString; + static HidD_SetFeature_ HidD_SetFeature; + static HidD_GetFeature_ HidD_GetFeature; + static HidD_GetIndexedString_ HidD_GetIndexedString; + static HidD_GetPreparsedData_ HidD_GetPreparsedData; + static HidD_FreePreparsedData_ HidD_FreePreparsedData; + static HidP_GetCaps_ HidP_GetCaps; + + static HMODULE lib_handle = NULL; + static BOOLEAN initialized = FALSE; +#endif // HIDAPI_USE_DDK + +struct hid_device_ { + HANDLE device_handle; + BOOL blocking; + USHORT output_report_length; + size_t input_report_length; + void *last_error_str; + DWORD last_error_num; + BOOL read_pending; + char *read_buf; + OVERLAPPED ol; +}; + +static hid_device *new_hid_device() +{ + hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); + dev->device_handle = INVALID_HANDLE_VALUE; + dev->blocking = TRUE; + dev->output_report_length = 0; + dev->input_report_length = 0; + dev->last_error_str = NULL; + dev->last_error_num = 0; + dev->read_pending = FALSE; + dev->read_buf = NULL; + memset(&dev->ol, 0, sizeof(dev->ol)); + dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL); + + return dev; +} + + +static void register_error(hid_device *device, const char *op) +{ + WCHAR *ptr, *msg; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&msg, 0/*sz*/, + NULL); + + // Get rid of the CR and LF that FormatMessage() sticks at the + // end of the message. Thanks Microsoft! + ptr = msg; + while (*ptr) { + if (*ptr == '\r') { + *ptr = 0x0000; + break; + } + ptr++; + } + + // Store the message off in the Device entry so that + // the hid_error() function can pick it up. + LocalFree(device->last_error_str); + device->last_error_str = msg; +} + +#ifndef HIDAPI_USE_DDK +static int lookup_functions() +{ + lib_handle = LoadLibraryA("hid.dll"); + if (lib_handle) { +#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; + RESOLVE(HidD_GetAttributes); + RESOLVE(HidD_GetSerialNumberString); + RESOLVE(HidD_GetManufacturerString); + RESOLVE(HidD_GetProductString); + RESOLVE(HidD_SetFeature); + RESOLVE(HidD_GetFeature); + RESOLVE(HidD_GetIndexedString); + RESOLVE(HidD_GetPreparsedData); + RESOLVE(HidD_FreePreparsedData); + RESOLVE(HidP_GetCaps); +#undef RESOLVE + } + else + return -1; + + return 0; +} +#endif + +static HANDLE open_device(const char *path, BOOL enumerate) +{ + HANDLE handle; + DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ); + DWORD share_mode = (enumerate)? + FILE_SHARE_READ|FILE_SHARE_WRITE: + FILE_SHARE_READ; + + handle = CreateFileA(path, + desired_access, + share_mode, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, + 0); + + return handle; +} + +int HID_API_EXPORT hid_init(void) +{ +#ifndef HIDAPI_USE_DDK + if (!initialized) { + if (lookup_functions() < 0) { + hid_exit(); + return -1; + } + initialized = TRUE; + } +#endif + return 0; +} + +int HID_API_EXPORT hid_exit(void) +{ +#ifndef HIDAPI_USE_DDK + if (lib_handle) + FreeLibrary(lib_handle); + lib_handle = NULL; + initialized = FALSE; +#endif + return 0; +} + +struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + BOOL res; + struct hid_device_info *root = NULL; // return object + struct hid_device_info *cur_dev = NULL; + + // Windows objects for interacting with the driver. + GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; + SP_DEVINFO_DATA devinfo_data; + SP_DEVICE_INTERFACE_DATA device_interface_data; + SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; + HDEVINFO device_info_set = INVALID_HANDLE_VALUE; + int device_index = 0; + int i; + + if (hid_init() < 0) + return NULL; + + // Initialize the Windows objects. + memset(&devinfo_data, 0x0, sizeof(devinfo_data)); + devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + // Get information for all the devices belonging to the HID class. + device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + // Iterate over each device in the HID class, looking for the right one. + + for (;;) { + HANDLE write_handle = INVALID_HANDLE_VALUE; + DWORD required_size = 0; + HIDD_ATTRIBUTES attrib; + + res = SetupDiEnumDeviceInterfaces(device_info_set, + NULL, + &InterfaceClassGuid, + device_index, + &device_interface_data); + + if (!res) { + // A return of FALSE from this function means that + // there are no more devices. + break; + } + + // Call with 0-sized detail size, and let the function + // tell us how long the detail struct needs to be. The + // size is put in &required_size. + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + NULL, + 0, + &required_size, + NULL); + + // Allocate a long enough structure for device_interface_detail_data. + device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); + device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); + + // Get the detailed data for this device. The detail data gives us + // the device path for this device, which is then passed into + // CreateFile() to get a handle to the device. + res = SetupDiGetDeviceInterfaceDetailA(device_info_set, + &device_interface_data, + device_interface_detail_data, + required_size, + NULL, + NULL); + + if (!res) { + //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); + // Continue to the next device. + goto cont; + } + + // Make sure this device is of Setup Class "HIDClass" and has a + // driver bound to it. + for (i = 0; ; i++) { + char driver_name[256]; + + // Populate devinfo_data. This function will return failure + // when there are no more interfaces left. + res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); + if (!res) + goto cont; + + res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, + SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); + if (!res) + goto cont; + + if (strcmp(driver_name, "HIDClass") == 0) { + // See if there's a driver bound. + res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, + SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); + if (res) + break; + } + } + + //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); + + // Open a handle to the device + write_handle = open_device(device_interface_detail_data->DevicePath, TRUE); + + // Check validity of write_handle. + if (write_handle == INVALID_HANDLE_VALUE) { + // Unable to open the device. + //register_error(dev, "CreateFile"); + goto cont_close; + } + + + // Get the Vendor ID and Product ID for this device. + attrib.Size = sizeof(HIDD_ATTRIBUTES); + HidD_GetAttributes(write_handle, &attrib); + //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); + + // Check the VID/PID to see if we should add this + // device to the enumeration list. + if ((vendor_id == 0x0 && product_id == 0x0) || + (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) { + + #define WSTR_LEN 512 + const char *str; + struct hid_device_info *tmp; + PHIDP_PREPARSED_DATA pp_data = NULL; + HIDP_CAPS caps; + BOOLEAN res; + NTSTATUS nt_res; + wchar_t wstr[WSTR_LEN]; // TODO: Determine Size + size_t len; + + /* VID/PID match. Create the record. */ + tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); + if (cur_dev) { + cur_dev->next = tmp; + } + else { + root = tmp; + } + cur_dev = tmp; + + // Get the Usage Page and Usage for this device. + res = HidD_GetPreparsedData(write_handle, &pp_data); + if (res) { + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res == HIDP_STATUS_SUCCESS) { + cur_dev->usage_page = caps.UsagePage; + cur_dev->usage = caps.Usage; + } + + HidD_FreePreparsedData(pp_data); + } + + /* Fill out the record */ + cur_dev->next = NULL; + str = device_interface_detail_data->DevicePath; + if (str) { + len = strlen(str); + cur_dev->path = (char*) calloc(len+1, sizeof(char)); + strncpy(cur_dev->path, str, len+1); + cur_dev->path[len] = '\0'; + } + else + cur_dev->path = NULL; + + /* Serial Number */ + res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->serial_number = _wcsdup(wstr); + } + + /* Manufacturer String */ + res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->manufacturer_string = _wcsdup(wstr); + } + + /* Product String */ + res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); + wstr[WSTR_LEN-1] = 0x0000; + if (res) { + cur_dev->product_string = _wcsdup(wstr); + } + + /* VID/PID */ + cur_dev->vendor_id = attrib.VendorID; + cur_dev->product_id = attrib.ProductID; + + /* Release Number */ + cur_dev->release_number = attrib.VersionNumber; + + /* Interface Number. It can sometimes be parsed out of the path + on Windows if a device has multiple interfaces. See + http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or + search for "Hardware IDs for HID Devices" at MSDN. If it's not + in the path, it's set to -1. */ + cur_dev->interface_number = -1; + if (cur_dev->path) { + char *interface_component = strstr(cur_dev->path, "&mi_"); + if (interface_component) { + char *hex_str = interface_component + 4; + char *endptr = NULL; + cur_dev->interface_number = strtol(hex_str, &endptr, 16); + if (endptr == hex_str) { + /* The parsing failed. Set interface_number to -1. */ + cur_dev->interface_number = -1; + } + } + } + } + +cont_close: + CloseHandle(write_handle); +cont: + // We no longer need the detail data. It can be freed + free(device_interface_detail_data); + + device_index++; + + } + + // Close the device information handle. + SetupDiDestroyDeviceInfoList(device_info_set); + + return root; + +} + +void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) +{ + // TODO: Merge this with the Linux version. This function is platform-independent. + struct hid_device_info *d = devs; + while (d) { + struct hid_device_info *next = d->next; + free(d->path); + free(d->serial_number); + free(d->manufacturer_string); + free(d->product_string); + free(d); + d = next; + } +} + + +HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ + // TODO: Merge this functions with the Linux version. This function should be platform independent. + struct hid_device_info *devs, *cur_dev; + const char *path_to_open = NULL; + hid_device *handle = NULL; + + devs = hid_enumerate(vendor_id, product_id); + cur_dev = devs; + while (cur_dev) { + if (cur_dev->vendor_id == vendor_id && + cur_dev->product_id == product_id) { + if (serial_number) { + if (wcscmp(serial_number, cur_dev->serial_number) == 0) { + path_to_open = cur_dev->path; + break; + } + } + else { + path_to_open = cur_dev->path; + break; + } + } + cur_dev = cur_dev->next; + } + + if (path_to_open) { + /* Open the device */ + handle = hid_open_path(path_to_open); + } + + hid_free_enumeration(devs); + + return handle; +} + +HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) +{ + hid_device *dev; + HIDP_CAPS caps; + PHIDP_PREPARSED_DATA pp_data = NULL; + BOOLEAN res; + NTSTATUS nt_res; + + if (hid_init() < 0) { + return NULL; + } + + dev = new_hid_device(); + + // Open a handle to the device + dev->device_handle = open_device(path, FALSE); + + // Check validity of write_handle. + if (dev->device_handle == INVALID_HANDLE_VALUE) { + // Unable to open the device. + register_error(dev, "CreateFile"); + goto err; + } + + // Get the Input Report length for the device. + res = HidD_GetPreparsedData(dev->device_handle, &pp_data); + if (!res) { + register_error(dev, "HidD_GetPreparsedData"); + goto err; + } + nt_res = HidP_GetCaps(pp_data, &caps); + if (nt_res != HIDP_STATUS_SUCCESS) { + register_error(dev, "HidP_GetCaps"); + goto err_pp_data; + } + dev->output_report_length = caps.OutputReportByteLength; + dev->input_report_length = caps.InputReportByteLength; + HidD_FreePreparsedData(pp_data); + + dev->read_buf = (char*) malloc(dev->input_report_length); + + return dev; + +err_pp_data: + HidD_FreePreparsedData(pp_data); +err: + CloseHandle(dev->device_handle); + free(dev); + return NULL; +} + +int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) +{ + DWORD bytes_written; + BOOL res; + + OVERLAPPED ol; + unsigned char *buf; + memset(&ol, 0, sizeof(ol)); + + /* Make sure the right number of bytes are passed to WriteFile. Windows + expects the number of bytes which are in the _longest_ report (plus + one for the report number) bytes even if the data is a report + which is shorter than that. Windows gives us this value in + caps.OutputReportByteLength. If a user passes in fewer bytes than this, + create a temporary buffer which is the proper size. */ + if (length >= dev->output_report_length) { + /* The user passed the right number of bytes. Use the buffer as-is. */ + buf = (unsigned char *) data; + } else { + /* Create a temporary buffer and copy the user's data + into it, padding the rest with zeros. */ + buf = (unsigned char *) malloc(dev->output_report_length); + memcpy(buf, data, length); + memset(buf + length, 0, dev->output_report_length - length); + length = dev->output_report_length; + } + + res = WriteFile(dev->device_handle, buf, length, NULL, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // WriteFile() failed. Return error. + register_error(dev, "WriteFile"); + bytes_written = -1; + goto end_of_function; + } + } + + // Wait here until the write is done. This makes + // hid_write() synchronous. + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); + if (!res) { + // The Write operation failed. + register_error(dev, "WriteFile"); + bytes_written = -1; + goto end_of_function; + } + +end_of_function: + if (buf != data) + free(buf); + + return bytes_written; +} + + +int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +{ + DWORD bytes_read = 0; + BOOL res; + + // Copy the handle for convenience. + HANDLE ev = dev->ol.hEvent; + + if (!dev->read_pending) { + // Start an Overlapped I/O read. + dev->read_pending = TRUE; + memset(dev->read_buf, 0, dev->input_report_length); + ResetEvent(ev); + res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // ReadFile() has failed. + // Clean up and return error. + CancelIo(dev->device_handle); + dev->read_pending = FALSE; + goto end_of_function; + } + } + } + + if (milliseconds >= 0) { + // See if there is any data yet. + res = WaitForSingleObject(ev, milliseconds); + if (res != WAIT_OBJECT_0) { + // There was no data this time. Return zero bytes available, + // but leave the Overlapped I/O running. + return 0; + } + } + + // Either WaitForSingleObject() told us that ReadFile has completed, or + // we are in non-blocking mode. Get the number of bytes read. The actual + // data has been copied to the data[] array which was passed to ReadFile(). + res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); + + // Set pending back to false, even if GetOverlappedResult() returned error. + dev->read_pending = FALSE; + + if (res && bytes_read > 0) { + if (dev->read_buf[0] == 0x0) { + /* If report numbers aren't being used, but Windows sticks a report + number (0x0) on the beginning of the report anyway. To make this + work like the other platforms, and to make it work more like the + HID spec, we'll skip over this byte. */ + size_t copy_len; + bytes_read--; + copy_len = length > bytes_read ? bytes_read : length; + memcpy(data, dev->read_buf+1, copy_len); + } + else { + /* Copy the whole buffer, report number and all. */ + size_t copy_len = length > bytes_read ? bytes_read : length; + memcpy(data, dev->read_buf, copy_len); + } + } + +end_of_function: + if (!res) { + register_error(dev, "GetOverlappedResult"); + return -1; + } + + return bytes_read; +} + +int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) +{ + return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +} + +int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) +{ + dev->blocking = !nonblock; + return 0; /* Success */ +} + +int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +{ + BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); + if (!res) { + register_error(dev, "HidD_SetFeature"); + return -1; + } + + return length; +} + + +int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +{ + BOOL res; +#if 0 + res = HidD_GetFeature(dev->device_handle, data, length); + if (!res) { + register_error(dev, "HidD_GetFeature"); + return -1; + } + return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ +#else + DWORD bytes_returned; + + OVERLAPPED ol; + memset(&ol, 0, sizeof(ol)); + + res = DeviceIoControl(dev->device_handle, + IOCTL_HID_GET_FEATURE, + data, length, + data, length, + &bytes_returned, &ol); + + if (!res) { + if (GetLastError() != ERROR_IO_PENDING) { + // DeviceIoControl() failed. Return error. + register_error(dev, "Send Feature Report DeviceIoControl"); + return -1; + } + } + + // Wait here until the write is done. This makes + // hid_get_feature_report() synchronous. + res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); + if (!res) { + // The operation failed. + register_error(dev, "Send Feature Report GetOverLappedResult"); + return -1; + } + return bytes_returned; +#endif +} + +void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) +{ + if (!dev) + return; + CancelIo(dev->device_handle); + CloseHandle(dev->ol.hEvent); + CloseHandle(dev->device_handle); + LocalFree(dev->last_error_str); + free(dev->read_buf); + free(dev); +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetManufacturerString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetProductString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetSerialNumberString"); + return -1; + } + + return 0; +} + +int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +{ + BOOL res; + + res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen); + if (!res) { + register_error(dev, "HidD_GetIndexedString"); + return -1; + } + + return 0; +} + + +HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +{ + return (wchar_t*)dev->last_error_str; +} + + +//#define PICPGM +//#define S11 +#define P32 +#ifdef S11 + unsigned short VendorID = 0xa0a0; + unsigned short ProductID = 0x0001; +#endif + +#ifdef P32 + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x3f; +#endif + + +#ifdef PICPGM + unsigned short VendorID = 0x04d8; + unsigned short ProductID = 0x0033; +#endif + + +#if 0 +int __cdecl main(int argc, char* argv[]) +{ + int res; + unsigned char buf[65]; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + // Set up the command buffer. + memset(buf,0x00,sizeof(buf)); + buf[0] = 0; + buf[1] = 0x81; + + + // Open the device. + int handle = open(VendorID, ProductID, L"12345"); + if (handle < 0) + printf("unable to open device\n"); + + + // Toggle LED (cmd 0x80) + buf[1] = 0x80; + res = write(handle, buf, 65); + if (res < 0) + printf("Unable to write()\n"); + + // Request state (cmd 0x81) + buf[1] = 0x81; + write(handle, buf, 65); + if (res < 0) + printf("Unable to write() (2)\n"); + + // Read requested state + read(handle, buf, 65); + if (res < 0) + printf("Unable to read()\n"); + + // Print out the returned buffer. + for (int i = 0; i < 4; i++) + printf("buf[%d]: %d\n", i, buf[i]); + + return 0; +} +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff -Nru libindi-1.0.0/libs/indibase/indibase.h libindi-1.1.0/libs/indibase/indibase.h --- libindi-1.0.0/libs/indibase/indibase.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indibase.h 2015-09-06 13:17:35.000000000 +0000 @@ -1,8 +1,11 @@ #ifndef INDIBASE_H #define INDIBASE_H +#include + #include "indiapi.h" #include "indidevapi.h" +#include "indibasetypes.h" #define MAXRBUF 2048 @@ -25,6 +28,9 @@
  • Telescope: Base class for telescope drivers.
  • FilterWheel: Base class for Filter Wheels. It implements the FilterInterface.
  • Focuser: Base class for focusers.
  • +
  • Dome: Base class for domes.
  • +
  • GPS: Base class for GPS devices.
  • +
  • Weather: Base class for Weather devices.
  • USBDevice: Base class for USB devices for direct read/write/control over USB.
  • Controller: Class to handle controller inputs like joysticks and gamepads.
  • Logger: Class to handle debugging and logging of drivers.
  • @@ -47,24 +53,14 @@ class FilterWheel; class Focuser; class Dome; + class GPS; + class Weather; class USBDevice; class Property; class Controller; class Logger; } -/*! INDI property type */ -typedef enum -{ - INDI_NUMBER, /*!< INumberVectorProperty. */ - INDI_SWITCH, /*!< ISwitchVectorProperty. */ - INDI_TEXT, /*!< ITextVectorProperty. */ - INDI_LIGHT, /*!< ILightVectorProperty. */ - INDI_BLOB, /*!< IBLOBVectorProperty. */ - INDI_UNKNOWN -} INDI_TYPE; - - /** * \class INDI::BaseMediator \brief Meditates event notification as generated by driver and passed to clients. @@ -78,6 +74,12 @@ */ virtual void newDevice(INDI::BaseDevice *dp) =0; + /** \brief Emmited when a device is deleted from INDI server. + \param dp Pointer to the base device instance. + + */ + virtual void removeDevice(INDI::BaseDevice *dp) =0; + /** \brief Emmited when a new property is created for an INDI driver. \param property Pointer to the Property Container diff -Nru libindi-1.0.0/libs/indibase/indibasetypes.h libindi-1.1.0/libs/indibase/indibasetypes.h --- libindi-1.0.0/libs/indibase/indibasetypes.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indibasetypes.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,61 @@ +/******************************************************************************* + Copyright(c) 2011 Jasem Mutlaq. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*******************************************************************************/ + +#ifndef INDIBASETYPES_H +#define INDIBASETYPES_H + +/*! INDI property type */ +typedef enum +{ + INDI_NUMBER, /*!< INumberVectorProperty. */ + INDI_SWITCH, /*!< ISwitchVectorProperty. */ + INDI_TEXT, /*!< ITextVectorProperty. */ + INDI_LIGHT, /*!< ILightVectorProperty. */ + INDI_BLOB, /*!< IBLOBVectorProperty. */ + INDI_UNKNOWN +} INDI_PROPERTY_TYPE; + +/*! INDI Equatorial Axis type */ +typedef enum +{ + AXIS_RA, /*!< Right Ascension Axis. */ + AXIS_DE /*!< Declination Axis. */ +} INDI_EQ_AXIS; + +/*! INDI Horizontal Axis type */ +typedef enum +{ + AXIS_AZ, /*!< Azimuth Axis. */ + AXIS_ALT /*!< Altitude Axis. */ +} INDI_HO_AXIS; + +/*! North/South Direction */ +typedef enum +{ + DIRECTION_NORTH, + DIRECTION_SOUTH +} INDI_DIR_NS; + +/*! West/East Direction */ +typedef enum +{ + DIRECTION_WEST, + DIRECTION_EAST +} INDI_DIR_WE; + +#endif // INDIBASETYPES_H diff -Nru libindi-1.0.0/libs/indibase/indiccd.cpp libindi-1.1.0/libs/indibase/indiccd.cpp --- libindi-1.0.0/libs/indibase/indiccd.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiccd.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -31,6 +31,7 @@ #include #include +#include #include const char *IMAGE_SETTINGS_TAB = "Image Settings"; @@ -38,6 +39,7 @@ const char *GUIDE_HEAD_TAB = "Guider Head"; const char *GUIDE_CONTROL_TAB = "Guider Control"; const char *RAPIDGUIDE_TAB = "Rapid Guide"; +const char *WCS_TAB = "WCS"; CCDChip::CCDChip() { @@ -235,7 +237,7 @@ void CCDChip::setImageExtension(const char *ext) { - strncpy(imageExtention, ext, MAXINDINAME); + strncpy(imageExtention, ext, MAXINDIBLOBFMT); } INDI::CCD::CCD() @@ -254,6 +256,7 @@ InGuideExposure=false; RapidGuideEnabled=false; GuiderRapidGuideEnabled=false; + ValidCCDRotation=false; AutoLoop=false; SendImage=false; @@ -268,6 +271,7 @@ RA=-1000; Dec=-1000; + Aperture=FocalLength=-1; } INDI::CCD::~CCD() @@ -407,7 +411,7 @@ IUFillNumber(&GuideCCD.RapidGuideDataN[2],"GUIDESTAR_FIT","Guide star fit","%5.2f",0,1024,0,0); IUFillNumberVector(&GuideCCD.RapidGuideDataNP,GuideCCD.RapidGuideDataN,3,getDeviceName(),"GUIDER_RAPID_GUIDE_DATA","Rapid Guide Data",RAPIDGUIDE_TAB,IP_RO,60,IPS_IDLE); - // CCD Class Init + // CCD Class Init IUFillText(&BayerT[0],"CFA_OFFSET_X","X Offset","0"); IUFillText(&BayerT[1],"CFA_OFFSET_Y","Y Offset","0"); @@ -420,7 +424,7 @@ IUFillSwitchVector(&UploadSP, UploadS, 3, getDeviceName(), "UPLOAD_MODE", "Upload", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillText(&UploadSettingsT[0],"UPLOAD_DIR","Dir",""); - IUFillText(&UploadSettingsT[1],"UPLOAD_PREFIX","Prefix","IMAGE_XX"); + IUFillText(&UploadSettingsT[1],"UPLOAD_PREFIX","Prefix","IMAGE_XXX"); IUFillTextVector(&UploadSettingsTP,UploadSettingsT,2,getDeviceName(),"UPLOAD_SETTINGS","Upload Settings",OPTIONS_TAB,IP_RW,60,IPS_IDLE); IUFillText(&ActiveDeviceT[0],"ACTIVE_TELESCOPE","Telescope","Telescope Simulator"); @@ -428,11 +432,23 @@ IUFillText(&ActiveDeviceT[2],"ACTIVE_FILTER","Filter","CCD Simulator"); IUFillTextVector(&ActiveDeviceTP,ActiveDeviceT,3,getDeviceName(),"ACTIVE_DEVICES","Snoop devices",OPTIONS_TAB,IP_RW,60,IPS_IDLE); + IUFillSwitch(&WorldCoordS[0], "WCS_ENABLE", "Enable", ISS_OFF); + IUFillSwitch(&WorldCoordS[1], "WCS_DISABLE", "Disable", ISS_ON); + IUFillSwitchVector(&WorldCoordSP, WorldCoordS, 2, getDeviceName(), "WCS_CONTROL", "WCS", WCS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + IUFillSwitch(&TelescopeTypeS[0], "TELESCOPE_PRIMARY", "Primary", ISS_ON); + IUFillSwitch(&TelescopeTypeS[1], "TELESCOPE_GUIDE", "Guide", ISS_OFF); + IUFillSwitchVector(&TelescopeTypeSP, TelescopeTypeS, 2, getDeviceName(), "TELESCOPE_TYPE", "Telescope", WCS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + + IUFillNumber(&CCDRotationN[0],"CCD_ROTATION_VALUE","Rotation","%g",-360,360,1,0); + IUFillNumberVector(&CCDRotationNP,CCDRotationN,1,getDeviceName(),"CCD_ROTATION","CCD FOV", WCS_TAB,IP_RW,60,IPS_IDLE); + IUFillNumber(&EqN[0],"RA","Ra (hh:mm:ss)","%010.6m",0,24,0,0); IUFillNumber(&EqN[1],"DEC","Dec (dd:mm:ss)","%010.6m",-90,90,0,0); IUFillNumberVector(&EqNP,EqN,2,ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD","EQ Coord","Main Control",IP_RW,60,IPS_IDLE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD"); + IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_SLOT"); IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_NAME"); @@ -530,6 +546,7 @@ defineNumber(&GuideCCD.RapidGuideDataNP); } defineText(&ActiveDeviceTP); + defineSwitch(&WorldCoordSP); defineSwitch(&UploadSP); if (UploadSettingsT[0].text == NULL) @@ -588,6 +605,12 @@ if (capability.hasBayer) deleteProperty(BayerTP.name); deleteProperty(ActiveDeviceTP.name); + if (WorldCoordS[0].s == ISS_ON) + { + deleteProperty(TelescopeTypeSP.name); + deleteProperty(CCDRotationNP.name); + } + deleteProperty(WorldCoordSP.name); deleteProperty(UploadSP.name); deleteProperty(UploadSettingsTP.name); } @@ -611,6 +634,34 @@ Dec=newdec; } } + else if (!strcmp(propName, "TELESCOPE_INFO")) + { + for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) + { + const char *name = findXMLAttValu(ep, "name"); + + if (!strcmp(name, "TELESCOPE_APERTURE")) + { + if (TelescopeTypeS[0].s == ISS_ON) + Aperture = atof(pcdataXMLEle(ep)); + } + else if (!strcmp(name, "TELESCOPE_FOCAL_LENGTH")) + { + if (TelescopeTypeS[0].s == ISS_ON) + FocalLength = atof(pcdataXMLEle(ep)); + } + else if (!strcmp(name, "GUIDER_APERTURE")) + { + if (TelescopeTypeS[1].s == ISS_ON) + Aperture = atof(pcdataXMLEle(ep)); + } + else if (!strcmp(name, "GUIDER_FOCAL_LENGTH")) + { + if (TelescopeTypeS[1].s == ISS_ON) + FocalLength = atof(pcdataXMLEle(ep)); + } + } + } else if (!strcmp(propName, "FILTER_NAME")) { FilterNames.clear(); @@ -647,6 +698,7 @@ // Update the property name! strncpy(EqNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD"); + IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_SLOT"); IDSnoopDevice(ActiveDeviceT[2].text,"FILTER_NAME"); @@ -687,6 +739,14 @@ // Now lets see if it's something we process here if(strcmp(name,"CCD_EXPOSURE")==0) { + if (values[0] < PrimaryCCD.ImageExposureN[0].min || values[0] > PrimaryCCD.ImageExposureN[0].max) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Requested exposure value (%g) seconds out of bounds [%g,%g].", values[0], PrimaryCCD.ImageExposureN[0].min, PrimaryCCD.ImageExposureN[0].max); + PrimaryCCD.ImageExposureNP.s=IPS_ALERT; + IDSetNumber(&PrimaryCCD.ImageExposureNP,NULL); + return false; + } + PrimaryCCD.ImageExposureN[0].value = ExposureTime = values[0]; if (PrimaryCCD.ImageExposureNP.s==IPS_BUSY) @@ -702,6 +762,14 @@ if(strcmp(name,"GUIDER_EXPOSURE")==0) { + if (values[0] < GuideCCD.ImageExposureN[0].min || values[0] > GuideCCD.ImageExposureN[0].max) + { + DEBUGF(INDI::Logger::DBG_ERROR, "Requested guide exposure value (%g) seconds out of bounds [%g,%g].", values[0], GuideCCD.ImageExposureN[0].min, GuideCCD.ImageExposureN[0].max); + GuideCCD.ImageExposureNP.s=IPS_ALERT; + IDSetNumber(&GuideCCD.ImageExposureNP,NULL); + return false; + } + GuideCCD.ImageExposureN[0].value = GuiderExposureTime = values[0]; GuideCCD.ImageExposureNP.s=IPS_BUSY; if (StartGuideExposure(GuiderExposureTime)) @@ -896,7 +964,18 @@ return true; } + // CCD Rotation + if (!strcmp(name, CCDRotationNP.name)) + { + IUUpdateNumber(&CCDRotationNP, values, names, n); + CCDRotationNP.s = IPS_OK; + IDSetNumber(&CCDRotationNP, NULL); + ValidCCDRotation=true; + DEBUGF(INDI::Logger::DBG_SESSION, "CCD FOV rotation updated to %g degrees.", CCDRotationN[0].value); + + return true; + } } // if we didn't process it, continue up the chain, let somebody else // give it a shot @@ -923,6 +1002,35 @@ return true; } + if (!strcmp(name, TelescopeTypeSP.name)) + { + IUUpdateSwitch(&TelescopeTypeSP, states, names, n); + TelescopeTypeSP.s = IPS_OK; + IDSetSwitch(&TelescopeTypeSP, NULL); + return true; + } + + if (!strcmp(name, WorldCoordSP.name)) + { + IUUpdateSwitch(&WorldCoordSP, states, names, n); + WorldCoordSP.s = IPS_OK; + + if (WorldCoordS[0].s == ISS_ON) + { + DEBUG(INDI::Logger::DBG_WARNING, "World Coordinate System is enabled. CCD rotation must be set either manually or by solving the image before proceeding to capture any frames, otherwise the WCS information may be invalid."); + defineSwitch(&TelescopeTypeSP); + defineNumber(&CCDRotationNP); + } + else + { + deleteProperty(TelescopeTypeSP.name); + deleteProperty(CCDRotationNP.name); + } + + ValidCCDRotation=false; + IDSetSwitch(&WorldCoordSP, NULL); + } + // Reset if(strcmp(name,PrimaryCCD.ResetSP.name)==0) { @@ -1227,6 +1335,8 @@ double pixSize1,pixSize2; unsigned int xbin, ybin; + setlocale(LC_NUMERIC,"C"); + if (targetChip->getNAxis() == 2) getMinMax(&min_val, &max_val, targetChip); @@ -1297,14 +1407,91 @@ fits_update_key_s(fptr, TSTRING, "BAYERPAT", BayerT[2].text, "Bayer color pattern", &status); } - if (RA != -1000 && Dec != -1000) + if (targetChip->getFrameType() == CCDChip::LIGHT_FRAME && RA != -1000 && Dec != -1000) { - fits_update_key_s(fptr, TDOUBLE, "OBJCTRA", &RA, "Object RA", &status); - fits_update_key_s(fptr, TDOUBLE, "OBJCTDEC", &Dec, "Object DEC", &status); + ln_equ_posn epochPos, J2000Pos; + epochPos.ra = RA*15.0; + epochPos.dec = Dec; + + // Convert from JNow to J2000 + //TODO use exp_start instead of julian from system + ln_get_equ_prec2(&epochPos, ln_get_julian_from_sys(), JD2000, &J2000Pos); + + double raJ2000 = J2000Pos.ra/15.0; + double decJ2000 = J2000Pos.dec; + + fits_update_key_s(fptr, TDOUBLE, "OBJCTRA", &raJ2000, "Object RA", &status); + fits_update_key_s(fptr, TDOUBLE, "OBJCTDEC", &decJ2000, "Object DEC", &status); + + int epoch = 2000; + + fits_update_key_s(fptr, TINT, "EPOCH", &epoch, "Epoch", &status); + fits_update_key_s(fptr, TINT, "EQUINOX", &epoch, "Equinox", &status); + + + // Add WCS Info + if (WorldCoordS[0].s == ISS_ON && ValidCCDRotation && FocalLength != -1) + { + raJ2000 *= 15; + fits_update_key_s(fptr, TDOUBLE, "CRVAL1", &raJ2000, "CRVAL1", &status); + fits_update_key_s(fptr, TDOUBLE, "CRVAL2", &decJ2000, "CRVAL1", &status); + + char radecsys[8] = "FK5"; + char ctype1[16] = "RA---TAN"; + char ctype2[16] = "DEC--TAN"; + + fits_update_key_s(fptr, TSTRING, "RADECSYS", radecsys, "RADECSYS", &status); + fits_update_key_s(fptr, TSTRING, "CTYPE1", ctype1, "CTYPE1", &status); + fits_update_key_s(fptr, TSTRING, "CTYPE2", ctype2, "CTYPE2", &status); + + double crpix1 = targetChip->getSubW()/targetChip->getBinX()/2.0; + double crpix2 = targetChip->getSubH()/targetChip->getBinY()/2.0; + + fits_update_key_s(fptr, TDOUBLE, "CRPIX1", &crpix1, "CRPIX1", &status); + fits_update_key_s(fptr, TDOUBLE, "CRPIX2", &crpix2, "CRPIX2", &status); + + double secpix1 = pixSize1 / FocalLength * 206.3 * targetChip->getBinX(); + double secpix2 = pixSize2 / FocalLength * 206.3 * targetChip->getBinY(); + + //double secpix1 = pixSize1 / FocalLength * 206.3; + //double secpix2 = pixSize2 / FocalLength * 206.3; + + fits_update_key_s(fptr, TDOUBLE, "SECPIX1", &secpix1, "SECPIX1", &status); + fits_update_key_s(fptr, TDOUBLE, "SECPIX2", &secpix2, "SECPIX2", &status); + + double degpix1 = secpix1 / 3600.0; + double degpix2 = secpix2 / 3600.0; + + fits_update_key_s(fptr, TDOUBLE, "CDELT1", °pix1, "CDELT1", &status); + fits_update_key_s(fptr, TDOUBLE, "CDELT2", °pix2, "CDELT2", &status); + + // Rotation is CW, we need to convert it to CCW per CROTA1 definition + double rotation = 360 - CCDRotationN[0].value; + if (rotation > 360) + rotation -= 360; + + fits_update_key_s(fptr, TDOUBLE, "CROTA1", &rotation, "CROTA1", &status); + fits_update_key_s(fptr, TDOUBLE, "CROTA2", &rotation, "CROTA2", &status); + + /*double cd[4]; + cd[0] = degpix1; + cd[1] = 0; + cd[2] = 0; + cd[3] = degpix2; + + fits_update_key_s(fptr, TDOUBLE, "CD1_1", &cd[0], "CD1_1", &status); + fits_update_key_s(fptr, TDOUBLE, "CD1_2", &cd[1], "CD1_2", &status); + fits_update_key_s(fptr, TDOUBLE, "CD2_1", &cd[2], "CD2_1", &status); + fits_update_key_s(fptr, TDOUBLE, "CD2_2", &cd[3], "CD2_2", &status);*/ + + } + } - fits_update_key_s(fptr, TSTRING, "INSTRUME", dev_name, "CCD Name", &status); fits_update_key_s(fptr, TSTRING, "DATE-OBS", exp_start, "UTC start date of observation", &status); + fits_write_comment(fptr, "Generated by INDI", &status); + + setlocale(LC_NUMERIC,""); } @@ -1650,10 +1837,10 @@ if (maxIndex > 0) { - char indexString[3]; - snprintf(indexString, 3, "%02d", maxIndex); + char indexString[4]; + snprintf(indexString, 4, "%03d", maxIndex); std::string prefixIndex = indexString; - prefix.replace(prefix.find("XX"), 2, prefixIndex); + prefix.replace(prefix.find("XXX"), 3, prefixIndex); } snprintf(imageFileName, MAXRBUF, "%s/%s%s", UploadSettingsT[0].text, prefix.c_str(), targetChip->FitsB.format); @@ -1742,6 +1929,11 @@ IUSaveConfigText(fp, &ActiveDeviceTP); IUSaveConfigSwitch(fp, &UploadSP); IUSaveConfigText(fp, &UploadSettingsTP); + //IUSaveConfigSwitch(fp, &WorldCoordSP); + IUSaveConfigSwitch(fp, &TelescopeTypeSP); + + //if (ValidCCDRotation) + // IUSaveConfigNumber(fp, &CCDRotationNP); IUSaveConfigSwitch(fp, &PrimaryCCD.CompressSP); @@ -1760,24 +1952,32 @@ return true; } -bool INDI::CCD::GuideNorth(float ms) +IPState INDI::CCD::GuideNorth(float ms) { - return false; + INDI_UNUSED(ms); + DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding."); + return IPS_ALERT; } -bool INDI::CCD::GuideSouth(float ms) +IPState INDI::CCD::GuideSouth(float ms) { - return false; + INDI_UNUSED(ms); + DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding."); + return IPS_ALERT; } -bool INDI::CCD::GuideEast(float ms) +IPState INDI::CCD::GuideEast(float ms) { - return false; + INDI_UNUSED(ms); + DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding."); + return IPS_ALERT; } -bool INDI::CCD::GuideWest(float ms) +IPState INDI::CCD::GuideWest(float ms) { - return false; + INDI_UNUSED(ms); + DEBUG(INDI::Logger::DBG_ERROR, "The CCD does not support guiding."); + return IPS_ALERT; } void INDI::CCD::getMinMax(double *min, double *max, CCDChip *targetChip) @@ -1851,11 +2051,11 @@ std::vector files = std::vector(); std::string prefixIndex = prefix; - if (prefixIndex.find("XX") == std::string::npos) + if (prefixIndex.find("XXX") == std::string::npos) return 0; std::string prefixSearch = prefix; - prefixSearch.replace(prefixSearch.find("XX"), 2, ""); + prefixSearch.replace(prefixSearch.find("XXX"), 3, ""); dpdf = opendir(dir); if (dpdf != NULL) @@ -1872,7 +2072,7 @@ int maxIndex=0; std::string filterIndex = "%d"; - prefixIndex.replace(prefixIndex.find("XX"), 2, filterIndex); + prefixIndex.replace(prefixIndex.find("XXX"), 3, filterIndex); char filter[MAXRBUF]; snprintf(filter, MAXRBUF, "%s%s", prefixIndex.c_str(), ext); for (int i=0; i < files.size(); i++) @@ -1887,4 +2087,7 @@ } - +void INDI::CCD::GuideComplete(INDI_EQ_AXIS axis) +{ + INDI::GuiderInterface::GuideComplete(axis); +} diff -Nru libindi-1.0.0/libs/indibase/indiccd.h libindi-1.1.0/libs/indibase/indiccd.h --- libindi-1.0.0/libs/indibase/indiccd.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiccd.h 2015-09-06 13:17:35.000000000 +0000 @@ -359,7 +359,7 @@ ISwitchVectorProperty RapidGuideSP; ISwitch RapidGuideSetupS[3]; - ISwitchVectorProperty RapidGuideSetupSP; + ISwitchVectorProperty RapidGuideSetupSP; INumber RapidGuideDataN[3]; INumberVectorProperty RapidGuideDataNP; @@ -593,28 +593,28 @@ \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return True if successful, false otherwise. */ - virtual bool GuideNorth(float ms); + virtual IPState GuideNorth(float ms); /** \brief Guide southward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ - virtual bool GuideSouth(float ms); + virtual IPState GuideSouth(float ms); /** \brief Guide easward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ - virtual bool GuideEast(float ms); + virtual IPState GuideEast(float ms); /** \brief Guide westward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ - virtual bool GuideWest(float ms); + virtual IPState GuideWest(float ms); /** \brief Add FITS keywords to a fits file \param fptr pointer to a valid FITS file. @@ -637,18 +637,20 @@ */ virtual void addFITSKeywords(fitsfile *fptr, CCDChip *targetChip); - /* A function to just remove GCC warnings about deprecated conversion */ + /** A function to just remove GCC warnings about deprecated conversion */ void fits_update_key_s(fitsfile* fptr, int type, std::string name, void* p, std::string explanation, int* status); /** * @brief activeDevicesUpdated Inform children that ActiveDevices property was updated so they can snoop on the updated devices if desired. */ - virtual void activeDevicesUpdated() {} + virtual void activeDevicesUpdated() {} virtual bool saveConfigItems(FILE *fp); + void GuideComplete(INDI_EQ_AXIS axis); double RA, Dec; + double FocalLength, Aperture; bool InExposure; bool InGuideExposure; bool RapidGuideEnabled; @@ -677,6 +679,15 @@ ITextVectorProperty ActiveDeviceTP; IText ActiveDeviceT[3]; + ISwitch WorldCoordS[2]; + ISwitchVectorProperty WorldCoordSP; + + INumber CCDRotationN[1]; + INumberVectorProperty CCDRotationNP; + + ISwitch TelescopeTypeS[2]; + ISwitchVectorProperty TelescopeTypeSP; + INumber TemperatureN[1]; INumberVectorProperty TemperatureNP; @@ -692,6 +703,8 @@ private: CCDCapability capability; + bool ValidCCDRotation; + bool uploadFile(CCDChip * targetChip, const void *fitsData, size_t totalBytes, bool sendImage, bool saveImage); void getMinMax(double *min, double *max, CCDChip *targetChip); int getFileIndex(const char *dir, const char *prefix, const char *ext); diff -Nru libindi-1.0.0/libs/indibase/indicontroller.cpp libindi-1.1.0/libs/indibase/indicontroller.cpp --- libindi-1.0.0/libs/indibase/indicontroller.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indicontroller.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -39,6 +39,8 @@ { for (int i=0; i < JoystickSettingTP.ntp; i++) free(JoystickSettingT[i].aux0); + + free(JoystickSettingT); } void Controller::mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue) @@ -78,6 +80,7 @@ IUFillTextVector(&JoystickSettingTP, JoystickSettingT, JoystickSettingTP.ntp, device->getDeviceName(), "JOYSTICKSETTINGS", "Settings", "Joystick", IP_RW, 0, IPS_IDLE); + return true; } void Controller::ISGetProperties(const char *dev) @@ -245,6 +248,7 @@ joystickCallbackFunc(setting, mag, angle, device); } + return true; } diff -Nru libindi-1.0.0/libs/indibase/indidome.cpp libindi-1.1.0/libs/indibase/indidome.cpp --- libindi-1.0.0/libs/indibase/indidome.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indidome.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -51,7 +51,7 @@ /* Port */ IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyUSB0"); - IUFillTextVector(&PortTP, PortT, 1, getDeviceName(), "DEVICE_PORT", "Ports", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); + IUFillTextVector(&PortTP, PortT, 1, getDeviceName(), "DEVICE_PORT", "Ports", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); // Presets IUFillNumber(&PresetN[0], "Preset 1", "", "%6.2f", 0, 360.0, 1.0, 0); @@ -112,6 +112,8 @@ { if(isConnected()) { + last_dome_motion = -1; + defineText(&ActiveDeviceTP); if (capability.hasShutter) @@ -120,10 +122,10 @@ // Now we add our Dome specific stuff defineSwitch(&DomeMotionSP); - if (capability.variableSpeed) + if (capability.hasVariableSpeed) { defineNumber(&DomeSpeedNP); - defineNumber(&DomeTimerNP); + //defineNumber(&DomeTimerNP); } if (capability.canRelMove) defineNumber(&DomeRelPosNP); @@ -140,6 +142,16 @@ defineSwitch(&DomeAutoSyncSP); } + if (capability.canPark) + { + defineSwitch(&ParkSP); + if (parkDataType != PARK_NONE) + { + defineNumber(&ParkPositionNP); + defineSwitch(&ParkOptionSP); + } + } + defineNumber(&DomeMeasurementsNP); } else { @@ -149,10 +161,10 @@ deleteProperty(DomeShutterSP.name); deleteProperty(DomeMotionSP.name); - if (capability.variableSpeed) + if (capability.hasVariableSpeed) { deleteProperty(DomeSpeedNP.name); - deleteProperty(DomeTimerNP.name); + //deleteProperty(DomeTimerNP.name); } if (capability.canRelMove) deleteProperty(DomeRelPosNP.name); @@ -169,6 +181,16 @@ deleteProperty(DomeAutoSyncSP.name); } + if (capability.canPark) + { + deleteProperty(ParkSP.name); + if (parkDataType != PARK_NONE) + { + deleteProperty(ParkPositionNP.name); + deleteProperty(ParkOptionSP.name); + } + } + deleteProperty(DomeMeasurementsNP.name); } @@ -214,16 +236,24 @@ { if (!strcmp(PresetGotoSP.name, name)) { + if (domeState == DOME_PARKED) + { + DEBUGDEVICE(getDeviceName(), INDI::Logger::DBG_ERROR, "Dome is parked. Please unpark before issuing any motion commands."); + PresetGotoSP.s = IPS_ALERT; + IDSetSwitch(&PresetGotoSP, NULL); + return false; + } + IUUpdateSwitch(&PresetGotoSP, states, names, n); int index = IUFindOnSwitchIndex(&PresetGotoSP); - int rc = MoveAbsDome(PresetN[index].value); - if (rc >= 0) + IPState rc = MoveAbs(PresetN[index].value); + if (rc == IPS_OK || rc == IPS_BUSY) { PresetGotoSP.s = IPS_OK; DEBUGF(INDI::Logger::DBG_SESSION, "Moving to Preset %d (%g degrees).", index+1, PresetN[index].value); IDSetSwitch(&PresetGotoSP, NULL); - if (rc == 1) + if (rc == IPS_BUSY) { DomeAbsPosNP.s = IPS_BUSY; IDSetNumber(&DomeAbsPosNP, NULL); @@ -249,8 +279,8 @@ else { IDSetSwitch(&DomeAutoSyncSP, "Dome is no longer synced to mount azimuth position."); - if (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY || DomeTimerNP.s == IPS_BUSY) - AbortDome(); + if (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY/* || DomeTimerNP.s == IPS_BUSY*/) + Abort(); } return true; @@ -390,65 +420,104 @@ if (state == ISS_OFF) return; - int rc=0; // Dome In if (!strcmp(button_n, "Dome CW")) { - if (capability.variableSpeed) - { - rc = MoveDome(DOME_CW, DomeSpeedN[0].value, DomeTimerN[0].value); - if (rc == 0) - DomeTimerNP.s = IPS_OK; - else if (rc == 1) - DomeTimerNP.s = IPS_BUSY; - else - DomeTimerNP.s = IPS_ALERT; - - IDSetNumber(&DomeTimerNP,NULL); - } - else if (capability.canRelMove) + if (capability.canRelMove) { - rc=MoveRelDome(DOME_CW, DomeRelPosN[0].value); - if (rc == 0) + IPState rc= MoveRel(DomeRelPosN[0].value); + if (rc == IPS_OK) { DomeRelPosNP.s=IPS_OK; IDSetNumber(&DomeRelPosNP, "Dome moved %g degrees CW", DomeRelPosN[0].value); IDSetNumber(&DomeAbsPosNP, NULL); } - else if (rc == 1) + else if (rc == IPS_BUSY) { DomeRelPosNP.s=IPS_BUSY; IDSetNumber(&DomeAbsPosNP, "Dome is moving %g degrees CW...", DomeRelPosN[0].value); } } - } - else if (!strcmp(button_n, "Dome CCW")) - { - if (capability.variableSpeed) + else { - rc = MoveDome(DOME_CCW, DomeSpeedN[0].value, DomeTimerN[0].value); - if (rc == 0) - DomeTimerNP.s = IPS_OK; - else if (rc == 1) - DomeTimerNP.s = IPS_BUSY; + if (DomeMotionSP.s == IPS_BUSY) + { + if (Move( DOME_CW, MOTION_STOP)) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_IDLE; + IDSetSwitch(&DomeMotionSP, NULL); + } + else + { + DomeMotionSP.s = IPS_ALERT; + IDSetSwitch(&DomeMotionSP, NULL); + } + } else - DomeTimerNP.s = IPS_ALERT; - - IDSetNumber(&DomeTimerNP,NULL); + { + if (Move( DOME_CW, MOTION_START)) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionS[DOME_CW].s = ISS_ON; + DomeMotionSP.s = IPS_BUSY; + IDSetSwitch(&DomeMotionSP, NULL); + } + else + { + DomeMotionSP.s = IPS_ALERT; + IDSetSwitch(&DomeMotionSP, NULL); + } + } } - else if (capability.canRelMove) + } + else if (!strcmp(button_n, "Dome CCW")) + { + if (capability.canRelMove) { - rc=MoveRelDome(DOME_CCW, DomeRelPosN[0].value); - if (rc == 0) + IPState rc= MoveRel(DomeRelPosN[0].value*-1); + if (rc == IPS_OK) { DomeRelPosNP.s=IPS_OK; - IDSetNumber(&DomeRelPosNP, "Dome moved %g degrees CCW", DomeRelPosN[0].value); + IDSetNumber(&DomeRelPosNP, "Dome moved %g degrees CW", DomeRelPosN[0].value); IDSetNumber(&DomeAbsPosNP, NULL); } - else if (rc == 1) + else if (rc == IPS_BUSY) { DomeRelPosNP.s=IPS_BUSY; - IDSetNumber(&DomeAbsPosNP, "Dome is moving %g degrees CCW...", DomeRelPosN[0].value); + IDSetNumber(&DomeAbsPosNP, "Dome is moving %g degrees CW...", DomeRelPosN[0].value); + } + } + else + { + if (DomeMotionSP.s == IPS_BUSY) + { + if (Move( DOME_CCW, MOTION_STOP)) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_IDLE; + IDSetSwitch(&DomeMotionSP, NULL); + } + else + { + DomeMotionSP.s = IPS_ALERT; + IDSetSwitch(&DomeMotionSP, NULL); + } + } + else + { + if (Move( DOME_CCW, MOTION_START)) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionS[DOME_CCW].s = ISS_ON; + DomeMotionSP.s = IPS_BUSY; + IDSetSwitch(&DomeMotionSP, NULL); + } + else + { + DomeMotionSP.s = IPS_ALERT; + IDSetSwitch(&DomeMotionSP, NULL); + } } } } @@ -674,7 +743,7 @@ if (fabs(targetAz - DomeAbsPosN[0].value) > DomeParamN[DOME_AUTOSYNC].value) { int ret = 0; - if ( (ret = MoveAbsDome(targetAz)) == 0) + if ( (ret = MoveAbs(targetAz)) == 0) { DomeAbsPosNP.s=IPS_OK; IDSetNumber(&DomeAbsPosNP, "Dome synced to position %g degrees.", targetAz); @@ -692,5 +761,3 @@ } } } - - diff -Nru libindi-1.0.0/libs/indibase/indidome.h libindi-1.1.0/libs/indibase/indidome.h --- libindi-1.0.0/libs/indibase/indidome.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indidome.h 2015-09-06 13:17:35.000000000 +0000 @@ -155,7 +155,6 @@ */ virtual void UpdateAutoSync(); - double Csc(double x); double Sec(double x); diff -Nru libindi-1.0.0/libs/indibase/indidomeinterface.cpp libindi-1.1.0/libs/indibase/indidomeinterface.cpp --- libindi-1.0.0/libs/indibase/indidomeinterface.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indidomeinterface.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -20,6 +20,7 @@ #include #include +#include #include "indidomeinterface.h" #include "indilogger.h" @@ -30,9 +31,16 @@ capability.canAbsMove=false; capability.canRelMove=true; capability.hasShutter=false; - capability.variableSpeed=false; + capability.hasVariableSpeed=false; - shutterStatus = SHUTTER_UNKNOWN; + shutterState = SHUTTER_UNKNOWN; + domeState = DOME_IDLE; + + last_dome_motion = -1; + + parkDataType = PARK_NONE; + Parkdatafile= "~/.indi/ParkData.xml"; + IsParked=false; } INDI::DomeInterface::~DomeInterface() @@ -47,10 +55,7 @@ IUFillNumber(&DomeSpeedN[0],"DOME_SPEED_VALUE","RPM","%6.2f",0.0,10,0.1,1.0); IUFillNumberVector(&DomeSpeedNP,DomeSpeedN,1,deviceName,"DOME_SPEED","Speed",groupName,IP_RW,60,IPS_OK); - IUFillNumber(&DomeTimerN[0],"DOME_TIMER_VALUE","Dome Timer (ms)","%4.0f",0.0,10000.0,50.0,1000.0); - IUFillNumberVector(&DomeTimerNP,DomeTimerN,1,deviceName,"DOME_TIMER","Timer",groupName,IP_RW,60,IPS_OK); - - IUFillSwitch(&DomeMotionS[0],"DOME_CW","Dome CW",ISS_ON); + IUFillSwitch(&DomeMotionS[0],"DOME_CW","Dome CW",ISS_OFF); IUFillSwitch(&DomeMotionS[1],"DOME_CCW","Dome CCW",ISS_OFF); IUFillSwitchVector(&DomeMotionSP,DomeMotionS,2,deviceName,"DOME_MOTION","Direction",groupName,IP_RW,ISR_ATMOST1,60,IPS_OK); @@ -58,30 +63,36 @@ IUFillNumber(&DomeAbsPosN[0],"DOME_ABSOLUTE_POSITION","Degrees","%6.2f",0.0,360.0,1.0,0.0); IUFillNumberVector(&DomeAbsPosNP,DomeAbsPosN,1,deviceName,"ABS_DOME_POSITION","Absolute Position",groupName,IP_RW,60,IPS_OK); - IUFillNumber(&DomeRelPosN[0],"DOME_RELATIVE_POSITION","Degrees","%6.2f",0.0,180.0,1.0,0.0); + IUFillNumber(&DomeRelPosN[0],"DOME_RELATIVE_POSITION","Degrees","%6.2f",-180,180.0,10.0,0.0); IUFillNumberVector(&DomeRelPosNP,DomeRelPosN,1,deviceName,"REL_DOME_POSITION","Relative Position",groupName,IP_RW,60,IPS_OK); IUFillSwitch(&AbortS[0],"ABORT","Abort",ISS_OFF); IUFillSwitchVector(&AbortSP,AbortS,1,deviceName,"DOME_ABORT_MOTION","Abort Motion",groupName,IP_RW,ISR_ATMOST1,60,IPS_IDLE); IUFillNumber(&DomeParamN[DOME_HOME],"HOME_POSITION","Home (deg)","%6.2f",0.0,360.0,1.0,0.0); - IUFillNumber(&DomeParamN[DOME_PARK],"PARK_POSITION","Park (deg)","%6.2f",0.0,360.0,1.0,0.0); IUFillNumber(&DomeParamN[DOME_AUTOSYNC],"AUTOSYNC_THRESHOLD","Autosync threshold (deg)","%6.2f",0.0,360.0,1.0,0.5); - IUFillNumberVector(&DomeParamNP,DomeParamN,3,deviceName,"DOME_PARAMS","Params",groupName,IP_RW,60,IPS_OK); + IUFillNumberVector(&DomeParamNP,DomeParamN,2,deviceName,"DOME_PARAMS","Params",groupName,IP_RW,60,IPS_OK); + + IUFillSwitch(&DomeGotoS[0],"DOME_HOME","Home",ISS_OFF); + IUFillSwitchVector(&DomeGotoSP,DomeGotoS,1,deviceName,"DOME_GOTO","Goto",groupName,IP_RW,ISR_ATMOST1,60,IPS_OK); - IUFillSwitch(&DomeGotoS[0],"DOME_HOME","Home",ISS_OFF); - IUFillSwitch(&DomeGotoS[1],"DOME_PARK","Park",ISS_OFF); - IUFillSwitchVector(&DomeGotoSP,DomeGotoS,2,deviceName,"DOME_GOTO","Goto",groupName,IP_RW,ISR_ATMOST1,60,IPS_OK); + IUFillSwitch(&ParkS[0],"PARK","Park",ISS_OFF); + IUFillSwitch(&ParkS[1],"UNPARK","UnPark",ISS_OFF); + IUFillSwitchVector(&ParkSP,ParkS,2,deviceName,"DOME_PARK","Parking",groupName,IP_RW,ISR_1OFMANY,60,IPS_OK); IUFillSwitch(&DomeShutterS[0],"SHUTTER_OPEN","Open",ISS_OFF); IUFillSwitch(&DomeShutterS[1],"SHUTTER_CLOSE","Close",ISS_ON); IUFillSwitchVector(&DomeShutterSP,DomeShutterS,2,deviceName,"DOME_SHUTTER","Shutter",groupName,IP_RW,ISR_1OFMANY,60,IPS_OK); + IUFillSwitch(&ParkOptionS[0],"PARK_CURRENT","Current",ISS_OFF); + IUFillSwitch(&ParkOptionS[1],"PARK_DEFAULT","Default",ISS_OFF); + IUFillSwitch(&ParkOptionS[2],"PARK_WRITE_DATA","Write Data",ISS_OFF); + IUFillSwitchVector(&ParkOptionSP,ParkOptionS,3,deviceName,"DOME_PARK_OPTION","Park Options", SITE_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE); + } bool INDI::DomeInterface::processDomeNumber (const char *dev, const char *name, double values[], char *names[], int n) { - if (!strcmp(name, DomeParamNP.name)) { IUUpdateNumber(&DomeParamNP, values, names, n); @@ -90,33 +101,40 @@ return true; } - if(!strcmp(name, DomeTimerNP.name)) + /*if(!strcmp(name, DomeTimerNP.name)) { + if (domeState == DOME_PARKED) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome is parked. Please unpark before issuing any motion commands."); + DomeTimerNP.s = IPS_ALERT; + IDSetNumber(&DomeTimerNP, NULL); + return false; + } + DomeDirection dir; int speed; - int t, rc; + int t; // first we get all the numbers just sent to us IUUpdateNumber(&DomeTimerNP,values,names,n); // Now lets find what we need for this move speed=DomeSpeedN[0].value; - if(DomeMotionS[0].s==ISS_ON) dir=DOME_CW; - else dir=DOME_CCW; + + if(DomeMotionS[0].s==ISS_ON) + dir=DOME_CW; + else + dir=DOME_CCW; t=DomeTimerN[0].value; - rc = MoveDome(dir,speed,t); + DomeTimerNP.s = Move(dir,speed,t); - if (rc == 0) - DomeTimerNP.s = IPS_OK; - else if (rc == 1) - DomeTimerNP.s = IPS_BUSY; - else - DomeTimerNP.s = IPS_ALERT; + if (DomeTimerNP.s == IPS_BUSY) + domeState = DOME_MOVING; IDSetNumber(&DomeTimerNP,NULL); return true; - } + }*/ if(!strcmp(name, DomeSpeedNP.name)) @@ -125,7 +143,7 @@ double current_speed = DomeSpeedN[0].value; IUUpdateNumber(&DomeSpeedNP,values,names,n); - if (SetDomeSpeed(DomeSpeedN[0].value) == false) + if (SetSpeed(DomeSpeedN[0].value) == false) { DomeSpeedN[0].value = current_speed; DomeSpeedNP.s = IPS_ALERT; @@ -138,9 +156,22 @@ if(!strcmp(name, DomeAbsPosNP.name)) { + if (domeState == DOME_PARKED) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome is parked. Please unpark before issuing any motion commands."); + DomeAbsPosNP.s = IPS_ALERT; + IDSetNumber(&DomeAbsPosNP, NULL); + return false; + } + + if (DomeRelPosNP.s != IPS_BUSY && DomeMotionSP.s == IPS_BUSY || (domeState == DOME_PARKING)) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Please stop dome before issuing any further motion commands."); + return false; + } double newPos = values[0]; - int ret =0; + IPState rc; if (newPos < DomeAbsPosN[0].min || newPos > DomeAbsPosN[0].max) { @@ -150,21 +181,23 @@ return false; } - if ( (ret = MoveAbsDome(newPos)) == 0) + if ( (rc = MoveAbs(newPos)) == IPS_OK) { + domeState = DOME_IDLE; DomeAbsPosNP.s=IPS_OK; IUUpdateNumber(&DomeAbsPosNP,values,names,n); IDSetNumber(&DomeAbsPosNP, "Dome moved to position %g degrees.", newPos); return true; } - else if (ret == 1) + else if (rc == IPS_BUSY) { + domeState = DOME_MOVING; DomeAbsPosNP.s=IPS_BUSY; IDSetNumber(&DomeAbsPosNP, "Dome is moving to position %g degrees...", newPos); return true; } - + domeState = DOME_IDLE; DomeAbsPosNP.s = IPS_ALERT; IDSetNumber(&DomeAbsPosNP, "Dome failed to move to new requested position."); return false; @@ -173,38 +206,31 @@ if(!strcmp(name, DomeRelPosNP.name)) { - double newPos = values[0]; - int ret =0; + if (domeState == DOME_PARKED) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome is parked. Please unpark before issuing any motion commands."); + DomeRelPosNP.s = IPS_ALERT; + IDSetNumber(&DomeRelPosNP, NULL); + return false; + } - /*if (capability.canAbsMove) + if (DomeRelPosNP.s != IPS_BUSY && DomeMotionSP.s == IPS_BUSY || (domeState == DOME_PARKING)) { - if (DomeMotionS[0].s == ISS_ON) - { - if (DomeAbsPosN[0].value - newPos < DomeAbsPosN[0].min) - { - DomeRelPosNP.s = IPS_ALERT; - IDSetNumber(&DomeRelPosNP, NULL); - DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Dome minimum position is %g", DomeAbsPosN[0].min); - return false; - } - } - else - { - if (DomeAbsPosN[0].value + newPos > DomeAbsPosN[0].max) - { - DomeRelPosNP.s = IPS_ALERT; - IDSetNumber(&DomeRelPosNP, NULL); - DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Dome maximum position is %g", DomeAbsPosN[0].max); - return false; - } - } - }*/ + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Please stop dome before issuing any further motion commands."); + DomeRelPosNP.s = IPS_IDLE; + IDSetNumber(&DomeRelPosNP, NULL); + return false; + } - if ( (ret=MoveRelDome( (DomeMotionS[0].s == ISS_ON ? DOME_CW : DOME_CCW), newPos)) == 0) + double newPos = values[0]; + IPState rc; + + if ( (rc=MoveRel(newPos)) == IPS_OK) { + domeState = DOME_IDLE; DomeRelPosNP.s=IPS_OK; IUUpdateNumber(&DomeRelPosNP,values,names,n); - IDSetNumber(&DomeRelPosNP, "Dome moved %g degrees %s.", newPos, (DomeMotionS[0].s == ISS_ON ? "clockwise" : "counter clockwise")); + IDSetNumber(&DomeRelPosNP, "Dome moved %g degrees %s.", newPos, (newPos > 0) ? "clockwise" : "counter clockwise"); if (capability.canAbsMove) { DomeAbsPosNP.s=IPS_OK; @@ -212,11 +238,12 @@ } return true; } - else if (ret == 1) + else if (rc == IPS_BUSY) { + domeState = DOME_MOVING; IUUpdateNumber(&DomeRelPosNP,values,names,n); DomeRelPosNP.s=IPS_BUSY; - IDSetNumber(&DomeRelPosNP, "Dome is moving %g degrees %s...", newPos, (DomeMotionS[0].s == ISS_ON ? "clockwise" : "counter clockwise")); + IDSetNumber(&DomeRelPosNP, "Dome is moving %g degrees %s...", newPos, (newPos > 0) ? "clockwise" : "counter clockwise"); if (capability.canAbsMove) { DomeAbsPosNP.s=IPS_BUSY; @@ -225,35 +252,129 @@ return true; } + domeState = DOME_IDLE; DomeRelPosNP.s = IPS_ALERT; IDSetNumber(&DomeRelPosNP, "Dome failed to move to new requested position."); return false; } + if(strcmp(name, ParkPositionNP.name) == 0) + { + IUUpdateNumber(&ParkPositionNP, values, names, n); + ParkPositionNP.s = IPS_OK; + + Axis1ParkPosition = ParkPositionN[AXIS_RA].value; + IDSetNumber(&ParkPositionNP, NULL); + return true; + } + return false; } bool INDI::DomeInterface::processDomeSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) -{ - // This one is for us +{ if(!strcmp(name, DomeMotionSP.name)) { - // client is telling us what to do with Dome direction - DomeMotionSP.s=IPS_OK; + // Check if it is already parked. + if (capability.canPark) + { + if (isParked()) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Please unpark the dome before issuing any motion commands."); + DomeMotionSP.s = IPS_IDLE; + IDSetSwitch(&DomeMotionSP, NULL); + return false; + } + } + + if ( (DomeMotionSP.s != IPS_BUSY && (DomeAbsPosNP.s == IPS_BUSY || DomeRelPosNP.s == IPS_BUSY)) + || (domeState == DOME_PARKING)) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Please stop dome before issuing any further motion commands."); + DomeMotionSP.s = IPS_IDLE; + IDSetSwitch(&DomeMotionSP, NULL); + return false; + } + IUUpdateSwitch(&DomeMotionSP,states,names,n); - // Update client display - IDSetSwitch(&DomeMotionSP,NULL); + + int current_motion = IUFindOnSwitchIndex(&DomeMotionSP); + + // if same move requested, return + if ( DomeMotionSP.s == IPS_BUSY && current_motion == last_dome_motion) + return true; + + // Time to stop motion + if (current_motion == -1 || (last_dome_motion != -1 && current_motion != last_dome_motion)) + { + if (Move(last_dome_motion == 0 ? DOME_CW : DOME_CCW, MOTION_STOP)) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_IDLE; + domeState = DOME_IDLE; + last_dome_motion = -1; + } + else + DomeMotionSP.s = IPS_ALERT; + } + else + { + if (Move(current_motion == 0 ? DOME_CW : DOME_CCW, MOTION_START)) + { + domeState = DOME_MOVING; + DomeMotionSP.s = IPS_BUSY; + last_dome_motion = current_motion; + } + else + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_ALERT; + last_dome_motion = -1; + } + } + + IDSetSwitch(&DomeMotionSP, NULL); return true; + } if(!strcmp(name, AbortSP.name)) { IUResetSwitch(&AbortSP); - if (AbortDome()) + if (Abort()) + { AbortSP.s = IPS_OK; + + if (domeState == DOME_PARKING) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Parking aborted."); + domeState = DOME_IDLE; + IUResetSwitch(&ParkSP); + ParkSP.s = IPS_ALERT; + IDSetSwitch(&ParkSP, NULL); + } + + if (DomeMotionSP.s == IPS_BUSY) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_OK; + IDSetSwitch(&DomeMotionSP, NULL); + } + if (capability.canAbsMove && DomeAbsPosNP.s != IPS_IDLE) + { + DomeAbsPosNP.s = IPS_IDLE; + IDSetNumber(&DomeAbsPosNP, NULL); + } + if (capability.canRelMove && DomeRelPosNP.s != IPS_IDLE) + { + DomeRelPosNP.s = IPS_IDLE; + IDSetNumber(&DomeRelPosNP, NULL); + } + + } else AbortSP.s = IPS_ALERT; @@ -263,28 +384,32 @@ if (!strcmp(name, DomeShutterSP.name)) { - int ret=0; + IPState rc; int prevStatus = IUFindOnSwitchIndex(&DomeShutterSP); + IPState prevState = DomeShutterSP.s; + IUUpdateSwitch(&DomeShutterSP, states, names, n); int shutterDome = IUFindOnSwitchIndex(&DomeShutterSP); // No change of status, let's return if (prevStatus == shutterDome) { - DomeShutterSP.s=IPS_OK; + DomeShutterSP.s = prevState; IDSetSwitch(&DomeShutterSP,NULL); + return true; } // go back to prev status in case of failure IUResetSwitch(&DomeShutterSP); - DomeShutterS[prevStatus].s = ISS_ON; + if (prevState != -1) + DomeShutterS[prevStatus].s = ISS_ON; if (shutterDome == 0) - ret= ControlDomeShutter(SHUTTER_OPEN); + rc= ControlShutter(SHUTTER_OPEN); else - ret= ControlDomeShutter(SHUTTER_CLOSE); + rc= ControlShutter(SHUTTER_CLOSE); - if ( ret == 0) + if ( rc == IPS_OK) { DomeShutterSP.s=IPS_OK; IUResetSwitch(&DomeShutterSP); @@ -292,7 +417,7 @@ IDSetSwitch(&DomeShutterSP, "Shutter is %s.", (shutterDome == 0 ? "open" : "closed")); return true; } - else if (ret == 1) + else if (rc == IPS_BUSY) { DomeShutterSP.s=IPS_BUSY; IUResetSwitch(&DomeShutterSP); @@ -309,112 +434,223 @@ if (!strcmp(name, DomeGotoSP.name)) { - int ret=0; - IUUpdateSwitch(&DomeGotoSP, states, names, n); + IUResetSwitch(&DomeGotoSP); - int gotoDome = IUFindOnSwitchIndex(&DomeGotoSP); + if (domeState == DOME_PARKED) + { + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome is parked. Please unpark before issuing any motion commands."); + DomeGotoSP.s = IPS_ALERT; + IDSetSwitch(&DomeGotoSP, NULL); + return false; + } - if (gotoDome == DOME_HOME) - ret= HomeDome(); - else - ret = ParkDome(); + DomeAbsPosNP.s = DomeGotoSP.s = Home(); - if ( ret == 0) + if (DomeGotoSP.s == IPS_OK) { - DomeGotoSP.s=IPS_OK; - IUResetSwitch(&DomeGotoSP); - IDSetSwitch(&DomeGotoSP, "Dome is %s.", (gotoDome == DOME_HOME ? "at home position" : "parked")); - return true; + domeState = DOME_IDLE; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome is at home position."); } - else if (ret == 1) + else if (DomeGotoSP.s == IPS_BUSY) { - DomeGotoSP.s=IPS_BUSY; - IUResetSwitch(&DomeGotoSP); - IDSetSwitch(&DomeGotoSP, "Dome is %s...", (gotoDome == DOME_HOME ? "moving to home position" : "parking")); - DomeAbsPosNP.s = IPS_BUSY; - IDSetNumber(&DomeAbsPosNP, NULL); - return true; + domeState = DOME_MOVING; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome is moving to home position."); + } + else if (DomeGotoSP.s == IPS_ALERT) + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome failed to move to home position."); + + IDSetSwitch(&DomeGotoSP, NULL); + return true; + } + + if(!strcmp(name,ParkSP.name)) + { + /*if (domeState == SCOPE_PARKING) + { + IUResetSwitch(&ParkSP); + ParkSP.s == IPS_IDLE; + Abort(); + DEBUG(INDI::Logger::DBG_SESSION, "Parking/Unparking aborted."); + IDSetSwitch(&ParkSP, NULL); + return true; + }*/ + + IPState rc; + int preIndex = IUFindOnSwitchIndex(&ParkSP); + IUUpdateSwitch(&ParkSP, states, names, n); + + bool toPark = (ParkS[0].s == ISS_ON); + + if (toPark == false && domeState != DOME_PARKED) + { + IUResetSwitch(&ParkSP); + ParkS[1].s = ISS_ON; + ParkSP.s = IPS_IDLE; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome already unparked."); + IDSetSwitch(&ParkSP, NULL); + return true; + } + + if (toPark && domeState == DOME_PARKED) + { + IUResetSwitch(&ParkSP); + ParkS[0].s = ISS_ON; + ParkSP.s = IPS_IDLE; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome already parked."); + IDSetSwitch(&ParkSP, NULL); + return true; + } + + IUResetSwitch(&ParkSP); + + rc = toPark ? Park() : UnPark(); + + if (toPark) + { + if (rc == IPS_OK) + SetParked(true); + else if (rc == IPS_BUSY) + { + domeState = DOME_PARKING; + + if (capability.canAbsMove) + DomeAbsPosNP.s=IPS_BUSY; + + ParkS[0].s = ISS_ON; + } + } + else + { + if (rc == IPS_OK) + SetParked(false); + else if (rc == IPS_BUSY) + { + ParkS[1].s = ISS_ON; + } + } + + if (DomeMotionSP.s == IPS_BUSY) + { + IUResetSwitch(&DomeMotionSP); + DomeMotionSP.s = IPS_IDLE; + IDSetSwitch(&DomeMotionSP, NULL); } - DomeGotoSP.s= IPS_ALERT; - IDSetNumber(&DomeRelPosNP, "Dome failed to %s.", (gotoDome == DOME_HOME ? "move to home position" : "park")); + ParkSP.s = rc; + if (rc == IPS_ALERT) + ParkS[preIndex].s = ISS_ON; + + IDSetSwitch(&ParkSP, NULL); + return true; + } + + if (!strcmp(name, ParkOptionSP.name)) + { + IUUpdateSwitch(&ParkOptionSP, states, names, n); + ISwitch *sp = IUFindOnSwitch(&ParkOptionSP); + if (!sp) return false; + + IUResetSwitch(&ParkOptionSP); + + if (!strcmp(sp->name, "PARK_CURRENT")) + { + SetCurrentPark(); + } + else if (!strcmp(sp->name, "PARK_DEFAULT")) + { + SetDefaultPark(); + } + else if (!strcmp(sp->name, "PARK_WRITE_DATA")) + { + if (WriteParkData()) + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Saved Park Status/Position."); + else + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Can not save Park Status/Position."); + } + + ParkOptionSP.s = IPS_OK; + IDSetSwitch(&ParkOptionSP, NULL); + + return true; } return false; } -int INDI::DomeInterface::MoveDome(DomeDirection dir, double speed, int duration) +bool INDI::DomeInterface::Move(DomeDirection dir, DomeMotionCommand operation) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + + INDI_UNUSED(dir); + INDI_UNUSED(operation); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support Move(). Move() must be implemented in the child class."); + return false; } -int INDI::DomeInterface::MoveRelDome(DomeDirection dir, double azDiff) +IPState INDI::DomeInterface::MoveRel(double azDiff) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + INDI_UNUSED(azDiff); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support MoveRel(). MoveRel() must be implemented in the child class."); + return IPS_ALERT; } -int INDI::DomeInterface::MoveAbsDome(double az) +IPState INDI::DomeInterface::MoveAbs(double az) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + INDI_UNUSED(az); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support MoveAbs(). MoveAbs() must be implemented in the child class."); + return IPS_ALERT; } -bool INDI::DomeInterface::AbortDome() +bool INDI::DomeInterface::Abort() { // This should be a virtual function, because the low level hardware class // must override this - DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support abort motion."); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support Abort(). Abort() must be implemented in the child class."); return false; } -bool INDI::DomeInterface::SetDomeSpeed(double speed) +bool INDI::DomeInterface::SetSpeed(double speed) { - INDI_UNUSED(speed); - - // This should be a virtual function, because the low level hardware class - // must override this - DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support variable speed."); + INDI_UNUSED(speed); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support SetSpeed(). SetSpeed() must be implemented in the child class."); return false; } -int INDI::DomeInterface::ControlDomeShutter(ShutterOperation operation) +IPState INDI::DomeInterface::ControlShutter(ShutterOperation operation) { - INDI_UNUSED(operation); + INDI_UNUSED(operation); + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support ControlShutter(). ControlShutter() must be implemented in the child class."); + return IPS_ALERT; +} - // This should be a virtual function, because the low level hardware class - // must override this - DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not have shutter control."); - return false; +IPState INDI::DomeInterface::Park() +{ + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support Park(). Park() must be implemented in the child class."); + return IPS_ALERT; } -int INDI::DomeInterface::ParkDome() +IPState INDI::DomeInterface::UnPark() { - // This should be a virtual function, because the low level hardware class - // must override this - DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support park."); - return -1; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support UnPark(). UnPark() must be implemented in the child class."); + return IPS_ALERT; } -int INDI::DomeInterface::HomeDome() +void INDI::DomeInterface::SetCurrentPark() { - // This should be a virtual function, because the low level hardware class - // must override this - DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support homing."); - return -1; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Parking is not supported."); +} + +void INDI::DomeInterface::SetDefaultPark() +{ + DEBUGDEVICE(DomeName, INDI::Logger::DBG_WARNING, "Parking is not supported."); +} + +IPState INDI::DomeInterface::Home() +{ + DEBUGDEVICE(DomeName, INDI::Logger::DBG_ERROR, "Dome does not support Home(). Home() must be implemented in the child class."); + return IPS_ALERT; } void INDI::DomeInterface::SetDomeCapability(DomeCapability *cap) @@ -422,8 +658,10 @@ capability.canAbort = cap->canAbort; capability.canAbsMove = cap->canAbsMove; capability.canRelMove = cap->canRelMove; + capability.canPark = cap->canPark; capability.hasShutter = cap->hasShutter; - capability.variableSpeed= cap->variableSpeed; + capability.hasVariableSpeed= cap->hasVariableSpeed; + } const char * INDI::DomeInterface::GetShutterStatusString(ShutterStatus status) @@ -440,9 +678,261 @@ return "Shutter is in motion."; break; case SHUTTER_UNKNOWN: + default: return "Shutter status is unknown."; break; } } +void INDI::DomeInterface::SetParkDataType(INDI::DomeInterface::DomeParkData type) +{ + parkDataType = type; + + if (parkDataType != PARK_NONE) + { + switch (parkDataType) + { + case PARK_AZ: + IUFillNumber(&ParkPositionN[AXIS_AZ],"PARK_AZ","AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0); + break; + + case PARK_AZ_ENCODER: + IUFillNumber(&ParkPositionN[AXIS_AZ],"PARK_AZ" ,"AZ Encoder","%.0f" ,0,16777215,1,0); + break; + + default: + break; + } + + IUFillNumberVector(&ParkPositionNP,ParkPositionN,1,DomeName,"DOME_PARK_POSITION","Park Position", SITE_TAB,IP_RW,60,IPS_IDLE); + } +} + +void INDI::DomeInterface::SetParked(bool isparked) +{ + IsParked=isparked; + IUResetSwitch(&ParkSP); + if (IsParked) + { + domeState = DOME_PARKED; + ParkSP.s = IPS_OK; + ParkS[0].s = ISS_ON; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome is parked."); + } + else + { + domeState = DOME_IDLE; + ParkSP.s=IPS_IDLE; + ParkS[1].s = ISS_ON; + DEBUGDEVICE(DomeName, INDI::Logger::DBG_SESSION, "Dome is unparked."); + } + + IDSetSwitch(&ParkSP, NULL); + + WriteParkData(); +} + +bool INDI::DomeInterface::isParked() +{ + return IsParked; +} + +bool INDI::DomeInterface::InitPark() +{ + char *loadres; + loadres=LoadParkData(); + if (loadres) + { + DEBUGFDEVICE(DomeName, INDI::Logger::DBG_SESSION, "InitPark: No Park data in file %s: %s", Parkdatafile, loadres); + SetParked(false); + return false; + } + + SetParked(isParked()); + + ParkPositionN[AXIS_AZ].value = Axis1ParkPosition; + IDSetNumber(&ParkPositionNP, NULL); + + // If parked, store the position as current azimuth angle or encoder ticks + if (isParked() && capability.canAbsMove) + { + DomeAbsPosN[0].value = ParkPositionN[AXIS_AZ].value; + IDSetNumber(&DomeAbsPosNP, NULL); + } + + return true; +} + +char *INDI::DomeInterface::LoadParkData() +{ + wordexp_t wexp; + FILE *fp; + LilXML *lp; + static char errmsg[512]; + + XMLEle *parkxml; + XMLAtt *ap; + bool devicefound=false; + + ParkDeviceName = DomeName; + ParkstatusXml=NULL; + ParkdeviceXml=NULL; + ParkpositionXml = NULL; + ParkpositionAxis1Xml = NULL; + + if (wordexp(Parkdatafile, &wexp, 0)) + { + wordfree(&wexp); + return (char *)("Badly formed filename."); + } + + if (!(fp=fopen(wexp.we_wordv[0], "r"))) + { + wordfree(&wexp); + return strerror(errno); + } + wordfree(&wexp); + + lp = newLilXML(); + + if (ParkdataXmlRoot) + delXMLEle(ParkdataXmlRoot); + + ParkdataXmlRoot = readXMLFile(fp, lp, errmsg); + + delLilXML(lp); + if (!ParkdataXmlRoot) + return errmsg; + + if (!strcmp(tagXMLEle(nextXMLEle(ParkdataXmlRoot, 1)), "parkdata")) + return (char *)("Not a park data file"); + + parkxml=nextXMLEle(ParkdataXmlRoot, 1); + + while (parkxml) + { + if (strcmp(tagXMLEle(parkxml), "device")) + { + parkxml=nextXMLEle(ParkdataXmlRoot, 0); + continue; + } + ap = findXMLAtt(parkxml, "name"); + if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName))) + { + devicefound = true; + break; + } + parkxml=nextXMLEle(ParkdataXmlRoot, 0); + } + + if (!devicefound) + return (char *)"No park data found for this device"; + + IsParked=false; + ParkdeviceXml=parkxml; + ParkstatusXml = findXMLEle(parkxml, "parkstatus"); + + if (ParkstatusXml == NULL) + { + return (char *)("Park data invalid or missing."); + } + + if (parkDataType != PARK_NONE) + { + ParkpositionXml = findXMLEle(parkxml, "parkposition"); + ParkpositionAxis1Xml = findXMLEle(ParkpositionXml, "axis1position"); + + if (ParkpositionAxis1Xml == NULL) + { + return (char *)("Park data invalid or missing."); + } + } + + + if (!strcmp(pcdataXMLEle(ParkstatusXml), "true")) + IsParked=true; + + if (parkDataType != PARK_NONE) + sscanf(pcdataXMLEle(ParkpositionAxis1Xml), "%lf", &Axis1ParkPosition); + + return NULL; +} + +bool INDI::DomeInterface::WriteParkData() +{ + wordexp_t wexp; + FILE *fp; + char pcdata[30]; + + if (wordexp(Parkdatafile, &wexp, 0)) + { + wordfree(&wexp); + DEBUGFDEVICE(DomeName, INDI::Logger::DBG_SESSION, "WriteParkData: can not write file %s: Badly formed filename.", Parkdatafile); + return false; + } + + if (!(fp=fopen(wexp.we_wordv[0], "w"))) + { + wordfree(&wexp); + DEBUGFDEVICE(DomeName, INDI::Logger::DBG_SESSION, "WriteParkData: can not write file %s: %s", Parkdatafile, strerror(errno)); + return false; + } + + if (!ParkdataXmlRoot) + ParkdataXmlRoot=addXMLEle(NULL, "parkdata"); + + if (!ParkdeviceXml) + { + ParkdeviceXml=addXMLEle(ParkdataXmlRoot, "device"); + addXMLAtt(ParkdeviceXml, "name", ParkDeviceName); + } + + if (!ParkstatusXml) + ParkstatusXml=addXMLEle(ParkdeviceXml, "parkstatus"); + + if (parkDataType != PARK_NONE) + { + if (!ParkpositionXml) + ParkpositionXml=addXMLEle(ParkdeviceXml, "parkposition"); + if (!ParkpositionAxis1Xml) + ParkpositionAxis1Xml=addXMLEle(ParkpositionXml, "axis1position"); + } + + editXMLEle(ParkstatusXml, (IsParked?"true":"false")); + + if (parkDataType != PARK_NONE) + { + snprintf(pcdata, sizeof(pcdata), "%f", Axis1ParkPosition); + editXMLEle(ParkpositionAxis1Xml, pcdata); + } + + prXMLEle(fp, ParkdataXmlRoot, 0); + fclose(fp); + + return true; +} + +double INDI::DomeInterface::GetAxis1Park() +{ + return Axis1ParkPosition; +} + +double INDI::DomeInterface::GetAxis1ParkDefault() +{ + return Axis1DefaultParkPosition; +} + +void INDI::DomeInterface::SetAxis1Park(double value) +{ + Axis1ParkPosition=value; + ParkPositionN[AXIS_RA].value = value; + IDSetNumber(&ParkPositionNP, NULL); +} + +void INDI::DomeInterface::SetAxis1ParkDefault(double value) +{ + Axis1DefaultParkPosition=value; +} + + diff -Nru libindi-1.0.0/libs/indibase/indidomeinterface.h libindi-1.1.0/libs/indibase/indidomeinterface.h --- libindi-1.0.0/libs/indibase/indidomeinterface.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indidomeinterface.h 2015-09-06 13:17:35.000000000 +0000 @@ -28,9 +28,11 @@ * \class INDI::DomeInterface \brief Provides interface to implement Dome functionality. - A Dome can be an independent device, or an embedded Dome within another device (e.g. Telescope). Before using any of the dome functions, you must define the capabilities of the dome and calling + A Dome can be an independent device, or an embedded Dome within another device. Before using any of the dome functions, you must define the capabilities of the dome by calling SetDomeCapability() function. All positions are represented as degrees of azimuth. + Relative motion is specified in degrees as either positive (clock wise direction), or negative (counter clock-wise direction). + Slaving is used to synchronizes the dome's azimuth position with that of the mount. The mount's azimuth position is snooped from the ACTIVE_TELESCOPE property in ACTIVE_DEVICES vector. The AutoSync threshold is the difference in degrees between the dome's azimuth angle and the mount's azimuth angle that should trigger a dome motion. By default, it is set to 0.5 degrees which would trigger dome motion due to any difference between the dome and mount azimuth angles that exceeds 0.5 degrees. For example, if the threshold is set to 5 degrees, the dome will only start moving to sync with the mount's azimuth angle once @@ -46,7 +48,14 @@ public: enum DomeDirection { DOME_CW, DOME_CCW }; - enum DomeParam { DOME_HOME, DOME_PARK, DOME_AUTOSYNC }; + enum DomeParam { DOME_HOME, DOME_AUTOSYNC }; + enum DomeMotionCommand { MOTION_START, MOTION_STOP }; + + /*! Dome Parking data type enum */ + enum DomeParkData { PARK_NONE, /*!< Open loop Parking */ + PARK_AZ, /*!< Parking via azimuth angle control */ + PARK_AZ_ENCODER, /*!< Parking via azimuth encoder control */ + }; /** \typedef ShutterOperation \brief Shutter operation command. @@ -57,6 +66,17 @@ SHUTTER_CLOSE /*!< Close Shutter */ } ShutterOperation; + /** \typedef DomeState + \brief Dome status + */ + typedef enum + { + DOME_IDLE, /*!< Dome is idle */ + DOME_MOVING, /*!< Dome is in motion */ + DOME_PARKING, /*!< Dome is parking */ + DOME_PARKED, /*!< Dome is parked */ + } DomeState; + /** \typedef ShutterStatus \brief Shutter Status */ @@ -78,12 +98,14 @@ bool canAbort; /** Can the dome move to an absolute azimuth position? */ bool canAbsMove; - /** Can the dome move to a relative position a number of degrees away from current position? */ + /** Can the dome move to a relative position a number of degrees away from current position? Positive degress is Clockwise direction. Negative Degrees is counter clock wise direction */ bool canRelMove; + /** Can the dome park and unpark itself? */ + bool canPark; /** Does the dome has a shutter than can be opened and closed electronically? */ bool hasShutter; /** Can the dome move in different configurable speeds? */ - bool variableSpeed; + bool hasVariableSpeed; } DomeCapability; /** @@ -119,59 +141,63 @@ * @param rpm Dome speed (RPM) * @return true if successful, false otherwise */ - virtual bool SetDomeSpeed(double rpm); + virtual bool SetSpeed(double rpm); - /** \brief Move the Dome in a particular direction with a specific speed for a finite duration. + /** \brief Move the Dome in a particular direction. \param dir Direction of Dome, either DOME_CW or DOME_CCW. - \param speed Speed (RPM) of dome if supported by the dome. - \param duration The timeout in milliseconds before the dome motion halts. - \return Return 0 if motion is completed and Dome reached requested position. Return 1 if Dome started motion to requested position and is in progress. - Return -1 if there is an error. + \return Return true if dome started motion in the desired direction. False if there is an error. */ - virtual int MoveDome(DomeDirection dir, double speed, int duration); + virtual bool Move(DomeDirection dir, DomeMotionCommand operation); /** \brief Move the Dome to an absolute azimuth. \param az The new position of the Dome. - \return Return 0 if motion is completed and Dome reached requested position. Return 1 if Dome started motion to requested position and is in progress. - Return -1 if there is an error. + \return Return IPS_OK if motion is completed and Dome reached requested position. Return IPS_BUSY if Dome started motion to requested position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int MoveAbsDome(double az); + virtual IPState MoveAbs(double az); /** \brief Move the Dome to an relative position. - \param dir Direction of Dome, either DOME_CW or DOME_CCW. - \param azDiff The relative azimuth angle to move. - \return Return 0 if motion is completed and Dome reached requested position. Return 1 if Dome started motion to requested position and is in progress. - Return -1 if there is an error. + \param azDiff The relative azimuth angle to move. Positive degree is clock-wise direction. Negative degrees is counter clock-wise direction. + \return Return IPS_OK if motion is completed and Dome reached requested position. Return IPS_BUSY if Dome started motion to requested position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int MoveRelDome(DomeDirection dir, double azDiff); + virtual IPState MoveRel(double azDiff); /** * \brief Abort all dome motion * \return True if abort is successful, false otherwise. */ - virtual bool AbortDome(); + virtual bool Abort(); /** * \brief Goto Home Position. The home position is an absolute azimuth value. - * \return Return 0 if motion is completed and Dome reached home position. Return 1 if Dome started motion to home position and is in progress. - Return -1 if there is an error. + * \return Return IPS_OK if motion is completed and Dome reached home position. Return IPS_BUSY if Dome started motion to home position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int HomeDome(); + virtual IPState Home(); /** * \brief Goto Park Position. The park position is an absolute azimuth value. - * \return Return 0 if motion is completed and Dome reached park position. Return 1 if Dome started motion to park requested position and is in progress. - Return -1 if there is an error. + * \return Return IPS_OK if motion is completed and Dome reached park position. Return IPS_BUSY if Dome started motion to park requested position and is in progress. + Return -IPS_ALERT if there is an error. */ - virtual int ParkDome(); + virtual IPState Park(); + + /** + * \brief UnPark dome. The action of the Unpark command is dome specific, but it may include opening the shutter and moving to home position. When UnPark() is successful + * The observatory should be in a ready state to utilize the mount to perform observations. + * \return Return IPS_OK if motion is completed and Dome is unparked. Return IPS_BUSY if Dome unparking is in progress. + Return -IPS_ALERT if there is an error. + */ + virtual IPState UnPark(); /** * \brief Open or Close shutter * \param operation Either open or close the shutter. - * \return Return 0 if shutter operation is complete. Return 1 if shutter operation is in progress. - Return -1 if there is an error. + * \return Return IPS_OK if shutter operation is complete. Return IPS_BUSY if shutter operation is in progress. + Return IPS_ALERT if there is an error. */ - virtual int ControlDomeShutter(ShutterOperation operation); + virtual IPState ControlShutter(ShutterOperation operation); /** * @brief getShutterStatusString @@ -180,29 +206,122 @@ */ const char * GetShutterStatusString(ShutterStatus status); + /** + * \brief setParkDataType Sets the type of parking data stored in the park data file and presented to the user. + * \param type parking data type. If PARK_NONE then no properties will be presented to the user for custom parking position. + */ + void SetParkDataType(DomeParkData type); + + /** + * @brief InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status + * and parking position. InitPark() should be called after successful connection to the dome on startup. + * @return True if loading is successful and data is read, false otherwise. On success, you must call + * SetAzParkDefault() to set the default parking values. On failure, you must call + * SetAzParkDefault() to set the default parking values in addition to SetAzPark() + * to set the current parking position. + */ + bool InitPark(); + + /** + * @brief isParked is dome currently parked? + * @return True if parked, false otherwise. + */ + bool isParked(); + + /** + * @brief SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData.xml) is updated in the process. + * @param isparked set to true if parked, false otherwise. + */ + void SetParked(bool isparked); + + /** + * @return Get current AZ parking position. + */ + double GetAxis1Park(); + + /** + * @return Get default AZ parking position. + */ + double GetAxis1ParkDefault(); + + /** + * @brief SetRAPark Set current AZ parking position. The data park file (stored in ~/.indi/ParkData.xml) is updated in the process. + * @param value current Axis 1 value (AZ either in angles or encoder values as specificed by the DomeParkData type). + */ + void SetAxis1Park(double value); + + /** + * @brief SetAxis1Park Set default AZ parking position. + * @param value Default Axis 1 value (AZ either in angles or encoder values as specificed by the DomeParkData type). + */ + void SetAxis1ParkDefault(double steps); + + /** + * @brief SetCurrentPark Set current coordinates/encoders value as the desired parking position + * \note This function performs no action unless subclassed by the child class if required. + */ + virtual void SetCurrentPark(); + + /** + * @brief SetDefaultPark Set default coordinates/encoders value as the desired parking position + * \note This function performs no action unless subclassed by the child class if required. + */ + virtual void SetDefaultPark(); + + //Park + char *LoadParkData(); + bool WriteParkData(); + INumberVectorProperty DomeSpeedNP; INumber DomeSpeedN[1]; + ISwitchVectorProperty DomeMotionSP; ISwitch DomeMotionS[2]; - INumberVectorProperty DomeTimerNP; - INumber DomeTimerN[1]; + INumberVectorProperty DomeAbsPosNP; INumber DomeAbsPosN[1]; + INumberVectorProperty DomeRelPosNP; INumber DomeRelPosN[1]; + ISwitchVectorProperty AbortSP; ISwitch AbortS[1]; + ISwitchVectorProperty DomeGotoSP; - ISwitch DomeGotoS[2]; + ISwitch DomeGotoS[1]; + INumberVectorProperty DomeParamNP; - INumber DomeParamN[3]; + INumber DomeParamN[2]; + ISwitchVectorProperty DomeShutterSP; ISwitch DomeShutterS[2]; + ISwitchVectorProperty ParkSP; + ISwitch ParkS[2]; + + INumber ParkPositionN[1]; + INumberVectorProperty ParkPositionNP; + + ISwitch ParkOptionS[3]; + ISwitchVectorProperty ParkOptionSP; + DomeCapability capability; - ShutterStatus shutterStatus; + DomeState domeState; + ShutterStatus shutterState; + DomeParkData parkDataType; + int last_dome_motion; + +private: + char DomeName[MAXINDIDEVICE]; + bool IsParked; + const char *ParkDeviceName; + const char * Parkdatafile; + XMLEle *ParkdataXmlRoot, *ParkdeviceXml, *ParkstatusXml, *ParkpositionXml, *ParkpositionAxis1Xml; + + double Axis1ParkPosition; + double Axis1DefaultParkPosition; }; #endif // INDIDomeINTERFACE_H diff -Nru libindi-1.0.0/libs/indibase/indifocuser.cpp libindi-1.1.0/libs/indibase/indifocuser.cpp --- libindi-1.0.0/libs/indibase/indifocuser.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indifocuser.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -57,6 +57,7 @@ controller->mapController("Focus In", "Focus In", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); controller->mapController("Focus Out", "Focus Out", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); + controller->mapController("Abort Focus", "Abort Focus", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); controller->initProperties(); @@ -157,6 +158,22 @@ { IUUpdateSwitch(&PresetGotoSP, states, names, n); int index = IUFindOnSwitchIndex(&PresetGotoSP); + + if (PresetN[index].value < FocusAbsPosN[0].min) + { + PresetGotoSP.s = IPS_ALERT; + IDSetSwitch(&PresetGotoSP, NULL); + DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus minimum position is %g", FocusAbsPosN[0].min); + return false; + } + else if (PresetN[index].value > FocusAbsPosN[0].max) + { + PresetGotoSP.s = IPS_ALERT; + IDSetSwitch(&PresetGotoSP, NULL); + DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus maximum position is %g", FocusAbsPosN[0].max); + return false; + } + int rc = MoveAbsFocuser(PresetN[index].value); if (rc >= 0) { @@ -230,9 +247,36 @@ FocusTimerN[0].value = lastTimerValue; - int rc=0; + IPState rc= IPS_IDLE; + + // Abort + if (!strcmp(button_n, "Abort Focus")) + { + if (AbortFocuser()) + { + AbortSP.s = IPS_OK; + DEBUG(INDI::Logger::DBG_SESSION, "Focuser aborted."); + if (capability.canAbsMove && FocusAbsPosNP.s != IPS_IDLE) + { + FocusAbsPosNP.s = IPS_IDLE; + IDSetNumber(&FocusAbsPosNP, NULL); + } + if (capability.canRelMove && FocusRelPosNP.s != IPS_IDLE) + { + FocusRelPosNP.s = IPS_IDLE; + IDSetNumber(&FocusRelPosNP, NULL); + } + } + else + { + AbortSP.s = IPS_ALERT; + DEBUG(INDI::Logger::DBG_ERROR, "Aborting focuser failed."); + } + + IDSetSwitch(&AbortSP, NULL); + } // Focus In - if (!strcmp(button_n, "Focus In")) + else if (!strcmp(button_n, "Focus In")) { if (FocusMotionS[FOCUS_INWARD].s != ISS_ON) { @@ -244,25 +288,19 @@ if (capability.variableSpeed) { rc = MoveFocuser(FOCUS_INWARD, FocusSpeedN[0].value, FocusTimerN[0].value); - if (rc == 0) - FocusTimerNP.s = IPS_OK; - else if (rc == 1) - FocusTimerNP.s = IPS_BUSY; - else - FocusTimerNP.s = IPS_ALERT; - - IDSetNumber(&FocusTimerNP,NULL); + FocusTimerNP.s = rc; + IDSetNumber(&FocusTimerNP,NULL); } else if (capability.canRelMove) { rc=MoveRelFocuser(FOCUS_INWARD, FocusRelPosN[0].value); - if (rc == 0) + if (rc == IPS_OK) { FocusRelPosNP.s=IPS_OK; IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps inward", (int) FocusRelPosN[0].value); IDSetNumber(&FocusAbsPosNP, NULL); } - else if (rc == 1) + else if (rc == IPS_BUSY) { FocusRelPosNP.s=IPS_BUSY; IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps inward...", (int) FocusRelPosN[0].value); @@ -281,25 +319,19 @@ if (capability.variableSpeed) { rc = MoveFocuser(FOCUS_OUTWARD, FocusSpeedN[0].value, FocusTimerN[0].value); - if (rc == 0) - FocusTimerNP.s = IPS_OK; - else if (rc == 1) - FocusTimerNP.s = IPS_BUSY; - else - FocusTimerNP.s = IPS_ALERT; - - IDSetNumber(&FocusTimerNP,NULL); + FocusTimerNP.s = rc; + IDSetNumber(&FocusTimerNP,NULL); } else if (capability.canRelMove) { rc=MoveRelFocuser(FOCUS_OUTWARD, FocusRelPosN[0].value); - if (rc == 0) + if (rc == IPS_OK) { FocusRelPosNP.s=IPS_OK; IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps outward", (int) FocusRelPosN[0].value); IDSetNumber(&FocusAbsPosNP, NULL); } - else if (rc == 1) + else if (rc == IPS_BUSY) { FocusRelPosNP.s=IPS_BUSY; IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps outward...", (int) FocusRelPosN[0].value); diff -Nru libindi-1.0.0/libs/indibase/indifocuserinterface.cpp libindi-1.1.0/libs/indibase/indifocuserinterface.cpp --- libindi-1.0.0/libs/indibase/indifocuserinterface.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indifocuserinterface.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -50,13 +50,13 @@ IUFillSwitch(&FocusMotionS[0],"FOCUS_INWARD","Focus In",ISS_ON); IUFillSwitch(&FocusMotionS[1],"FOCUS_OUTWARD","Focus Out",ISS_OFF); - IUFillSwitchVector(&FocusMotionSP,FocusMotionS,2,deviceName,"FOCUS_MOTION","Direction",groupName,IP_RW,ISR_ATMOST1,60,IPS_OK); + IUFillSwitchVector(&FocusMotionSP,FocusMotionS,2,deviceName,"FOCUS_MOTION","Direction",groupName,IP_RW,ISR_1OFMANY,60,IPS_OK); // Driver can define those to clients if there is support - IUFillNumber(&FocusAbsPosN[0],"FOCUS_ABSOLUTE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,50000.0); + IUFillNumber(&FocusAbsPosN[0],"FOCUS_ABSOLUTE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,0); IUFillNumberVector(&FocusAbsPosNP,FocusAbsPosN,1,deviceName,"ABS_FOCUS_POSITION","Absolute Position",groupName,IP_RW,60,IPS_OK); - IUFillNumber(&FocusRelPosN[0],"FOCUS_RELATIVE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,50000.0); + IUFillNumber(&FocusRelPosN[0],"FOCUS_RELATIVE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,0); IUFillNumberVector(&FocusRelPosNP,FocusRelPosN,1,deviceName,"REL_FOCUS_POSITION","Relative Position",groupName,IP_RW,60,IPS_OK); IUFillSwitch(&AbortS[0],"ABORT","Abort",ISS_OFF); @@ -71,27 +71,23 @@ { FocusDirection dir; int speed; - int t, rc; + int t; // first we get all the numbers just sent to us IUUpdateNumber(&FocusTimerNP,values,names,n); // Now lets find what we need for this move speed=FocusSpeedN[0].value; - if(FocusMotionS[0].s==ISS_ON) dir=FOCUS_INWARD; - else dir=FOCUS_OUTWARD; - t=FocusTimerN[0].value; - lastTimerValue = t; - - rc = MoveFocuser(dir,speed,t); - if (rc == 0) - FocusTimerNP.s = IPS_OK; - else if (rc == 1) - FocusTimerNP.s = IPS_BUSY; + if(FocusMotionS[0].s==ISS_ON) + dir=FOCUS_INWARD; else - FocusTimerNP.s = IPS_ALERT; + dir=FOCUS_OUTWARD; + + t=FocusTimerN[0].value; + lastTimerValue = t; + FocusTimerNP.s = MoveFocuser(dir,speed,t); IDSetNumber(&FocusTimerNP,NULL); return true; } @@ -116,18 +112,33 @@ if(strcmp(name,"ABS_FOCUS_POSITION")==0) { - int newPos = (int) values[0]; - int ret =0; - if ( (ret = MoveAbsFocuser(newPos)) == 0) + if (newPos < FocusAbsPosN[0].min) + { + FocusAbsPosNP.s = IPS_ALERT; + IDSetNumber(&FocusAbsPosNP, NULL); + DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus minimum position is %g", FocusAbsPosN[0].min); + return false; + } + else if (newPos > FocusAbsPosN[0].max) + { + FocusAbsPosNP.s = IPS_ALERT; + IDSetNumber(&FocusAbsPosNP, NULL); + DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus maximum position is %g", FocusAbsPosN[0].max); + return false; + } + + IPState ret; + + if ( (ret = MoveAbsFocuser(newPos)) == IPS_OK) { FocusAbsPosNP.s=IPS_OK; IUUpdateNumber(&FocusAbsPosNP,values,names,n); IDSetNumber(&FocusAbsPosNP, "Focuser moved to position %d", newPos); return true; } - else if (ret == 1) + else if (ret == IPS_BUSY) { FocusAbsPosNP.s=IPS_BUSY; IDSetNumber(&FocusAbsPosNP, "Focuser is moving to position %d", newPos); @@ -144,7 +155,16 @@ if(strcmp(name,"REL_FOCUS_POSITION")==0) { int newPos = (int) values[0]; - int ret =0; + + if (newPos <= 0) + { + DEBUGDEVICE(dev, INDI::Logger::DBG_ERROR, "Relative ticks value must be greater than zero."); + FocusRelPosNP.s = IPS_ALERT; + IDSetNumber(&FocusRelPosNP, NULL); + return false; + } + + IPState ret; if (capability.canAbsMove) { @@ -170,19 +190,20 @@ } } - if ( (ret=MoveRelFocuser( (FocusMotionS[0].s == ISS_ON ? FOCUS_INWARD : FOCUS_OUTWARD), newPos)) == 0) + if ( (ret=MoveRelFocuser( (FocusMotionS[0].s == ISS_ON ? FOCUS_INWARD : FOCUS_OUTWARD), newPos)) == IPS_OK) { - FocusRelPosNP.s=IPS_OK; + FocusRelPosNP.s=FocusAbsPosNP.s=IPS_OK; IUUpdateNumber(&FocusRelPosNP,values,names,n); - IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps", newPos); + IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps %s", newPos, FocusMotionS[0].s == ISS_ON ? "inward" : "outward"); IDSetNumber(&FocusAbsPosNP, NULL); return true; } - else if (ret == 1) + else if (ret == IPS_BUSY) { IUUpdateNumber(&FocusRelPosNP,values,names,n); - FocusRelPosNP.s=IPS_BUSY; - IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps...", newPos); + FocusRelPosNP.s=FocusAbsPosNP.s=IPS_BUSY; + IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps %s...", newPos, FocusMotionS[0].s == ISS_ON ? "inward" : "outward"); + IDSetNumber(&FocusAbsPosNP, NULL); return true; } @@ -214,7 +235,19 @@ IUResetSwitch(&AbortSP); if (AbortFocuser()) + { AbortSP.s = IPS_OK; + if (capability.canAbsMove && FocusAbsPosNP.s != IPS_IDLE) + { + FocusAbsPosNP.s = IPS_IDLE; + IDSetNumber(&FocusAbsPosNP, NULL); + } + if (capability.canRelMove && FocusRelPosNP.s != IPS_IDLE) + { + FocusRelPosNP.s = IPS_IDLE; + IDSetNumber(&FocusRelPosNP, NULL); + } + } else AbortSP.s = IPS_ALERT; @@ -226,31 +259,22 @@ } -int INDI::FocuserInterface::MoveFocuser(FocusDirection dir, int speed, int duration) +IPState INDI::FocuserInterface::MoveFocuser(FocusDirection dir, int speed, uint16_t duration) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + // Must be implemented by child class + return IPS_ALERT; } -int INDI::FocuserInterface::MoveRelFocuser(FocusDirection dir, unsigned int ticks) +IPState INDI::FocuserInterface::MoveRelFocuser(FocusDirection dir, uint32_t ticks) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + // Must be implemented by child class + return IPS_ALERT; } -int INDI::FocuserInterface::MoveAbsFocuser(int ticks) +IPState INDI::FocuserInterface::MoveAbsFocuser(uint32_t ticks) { - // This should be a virtual function, because the low level hardware class - // must override this - // but it's much easier early development if the method actually - // exists for now - return -1; + // Must be implemented by child class + return IPS_ALERT; } diff -Nru libindi-1.0.0/libs/indibase/indifocuserinterface.h libindi-1.1.0/libs/indibase/indifocuserinterface.h --- libindi-1.0.0/libs/indibase/indifocuserinterface.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indifocuserinterface.h 2015-09-06 13:17:35.000000000 +0000 @@ -95,25 +95,25 @@ \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD. \param speed Speed of focuser if supported by the focuser. \param duration The timeout in milliseconds before the focus motion halts. - \return Return 0 if motion is completed and focuser reached requested position. Return 1 if focuser started motion to requested position and is in progress. - Return -1 if there is an error. + \return Return IPS_OK if motion is completed and focuser reached requested position. Return IPS_BUSY if focuser started motion to requested position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int MoveFocuser(FocusDirection dir, int speed, int duration); + virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration); /** \brief MoveFocuser the focuser to an absolute position. \param ticks The new position of the focuser. - \return Return 0 if motion is completed and focuser reached requested position. Return 1 if focuser started motion to requested position and is in progress. - Return -1 if there is an error. + \return Return IPS_OK if motion is completed and focuser reached requested position. Return IPS_BUSY if focuser started motion to requested position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int MoveAbsFocuser(int ticks); + virtual IPState MoveAbsFocuser(uint32_t ticks); /** \brief MoveFocuser the focuser to an relative position. \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD. \param ticks The relative ticks to move. - \return Return 0 if motion is completed and focuser reached requested position. Return 1 if focuser started motion to requested position and is in progress. - Return -1 if there is an error. + \return Return IPS_OK if motion is completed and focuser reached requested position. Return IPS_BUSY if focuser started motion to requested position and is in progress. + Return IPS_ALERT if there is an error. */ - virtual int MoveRelFocuser(FocusDirection dir, unsigned int ticks); + virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks); /** * @brief AbortFocuser all focus motion diff -Nru libindi-1.0.0/libs/indibase/indigps.cpp libindi-1.1.0/libs/indibase/indigps.cpp --- libindi-1.0.0/libs/indibase/indigps.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indigps.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,139 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI GPS Device Class + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#include "indigps.h" + +#define POLLMS 1000 + +INDI::GPS::GPS() +{ + //ctor +} + +INDI::GPS::~GPS() +{ +} + +bool INDI::GPS::initProperties() +{ + INDI::DefaultDevice::initProperties(); + + IUFillSwitch(&RefreshS[0], "REFRESH", "GPS", ISS_OFF); + IUFillSwitchVector(&RefreshSP, RefreshS, 1, getDeviceName(), "GPS_REFRESH", "Refresh", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + IUFillNumber(&LocationN[LOCATION_LATITUDE],"LAT","Lat (dd:mm:ss)","%010.6m",-90,90,0,0.0); + IUFillNumber(&LocationN[LOCATION_LONGITUDE],"LONG","Lon (dd:mm:ss)","%010.6m",0,360,0,0.0 ); + IUFillNumber(&LocationN[LOCATION_ELEVATION],"ELEV","Elevation (m)","%g",-200,10000,0,0 ); + IUFillNumberVector(&LocationNP,LocationN,3,getDeviceName(),"GEOGRAPHIC_COORD","Location",MAIN_CONTROL_TAB,IP_RO,60,IPS_OK); + + IUFillText(&TimeT[0],"UTC","UTC Time",NULL); + IUFillText(&TimeT[1],"OFFSET","UTC Offset",NULL); + IUFillTextVector(&TimeTP,TimeT,2,getDeviceName(),"TIME_UTC","UTC",MAIN_CONTROL_TAB,IP_RO,60,IPS_IDLE); + + return true; +} + +bool INDI::GPS::updateProperties() +{ + INDI::DefaultDevice::updateProperties(); + + if (isConnected()) + { + // Update GPS and send values to client + IPState state = updateGPS(); + + defineNumber(&LocationNP); + defineText(&TimeTP); + defineSwitch(&RefreshSP); + + if (state != IPS_OK) + { + if (state == IPS_BUSY) + DEBUG(INDI::Logger::DBG_SESSION, "GPS fix is in progress..."); + + SetTimer(POLLMS); + } + } + else + { + deleteProperty(LocationNP.name); + deleteProperty(TimeTP.name); + deleteProperty(RefreshSP.name); + } + + return true; +} + + +void INDI::GPS::TimerHit() +{ + if (isConnected() == false) + return; + + IPState state = updateGPS(); + + switch (state) + { + // Ok or Alert + case IPS_OK: + case IPS_ALERT: + IDSetNumber(&LocationNP, NULL); + IDSetText(&TimeTP, NULL); + return; + + // GPS fix is in progress + case IPS_BUSY: + IDSetNumber(&LocationNP, NULL); + IDSetText(&TimeTP, NULL); + break; + + default: + break; + } + + SetTimer(POLLMS); +} + +IPState INDI::GPS::updateGPS() +{ + DEBUG(INDI::Logger::DBG_ERROR, "updateGPS() must be implemented in GPS device child class to update TIME_UTC and GEOGRAPHIC_COORD properties."); + return IPS_ALERT; +} + +bool INDI::GPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) + { + if (!strcmp(name, RefreshSP.name)) + { + RefreshS[0].s = ISS_OFF; + RefreshSP.s = IPS_OK; + IDSetSwitch(&RefreshSP, NULL); + + TimerHit(); + } + } + + return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n); +} diff -Nru libindi-1.0.0/libs/indibase/indigps.h libindi-1.1.0/libs/indibase/indigps.h --- libindi-1.0.0/libs/indibase/indigps.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indigps.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,85 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI GPS Device Class + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#ifndef INDIGPS_H +#define INDIGPS_H + +#include + +/** + * \class INDI::GPS + \brief Class to provide general functionality of a GPS device. + + The INDI::GPS provides a simple interface for GPS devices. It reports time in INDI standard property TIME_UTC. Location is reported in INDI standard property GEOGRAPHIC_COORD + Only one function is called by the INDI framework to update GPS data (updateGPS()). If the data is valid, it is sent to the client. If GPS data is not ready yet, updateGPS will + be called every second until the data becomes available and then INDI sends the data to the client. + + updateGPS() is called upon successful connection and whenever the client requests a data refresh. + + \example GPS Simulator is available under Auxiliary drivers as a sample implementation of INDI::GPS + \e IMPORTANT: GEOGRAPHIC_COORD stores latitude and longitude in INDI specific format, refer to INDI Standard Properties for details. + +\author Jasem Mutlaq +*/ +class INDI::GPS : public INDI::DefaultDevice +{ + public: + + enum GPSLocation { LOCATION_LATITUDE, LOCATION_LONGITUDE, LOCATION_ELEVATION }; + + GPS(); + virtual ~GPS(); + + virtual bool initProperties(); + virtual bool updateProperties(); + virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + + protected: + + /** + * @brief updateGPS Retrieve Location & Time from GPS. Update LocationNP & TimeTP properties (value and state) without sending them to the client (i.e. IDSetXXX). + * @return Return overall state. The state should be IPS_OK if data is valid. IPS_BUSY if GPS fix is in progress. IPS_ALERT is there is an error. The clients will only accept values with IPS_OK state. + */ + virtual IPState updateGPS(); + + /** + * @brief TimerHit Keep calling updateGPS() until it is successfull, if it fails upon first connection. + */ + virtual void TimerHit(); + + // A number vector that stores lattitude and longitude + INumberVectorProperty LocationNP; + INumber LocationN[3]; + + // UTC and UTC Offset + IText TimeT[2]; + ITextVectorProperty TimeTP; + + // Refresh data + ISwitch RefreshS[1]; + ISwitchVectorProperty RefreshSP; + +}; + +#endif // INDIGPS_H diff -Nru libindi-1.0.0/libs/indibase/indiguiderinterface.cpp libindi-1.1.0/libs/indibase/indiguiderinterface.cpp --- libindi-1.0.0/libs/indibase/indiguiderinterface.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiguiderinterface.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -36,13 +36,13 @@ void INDI::GuiderInterface::initGuiderProperties(const char *deviceName, const char* groupName) { - IUFillNumber(&GuideNSN[0],"TIMED_GUIDE_N","North (msec)","%g",0,60000,10,0); - IUFillNumber(&GuideNSN[1],"TIMED_GUIDE_S","South (msec)","%g",0,60000,10,0); - IUFillNumberVector(&GuideNSNP,GuideNSN,2,deviceName,"TELESCOPE_TIMED_GUIDE_NS","Guide North/South",groupName,IP_RW,60,IPS_IDLE); - - IUFillNumber(&GuideWEN[0],"TIMED_GUIDE_E","East (msec)","%g",0,60000,10,0); - IUFillNumber(&GuideWEN[1],"TIMED_GUIDE_W","West (msec)","%g",0,60000,10,0); - IUFillNumberVector(&GuideWENP,GuideWEN,2,deviceName,"TELESCOPE_TIMED_GUIDE_WE","Guide East/West",groupName,IP_RW,60,IPS_IDLE); + IUFillNumber(&GuideNSN[DIRECTION_NORTH],"TIMED_GUIDE_N","North (ms)","%.f",0,60000,100,0); + IUFillNumber(&GuideNSN[DIRECTION_SOUTH],"TIMED_GUIDE_S","South (ms)","%.f",0,60000,100,0); + IUFillNumberVector(&GuideNSNP,GuideNSN,2,deviceName,"TELESCOPE_TIMED_GUIDE_NS","Guide N/S",groupName,IP_RW,60,IPS_IDLE); + + IUFillNumber(&GuideWEN[DIRECTION_WEST],"TIMED_GUIDE_W","West (ms)","%.f",0,60000,100,0); + IUFillNumber(&GuideWEN[DIRECTION_EAST],"TIMED_GUIDE_E","East (ms)","%.f",0,60000,100,0); + IUFillNumberVector(&GuideWENP,GuideWEN,2,deviceName,"TELESCOPE_TIMED_GUIDE_WE","Guide E/W",groupName,IP_RW,60,IPS_IDLE); } void INDI::GuiderInterface::processGuiderProperties(const char *name, double values[], char *names[], int n) @@ -51,19 +51,15 @@ { // We are being asked to send a guide pulse north/south on the st4 port IUUpdateNumber(&GuideNSNP,values,names,n); - bool rc= false; - if(GuideNSN[0].value != 0) + if(GuideNSN[DIRECTION_NORTH].value != 0) { - GuideNSN[1].value = 0; - rc = GuideNorth(GuideNSN[0].value); - } - else if(GuideNSN[1].value != 0) - { - rc = GuideSouth(GuideNSN[1].value); + GuideNSN[DIRECTION_SOUTH].value = 0; + GuideNSNP.s = GuideNorth(GuideNSN[DIRECTION_NORTH].value); } + else if(GuideNSN[DIRECTION_SOUTH].value != 0) + GuideNSNP.s = GuideSouth(GuideNSN[DIRECTION_SOUTH].value); - GuideNSNP.s= rc ? IPS_OK : IPS_ALERT; IDSetNumber(&GuideNSNP,NULL); return; } @@ -72,20 +68,34 @@ { // We are being asked to send a guide pulse north/south on the st4 port IUUpdateNumber(&GuideWENP,values,names,n); - bool rc=false; - if(GuideWEN[0].value != 0) + if(GuideWEN[DIRECTION_WEST].value != 0) { - GuideWEN[1].value = 0; - rc = GuideEast(GuideWEN[0].value); + GuideWEN[DIRECTION_EAST].value = 0; + GuideWENP.s = GuideWest(GuideWEN[DIRECTION_WEST].value); } - else if(GuideWEN[1].value != 0) - rc = GuideWest(GuideWEN[1].value); + else if(GuideWEN[DIRECTION_EAST].value != 0) + GuideWENP.s = GuideEast(GuideWEN[DIRECTION_EAST].value); - GuideWENP.s= rc ? IPS_OK : IPS_ALERT; IDSetNumber(&GuideWENP,NULL); return; } } +void INDI::GuiderInterface::GuideComplete(INDI_EQ_AXIS axis) +{ + switch (axis) + { + case AXIS_DE: + GuideNSNP.s = IPS_IDLE; + IDSetNumber(&GuideNSNP, NULL); + break; + + case AXIS_RA: + GuideWENP.s = IPS_IDLE; + IDSetNumber(&GuideWENP, NULL); + break; + } +} + diff -Nru libindi-1.0.0/libs/indibase/indiguiderinterface.h libindi-1.1.0/libs/indibase/indiguiderinterface.h --- libindi-1.0.0/libs/indibase/indiguiderinterface.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiguiderinterface.h 2015-09-06 13:17:35.000000000 +0000 @@ -27,6 +27,11 @@ * \class INDI::GuiderInterface \brief Provides interface to implement guider (ST4) port functionality. + The child class implements GuideXXXX() functions and returns: + * IPS_OK if the guide operation is completed in the function, which is usually appropiate for very short guiding pulses. + * IPS_BUSY if the guide operation is in progress and will take time to complete. In this case, the child class must call GuideComplete() once the guiding pulse is complete. + * IPS_ALERT if the guide operation failed. + \e IMPORTANT: initGuiderProperties() must be called before any other function to initilize the guider properties. \e IMPORATNT: processGuiderProperties() must be called in your driver's ISNewNumber(..) function. processGuiderProperties() will call the guide functions @@ -40,24 +45,30 @@ public: /** \brief Guide north for ms milliseconds - \return True if OK, false otherwise + \return IPS_OK if operation is completed successfully, IPS_BUSY if operation will take take to complete, or IPS_ALERT if operation failed. */ - virtual bool GuideNorth(float ms) = 0; + virtual IPState GuideNorth(float ms) = 0; /** \brief Guide south for ms milliseconds - \return True if OK, false otherwise + \return IPS_OK if operation is completed successfully, IPS_BUSY if operation will take take to complete, or IPS_ALERT if operation failed. */ - virtual bool GuideSouth(float ms) = 0; + virtual IPState GuideSouth(float ms) = 0; /** \brief Guide east for ms milliseconds - \return True if OK, false otherwise + \return IPS_OK if operation is completed successfully, IPS_BUSY if operation will take take to complete, or IPS_ALERT if operation failed. */ - virtual bool GuideEast(float ms) = 0; + virtual IPState GuideEast(float ms) = 0; /** \brief Guide west for ms milliseconds - \return True if OK, false otherwise + \return IPS_OK if operation is completed successfully, IPS_BUSY if operation will take take to complete, or IPS_ALERT if operation failed. */ - virtual bool GuideWest(float ms) = 0; + virtual IPState GuideWest(float ms) = 0; + + /** + * \brief Call GuideComplete once the guiding pulse is complete. + * @param axis Axis of completed guiding operation. + */ + virtual void GuideComplete(INDI_EQ_AXIS axis); protected: diff -Nru libindi-1.0.0/libs/indibase/indilogger.cpp libindi-1.1.0/libs/indibase/indilogger.cpp --- libindi-1.0.0/libs/indibase/indilogger.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indilogger.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -71,7 +71,7 @@ unsigned int Logger::rememberscreenlevel_=Logger::defaultlevel; Logger::loggerConf Logger::configuration_= Logger::screen_on | Logger::file_off; std::string Logger::logFile_; - +unsigned int Logger::nDevices=0; unsigned int Logger::customLevel=4; int Logger::addDebugLevel(const char *debugLevelName, const char * loggingLevelName) @@ -89,6 +89,8 @@ bool Logger::initProperties(DefaultDevice *device) { + nDevices++; + for (unsigned int i=0; i +#include #include "inditelescope.h" #include "indicom.h" @@ -24,31 +25,50 @@ INDI::Telescope::Telescope() { - //ctor capability.canPark = capability.canSync = capability.canAbort = false; + capability.nSlewRate = 0; last_we_motion = last_ns_motion = -1; + parkDataType = PARK_NONE; + Parkdatafile= "~/.indi/ParkData.xml"; + IsParked=false; + SlewRateS = NULL; + + controller = new INDI::Controller(this); + controller->setJoystickCallback(joystickHelper); + controller->setButtonCallback(buttonHelper); + } INDI::Telescope::~Telescope() { - + delete (controller); } bool INDI::Telescope::initProperties() { DefaultDevice::initProperties(); - IUFillNumber(&EqN[0],"RA","RA (hh:mm:ss)","%010.6m",0,24,0,0); - IUFillNumber(&EqN[1],"DEC","DEC (dd:mm:ss)","%010.6m",-90,90,0,0); + // Active Devices + IUFillText(&ActiveDeviceT[0],"ACTIVE_GPS","GPS","GPS Simulator"); + IUFillTextVector(&ActiveDeviceTP,ActiveDeviceT,1,getDeviceName(),"ACTIVE_DEVICES","Snoop devices",OPTIONS_TAB,IP_RW,60,IPS_IDLE); + + IUFillNumber(&EqN[AXIS_RA],"RA","RA (hh:mm:ss)","%010.6m",0,24,0,0); + IUFillNumber(&EqN[AXIS_DE],"DEC","DEC (dd:mm:ss)","%010.6m",-90,90,0,0); IUFillNumberVector(&EqNP,EqN,2,getDeviceName(),"EQUATORIAL_EOD_COORD","Eq. Coordinates",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); + lastEqState = IPS_IDLE; - IUFillText(&TimeT[0],"UTC","UTC Time",""); - IUFillText(&TimeT[1],"OFFSET","UTC Offset",""); + IUFillSwitch(&ParkOptionS[0],"PARK_CURRENT","Current",ISS_OFF); + IUFillSwitch(&ParkOptionS[1],"PARK_DEFAULT","Default",ISS_OFF); + IUFillSwitch(&ParkOptionS[2],"PARK_WRITE_DATA","Write Data",ISS_OFF); + IUFillSwitchVector(&ParkOptionSP,ParkOptionS,3,getDeviceName(),"TELESCOPE_PARK_OPTION","Park Options", SITE_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE); + + IUFillText(&TimeT[0],"UTC","UTC Time",NULL); + IUFillText(&TimeT[1],"OFFSET","UTC Offset",NULL); IUFillTextVector(&TimeTP,TimeT,2,getDeviceName(),"TIME_UTC","UTC",SITE_TAB,IP_RW,60,IPS_IDLE); - IUFillNumber(&LocationN[0],"LAT","Lat (dd:mm:ss)","%010.6m",-90,90,0,0.0); - IUFillNumber(&LocationN[1],"LONG","Lon (dd:mm:ss)","%010.6m",0,360,0,0.0 ); - IUFillNumber(&LocationN[2],"ELEV","Elevation (m)","%g",-200,10000,0,0 ); + IUFillNumber(&LocationN[LOCATION_LATITUDE],"LAT","Lat (dd:mm:ss)","%010.6m",-90,90,0,0.0); + IUFillNumber(&LocationN[LOCATION_LONGITUDE],"LONG","Lon (dd:mm:ss)","%010.6m",0,360,0,0.0 ); + IUFillNumber(&LocationN[LOCATION_ELEVATION],"ELEV","Elevation (m)","%g",-200,10000,0,0 ); IUFillNumberVector(&LocationNP,LocationN,3,getDeviceName(),"GEOGRAPHIC_COORD","Scope Location",SITE_TAB,IP_RW,60,IPS_OK); IUFillSwitch(&CoordS[0],"TRACK","Track",ISS_ON); @@ -60,9 +80,12 @@ else IUFillSwitchVector(&CoordSP,CoordS,2,getDeviceName(),"ON_COORD_SET","On Set",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); + if (capability.nSlewRate >= 4) + IUFillSwitchVector(&SlewRateSP, SlewRateS, capability.nSlewRate, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&ParkS[0],"PARK","Park",ISS_OFF); - IUFillSwitchVector(&ParkSP,ParkS,1,getDeviceName(),"TELESCOPE_PARK","Park",MAIN_CONTROL_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE); + IUFillSwitch(&ParkS[1],"UNPARK","UnPark",ISS_OFF); + IUFillSwitchVector(&ParkSP,ParkS,2,getDeviceName(),"TELESCOPE_PARK","Parking",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillSwitch(&AbortS[0],"ABORT","Abort",ISS_OFF); IUFillSwitchVector(&AbortSP,AbortS,1,getDeviceName(),"TELESCOPE_ABORT_MOTION","Abort Motion",MAIN_CONTROL_TAB,IP_RW,ISR_ATMOST1,60,IPS_IDLE); @@ -70,13 +93,21 @@ IUFillText(&PortT[0],"PORT","Port","/dev/ttyUSB0"); IUFillTextVector(&PortTP,PortT,1,getDeviceName(),"DEVICE_PORT","Ports",OPTIONS_TAB,IP_RW,60,IPS_IDLE); - IUFillSwitch(&MovementNSS[MOTION_NORTH], "MOTION_NORTH", "North", ISS_OFF); - IUFillSwitch(&MovementNSS[MOTION_SOUTH], "MOTION_SOUTH", "South", ISS_OFF); - IUFillSwitchVector(&MovementNSSP, MovementNSS, 2, getDeviceName(),"TELESCOPE_MOTION_NS", "North/South", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); - - IUFillSwitch(&MovementWES[MOTION_WEST], "MOTION_WEST", "West", ISS_OFF); - IUFillSwitch(&MovementWES[MOTION_EAST], "MOTION_EAST", "East", ISS_OFF); - IUFillSwitchVector(&MovementWESP, MovementWES, 2, getDeviceName(),"TELESCOPE_MOTION_WE", "West/East", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); + IUFillSwitch(&BaudRateS[0], "9600", "", ISS_ON); + IUFillSwitch(&BaudRateS[1], "19200", "", ISS_OFF); + IUFillSwitch(&BaudRateS[2], "38400", "", ISS_OFF); + IUFillSwitch(&BaudRateS[3], "57600", "", ISS_OFF); + IUFillSwitch(&BaudRateS[4], "115200", "", ISS_OFF); + IUFillSwitch(&BaudRateS[5], "230400", "", ISS_OFF); + IUFillSwitchVector(&BaudRateSP, BaudRateS, 6, getDeviceName(),"TELESCOPE_BAUD_RATE", "Baud Rate", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); + + IUFillSwitch(&MovementNSS[DIRECTION_NORTH], "MOTION_NORTH", "North", ISS_OFF); + IUFillSwitch(&MovementNSS[DIRECTION_SOUTH], "MOTION_SOUTH", "South", ISS_OFF); + IUFillSwitchVector(&MovementNSSP, MovementNSS, 2, getDeviceName(),"TELESCOPE_MOTION_NS", "Motion N/S", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); + + IUFillSwitch(&MovementWES[DIRECTION_WEST], "MOTION_WEST", "West", ISS_OFF); + IUFillSwitch(&MovementWES[DIRECTION_EAST], "MOTION_EAST", "East", ISS_OFF); + IUFillSwitchVector(&MovementWESP, MovementWES, 2, getDeviceName(),"TELESCOPE_MOTION_WE", "Motion W/E", MOTION_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE); IUFillNumber(&ScopeParametersN[0],"TELESCOPE_APERTURE","Aperture (mm)","%g",50,4000,0,0.0); IUFillNumber(&ScopeParametersN[1],"TELESCOPE_FOCAL_LENGTH","Focal Length (mm)","%g",100,10000,0,0.0 ); @@ -84,10 +115,25 @@ IUFillNumber(&ScopeParametersN[3],"GUIDER_FOCAL_LENGTH","Guider Focal Length (mm)","%g",100,10000,0,0.0 ); IUFillNumberVector(&ScopeParametersNP,ScopeParametersN,4,getDeviceName(),"TELESCOPE_INFO","Scope Properties",OPTIONS_TAB,IP_RW,60,IPS_OK); - TrackState=SCOPE_PARKED; + controller->mapController("MOTIONDIR", "N/S/W/E Control", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1"); + if (capability.nSlewRate >= 4) + controller->mapController("SLEWPRESET", "Slew Rate", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_2"); + if (capability.canAbort) + controller->mapController("ABORTBUTTON", "Abort", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); + if (capability.canPark) + { + controller->mapController("PARKBUTTON", "Park", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); + controller->mapController("UNPARKBUTTON", "UnPark", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); + } + controller->initProperties(); + + TrackState=SCOPE_IDLE; setInterfaceDescriptor(TELESCOPE_INTERFACE); + IDSnoopDevice(ActiveDeviceT[0].text,"GEOGRAPHIC_COORD"); + IDSnoopDevice(ActiveDeviceT[0].text,"TIME_UTC"); + return true; } @@ -97,6 +143,7 @@ DefaultDevice::ISGetProperties(dev); defineText(&PortTP); + defineSwitch(&BaudRateSP); if(isConnected()) { @@ -105,15 +152,36 @@ defineNumber(&EqNP); if (capability.canAbort) defineSwitch(&AbortSP); - defineText(&TimeTP); - defineNumber(&LocationNP); - defineSwitch(&ParkSP); + + if (capability.hasTime) + defineText(&TimeTP); + if (capability.hasLocation) + defineNumber(&LocationNP); + + if (capability.canPark) + { + defineSwitch(&ParkSP); + if (parkDataType != PARK_NONE) + { + defineNumber(&ParkPositionNP); + defineSwitch(&ParkOptionSP); + } + } defineSwitch(&MovementNSSP); defineSwitch(&MovementWESP); + + if (capability.nSlewRate >= 4) + defineSwitch(&SlewRateSP); + defineNumber(&ScopeParametersNP); + if (capability.hasTime && capability.hasLocation) + defineText(&ActiveDeviceTP); + } - return; + + controller->ISGetProperties(dev); + } bool INDI::Telescope::updateProperties() @@ -128,12 +196,27 @@ defineSwitch(&AbortSP); defineSwitch(&MovementNSSP); defineSwitch(&MovementWESP); - defineText(&TimeTP); - defineNumber(&LocationNP); + if (capability.nSlewRate >= 4) + defineSwitch(&SlewRateSP); + + if (capability.hasTime) + defineText(&TimeTP); + if (capability.hasLocation) + defineNumber(&LocationNP); if (capability.canPark) + { defineSwitch(&ParkSP); + if (parkDataType != PARK_NONE) + { + defineNumber(&ParkPositionNP); + defineSwitch(&ParkOptionSP); + } + } defineNumber(&ScopeParametersNP); + if (capability.hasTime && capability.hasLocation) + defineText(&ActiveDeviceTP); + } else { @@ -143,37 +226,107 @@ deleteProperty(AbortSP.name); deleteProperty(MovementNSSP.name); deleteProperty(MovementWESP.name); - deleteProperty(TimeTP.name); - deleteProperty(LocationNP.name); + if (capability.nSlewRate >= 4) + deleteProperty(SlewRateSP.name); + + if (capability.hasTime) + deleteProperty(TimeTP.name); + if (capability.hasLocation) + deleteProperty(LocationNP.name); + if (capability.canPark) + { deleteProperty(ParkSP.name); + if (parkDataType != PARK_NONE) + { + deleteProperty(ParkPositionNP.name); + deleteProperty(ParkOptionSP.name); + } + } deleteProperty(ScopeParametersNP.name); + + if (capability.hasTime && capability.hasLocation) + deleteProperty(ActiveDeviceTP.name); } + controller->updateProperties(); + return true; } bool INDI::Telescope::ISSnoopDevice(XMLEle *root) { + controller->ISSnoopDevice(root); + + XMLEle *ep=NULL; + const char *propName = findXMLAttValu(root, "name"); + + if (isConnected()) + { + if (capability.hasLocation && !strcmp(propName, "GEOGRAPHIC_COORD")) + { + // Only accept IPS_OK state + if (strcmp(findXMLAttValu(root, "state"), "Ok")) + return false; + + double longitude=-1, latitude=-1, elevation=-1; + + for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) + { + const char *elemName = findXMLAttValu(ep, "name"); + + if (!strcmp(elemName, "LAT")) + latitude = atof(pcdataXMLEle(ep)); + else if (!strcmp(elemName, "LONG")) + longitude = atof(pcdataXMLEle(ep)); + else if (!strcmp(elemName, "ELEV")) + elevation = atof(pcdataXMLEle(ep)); + + } + + return processLocationInfo(latitude, longitude, elevation); + } + else if (capability.hasTime && !strcmp(propName, "TIME_UTC")) + { + // Only accept IPS_OK state + if (strcmp(findXMLAttValu(root, "state"), "Ok")) + return false; + + char utc[MAXINDITSTAMP], offset[MAXINDITSTAMP]; + + for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) + { + const char *elemName = findXMLAttValu(ep, "name"); + + if (!strcmp(elemName, "UTC")) + strncpy(utc, pcdataXMLEle(ep), MAXINDITSTAMP); + else if (!strcmp(elemName, "OFFSET")) + strncpy(offset, pcdataXMLEle(ep), MAXINDITSTAMP); + } + + return processTimeInfo(utc, offset); + } + } + return INDI::DefaultDevice::ISSnoopDevice(root); } bool INDI::Telescope::saveConfigItems(FILE *fp) { - + IUSaveConfigText(fp, &ActiveDeviceTP); IUSaveConfigText(fp, &PortTP); - IUSaveConfigNumber(fp,&LocationNP); + IUSaveConfigSwitch(fp, &BaudRateSP); + if (capability.hasLocation) + IUSaveConfigNumber(fp,&LocationNP); IUSaveConfigNumber(fp, &ScopeParametersNP); + controller->saveConfigItems(fp); + return true; } void INDI::Telescope::NewRaDec(double ra,double dec) { - // Lets set our eq values to these numbers - // which came from the hardware - static int last_state=-1; - switch(TrackState) { case SCOPE_PARKED: @@ -193,12 +346,11 @@ break; } - //IDLog("newRA DEC RA %g - DEC %g --- EqN[0] %g --- EqN[1] %g --- EqN.state %d\n", ra, dec, EqN[0].value, EqN[1].value, EqNP.s); - if (EqN[0].value != ra || EqN[1].value != dec || EqNP.s != last_state) + if (EqN[AXIS_RA].value != ra || EqN[AXIS_DE].value != dec || EqNP.s != lastEqState) { - EqN[0].value=ra; - EqN[1].value=dec; - last_state = EqNP.s; + EqN[AXIS_RA].value=ra; + EqN[AXIS_DE].value=dec; + lastEqState = EqNP.s; IDSetNumber(&EqNP, NULL); } @@ -207,26 +359,26 @@ bool INDI::Telescope::Sync(double ra,double dec) { // if we get here, our mount doesn't support sync - DEBUG(Logger::DBG_ERROR, "Mount does not support Sync."); + DEBUG(Logger::DBG_ERROR, "Telescope does not support Sync."); return false; } -bool INDI::Telescope::MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command) +bool INDI::Telescope::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) { INDI_UNUSED(dir); INDI_UNUSED(command); - DEBUG(Logger::DBG_ERROR, "Mount does not support North/South motion."); + DEBUG(Logger::DBG_ERROR, "Telescope does not support North/South motion."); IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); return false; } -bool INDI::Telescope::MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command) +bool INDI::Telescope::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) { INDI_UNUSED(dir); INDI_UNUSED(command); - DEBUG(Logger::DBG_ERROR,"Mount does not support West/East motion."); + DEBUG(Logger::DBG_ERROR,"Telescope does not support West/East motion."); IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); @@ -239,11 +391,10 @@ bool INDI::Telescope::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // first check if it's for our device - if(strcmp(dev,getDeviceName())==0) + if(!strcmp(dev,getDeviceName())) { - // This is for our device - // Now lets see if it's something we process here - if(strcmp(name,PortTP.name)==0) + + if(!strcmp(name,PortTP.name)) { // This is our port, so, lets process it int rc; @@ -255,38 +406,28 @@ return true; } - if(strcmp(name,"TIME_UTC")==0) + if(!strcmp(name,TimeTP.name)) { int utcindex = IUFindIndex("UTC", names, n); int offsetindex= IUFindIndex("OFFSET", names, n); - struct ln_date utc; - double utc_offset=0; - if (extractISOTime(texts[utcindex], &utc) == -1) - { - TimeTP.s = IPS_ALERT; - IDSetText(&TimeTP, "Date/Time is invalid: %s.", texts[utcindex]); - return false; - } - - utc_offset = atof(texts[offsetindex]); + return processTimeInfo(texts[utcindex], texts[offsetindex]); + } - if (updateTime(&utc, utc_offset)) - { - IUUpdateText(&TimeTP, texts, names, n); - TimeTP.s = IPS_OK; - IDSetText(&TimeTP, NULL); - return true; - } - else - { - TimeTP.s = IPS_ALERT; - IDSetText(&TimeTP, NULL); - return false; - } + if(!strcmp(name,ActiveDeviceTP.name)) + { + ActiveDeviceTP.s=IPS_OK; + IUUpdateText(&ActiveDeviceTP,texts,names,n); + // Update client display + IDSetText(&ActiveDeviceTP,NULL); + + IDSnoopDevice(ActiveDeviceT[0].text,"GEOGRAPHIC_COORD"); + IDSnoopDevice(ActiveDeviceT[0].text,"TIME_UTC"); + return true; + } } - } + controller->ISNewText(dev, name, texts, names, n); return DefaultDevice::ISNewText(dev,name,texts,names,n); } @@ -312,21 +453,29 @@ //IDLog("request stuff %s %4.2f\n",names[x],values[x]); INumber *eqp = IUFindNumber (&EqNP, names[x]); - if (eqp == &EqN[0]) + if (eqp == &EqN[AXIS_RA]) { ra = values[x]; - } else if (eqp == &EqN[1]) + } else if (eqp == &EqN[AXIS_DE]) { dec = values[x]; } } if ((ra>=0)&&(ra<=24)&&(dec>=-90)&&(dec<=90)) { - // we got an ra and a dec, both in range - // And now we let the underlying hardware specific class - // perform the goto - // Ok, lets see if we should be doing a goto - // or a sync + // Check if it is already parked. + if (capability.canPark) + { + if (isParked()) + { + DEBUG(INDI::Logger::DBG_WARNING, "Please unpark the mount before issuing any motion/sync commands."); + EqNP.s = lastEqState = IPS_IDLE; + IDSetNumber(&EqNP, NULL); + return false; + } + } + + // Check if it can sync if (capability.canSync) { ISwitch *sw; @@ -335,25 +484,22 @@ { rc=Sync(ra,dec); if (rc) - CoordSP .s = IPS_OK; + EqNP .s = lastEqState = IPS_OK; else - CoordSP.s = IPS_ALERT; - IDSetSwitch(&CoordSP, NULL); + EqNP.s = lastEqState = IPS_ALERT; + IDSetNumber(&EqNP, NULL); return rc; } } - // Ensure we are not showing Parked status - ParkSP.s=IPS_IDLE; - IUResetSwitch(&ParkSP); + // Issue GOTO rc=Goto(ra,dec); if (rc) - CoordSP .s = IPS_OK; + EqNP .s = lastEqState = IPS_BUSY; else - CoordSP.s = IPS_ALERT; - IDSetSwitch(&CoordSP, NULL); + EqNP.s = lastEqState = IPS_ALERT; + IDSetNumber(&EqNP, NULL); - // Ok, now we have to put our switches back } return rc; } @@ -374,19 +520,8 @@ double targetLong = values[longindex]; double targetElev = values[elevationindex]; - if (updateLocation(targetLat, targetLong, targetElev)) - { - LocationNP.s=IPS_OK; - IUUpdateNumber(&LocationNP,values,names,n); - // Update client display - IDSetNumber(&LocationNP,NULL); - } - else - { - LocationNP.s=IPS_ALERT; - // Update client display - IDSetNumber(&LocationNP,NULL); - } + return processLocationInfo(targetLat, targetLong, targetElev); + } if(strcmp(name,"TELESCOPE_INFO")==0) @@ -399,6 +534,18 @@ return true; } + if(strcmp(name, ParkPositionNP.name) == 0) + { + IUUpdateNumber(&ParkPositionNP, values, names, n); + ParkPositionNP.s = IPS_OK; + + Axis1ParkPosition = ParkPositionN[AXIS_RA].value; + Axis2ParkPosition = ParkPositionN[AXIS_DE].value; + + IDSetNumber(&ParkPositionNP, NULL); + return true; + } + } return DefaultDevice::ISNewNumber(dev,name,values,names,n); @@ -412,7 +559,7 @@ if(strcmp(dev,getDeviceName())==0) { // This one is for us - if(strcmp(name,"ON_COORD_SET")==0) + if(!strcmp(name,CoordSP.name)) { // client is telling us what to do with co-ordinate requests CoordSP.s=IPS_OK; @@ -422,36 +569,102 @@ return true; } - if(strcmp(name,"TELESCOPE_PARK")==0) + // Slew Rate + if (!strcmp (name, SlewRateSP.name)) { - ParkS[0].s = ISS_OFF; + int preIndex = IUFindOnSwitchIndex(&SlewRateSP); + IUUpdateSwitch(&SlewRateSP, states, names, n); + int nowIndex = IUFindOnSwitchIndex(&SlewRateSP); + if (SetSlewRate(nowIndex) == false) + { + IUResetSwitch(&SlewRateSP); + SlewRateS[preIndex].s = ISS_ON; + SlewRateSP.s = IPS_ALERT; + } + else + SlewRateSP.s = IPS_OK; + IDSetSwitch(&SlewRateSP, NULL); + return true; + } - if (ParkSP.s == IPS_BUSY) + if(!strcmp(name,ParkSP.name)) + { + if (TrackState == SCOPE_PARKING) { + IUResetSwitch(&ParkSP); + ParkSP.s == IPS_IDLE; + Abort(); + DEBUG(INDI::Logger::DBG_SESSION, "Parking/Unparking aborted."); + IDSetSwitch(&ParkSP, NULL); + return true; + } + + int preIndex = IUFindOnSwitchIndex(&ParkSP); + IUUpdateSwitch(&ParkSP, states, names, n); + + bool toPark = (ParkS[0].s == ISS_ON); + + if (toPark == false && TrackState != SCOPE_PARKED) + { + IUResetSwitch(&ParkSP); + ParkS[1].s = ISS_ON; + ParkSP.s = IPS_IDLE; + DEBUG(INDI::Logger::DBG_SESSION, "Telescope already unparked."); IDSetSwitch(&ParkSP, NULL); return true; } - bool rc = Park(); + if (toPark && TrackState == SCOPE_PARKED) + { + IUResetSwitch(&ParkSP); + ParkS[0].s = ISS_ON; + ParkSP.s = IPS_IDLE; + DEBUG(INDI::Logger::DBG_SESSION, "Telescope already parked."); + IDSetSwitch(&ParkSP, NULL); + return true; + } + + IUResetSwitch(&ParkSP); + bool rc = toPark ? Park() : UnPark(); if (rc) { if (TrackState == SCOPE_PARKING) { - ParkS[0].s = ISS_ON; + ParkS[0].s = toPark ? ISS_ON : ISS_OFF; + ParkS[1].s = toPark ? ISS_OFF : ISS_ON; ParkSP.s = IPS_BUSY; } else + { + ParkS[0].s = toPark ? ISS_ON : ISS_OFF; + ParkS[1].s = toPark ? ISS_OFF : ISS_ON; ParkSP.s = IPS_OK; + } } else + { + ParkS[preIndex].s = ISS_ON; ParkSP.s = IPS_ALERT; + } IDSetSwitch(&ParkSP, NULL); return true; } - if(strcmp(name,"TELESCOPE_MOTION_NS")==0) - { + if(!strcmp(name,MovementNSSP.name)) + { + // Check if it is already parked. + if (capability.canPark) + { + if (isParked()) + { + DEBUG(INDI::Logger::DBG_WARNING, "Please unpark the mount before issuing any motion/sync commands."); + MovementNSSP.s = IPS_IDLE; + IDSetSwitch(&MovementNSSP, NULL); + return false; + } + } + IUUpdateSwitch(&MovementNSSP,states,names,n); int current_motion = IUFindOnSwitchIndex(&MovementNSSP); @@ -463,7 +676,7 @@ // Time to stop motion if (current_motion == -1 || (last_ns_motion != -1 && current_motion != last_ns_motion)) { - if (MoveNS(last_ns_motion == 0 ? MOTION_NORTH : MOTION_SOUTH, MOTION_STOP)) + if (MoveNS(last_ns_motion == 0 ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_STOP)) { IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; @@ -474,13 +687,17 @@ } else { - if (MoveNS(current_motion == 0 ? MOTION_NORTH : MOTION_SOUTH, MOTION_START)) + if (MoveNS(current_motion == 0 ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_START)) { MovementNSSP.s = IPS_BUSY; last_ns_motion = current_motion; } else + { + IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_ALERT; + last_ns_motion = -1; + } } IDSetSwitch(&MovementNSSP, NULL); @@ -488,8 +705,20 @@ return true; } - if(strcmp(name,"TELESCOPE_MOTION_WE")==0) + if(!strcmp(name,MovementWESP.name)) { + // Check if it is already parked. + if (capability.canPark) + { + if (isParked()) + { + DEBUG(INDI::Logger::DBG_WARNING, "Please unpark the mount before issuing any motion/sync commands."); + MovementWESP.s = IPS_IDLE; + IDSetSwitch(&MovementWESP, NULL); + return false; + } + } + IUUpdateSwitch(&MovementWESP,states,names,n); int current_motion = IUFindOnSwitchIndex(&MovementWESP); @@ -501,7 +730,7 @@ // Time to stop motion if (current_motion == -1 || (last_we_motion != -1 && current_motion != last_we_motion)) { - if (MoveWE(last_we_motion == 0 ? MOTION_WEST : MOTION_EAST, MOTION_STOP)) + if (MoveWE(last_we_motion == 0 ? DIRECTION_WEST : DIRECTION_EAST, MOTION_STOP)) { IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; @@ -512,13 +741,17 @@ } else { - if (MoveWE(current_motion == 0 ? MOTION_WEST : MOTION_EAST, MOTION_START)) + if (MoveWE(current_motion == 0 ? DIRECTION_WEST : DIRECTION_EAST, MOTION_START)) { MovementWESP.s = IPS_BUSY; last_we_motion = current_motion; } else + { + IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_ALERT; + last_we_motion = -1; + } } IDSetSwitch(&MovementWESP, NULL); @@ -526,7 +759,7 @@ return true; } - if(strcmp(name,"TELESCOPE_ABORT_MOTION")==0) + if(!strcmp(name,AbortSP.name)) { IUResetSwitch(&AbortSP); @@ -540,29 +773,32 @@ } if (EqNP.s == IPS_BUSY) { - EqNP.s = IPS_IDLE; + EqNP.s = lastEqState = IPS_IDLE; IDSetNumber(&EqNP, NULL); } if (MovementWESP.s == IPS_BUSY) { + IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); } if (MovementNSSP.s == IPS_BUSY) { + IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); } if (EqNP.s == IPS_BUSY) { - EqNP.s = IPS_IDLE; + EqNP.s = lastEqState = IPS_IDLE; IDSetNumber(&EqNP, NULL); } last_ns_motion=last_we_motion=-1; - TrackState = SCOPE_IDLE; + if (TrackState != SCOPE_PARKED) + TrackState = SCOPE_IDLE; } else AbortSP.s = IPS_ALERT; @@ -572,8 +808,57 @@ return true; } + if (!strcmp(name, ParkOptionSP.name)) + { + IUUpdateSwitch(&ParkOptionSP, states, names, n); + ISwitch *sp = IUFindOnSwitch(&ParkOptionSP); + if (!sp) + return false; + + IUResetSwitch(&ParkOptionSP); + + if ( (TrackState != SCOPE_IDLE && TrackState != SCOPE_TRACKING) || MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) + { + DEBUG(INDI::Logger::DBG_SESSION, "Can not change park position while slewing or already parked..."); + ParkOptionSP.s=IPS_ALERT; + IDSetSwitch(&ParkOptionSP, NULL); + return false; + } + + if (!strcmp(sp->name, "PARK_CURRENT")) + { + SetCurrentPark(); + } + else if (!strcmp(sp->name, "PARK_DEFAULT")) + { + SetDefaultPark(); + } + else if (!strcmp(sp->name, "PARK_WRITE_DATA")) + { + if (WriteParkData()) + DEBUG(INDI::Logger::DBG_SESSION, "Saved Park Status/Position."); + else + DEBUG(INDI::Logger::DBG_WARNING, "Can not save Park Status/Position."); + } + + ParkOptionSP.s = IPS_OK; + IDSetSwitch(&ParkOptionSP, NULL); + + return true; + } + + if (!strcmp(name, BaudRateSP.name)) + { + IUUpdateSwitch(&BaudRateSP, states, names, n); + BaudRateSP.s = IPS_OK; + IDSetSwitch(&BaudRateSP, NULL); + return true; + } + } + controller->ISNewSwitch(dev, name, states, names, n); + // Nobody has claimed this, so, ignore it return DefaultDevice::ISNewSwitch(dev,name,states,names,n); } @@ -581,21 +866,12 @@ bool INDI::Telescope::Connect() { - // Parent class is wanting a connection - if (isDebug()) - IDLog("INDI::Telescope arrived in connect with %s\n",PortT[0].text); bool rc=false; - if(isConnected()) return true; - - - if (isDebug()) - IDLog("Telescope Calling Connect\n"); - - rc=Connect(PortT[0].text); + if(isConnected()) + return true; - if (isDebug()) - IDLog("Telescope Connect returns %d\n",rc); + rc=Connect(PortT[0].text, atoi(IUFindOnSwitch(&BaudRateSP)->name)); if(rc) SetTimer(POLLMS); @@ -603,7 +879,7 @@ } -bool INDI::Telescope::Connect(const char *port) +bool INDI::Telescope::Connect(const char *port, uint16_t baud) { // We want to connect to a port // For now, we will assume it's a serial port @@ -611,9 +887,9 @@ char errorMsg[MAXRBUF]; bool rc; - DEBUGF(Logger::DBG_DEBUG, "INDI::Telescope connecting to %s\n",port); + DEBUGF(Logger::DBG_DEBUG, "INDI::Telescope connecting to %s",port); - if ( (connectrc = tty_connect(port, 9600, 8, 0, 1, &PortFD)) != TTY_OK) + if ( (connectrc = tty_connect(port, baud, 8, 0, 1, &PortFD)) != TTY_OK) { tty_error_msg(connectrc, errorMsg, MAXRBUF); @@ -623,7 +899,7 @@ } - DEBUGF(Logger::DBG_DEBUG, "Port Fd %d\n",PortFD); + DEBUGF(Logger::DBG_DEBUG, "Port FD %d",PortFD); /* Test connection */ rc=ReadScopeStatus(); @@ -663,7 +939,7 @@ if(rc == false) { // read was not good - EqNP.s=IPS_ALERT; + EqNP.s= lastEqState = IPS_ALERT; IDSetNumber(&EqNP, NULL); } @@ -674,12 +950,79 @@ bool INDI::Telescope::Park() { - // We want to park our telescope - // but the scope doesn't seem to support park - // or it wouldn't have gotten here + DEBUG(INDI::Logger::DBG_WARNING, "Parking is not supported."); return false; } +bool INDI::Telescope::UnPark() +{ + DEBUG(INDI::Logger::DBG_WARNING, "UnParking is not supported."); + return false; +} + +void INDI::Telescope::SetCurrentPark() +{ + DEBUG(INDI::Logger::DBG_WARNING, "Parking is not supported."); +} + +void INDI::Telescope::SetDefaultPark() +{ + DEBUG(INDI::Logger::DBG_WARNING, "Parking is not supported."); +} + +bool INDI::Telescope::processTimeInfo(const char *utc, const char *offset) +{ + struct ln_date utc_date; + double utc_offset=0; + + if (extractISOTime(utc, &utc_date) == -1) + { + TimeTP.s = IPS_ALERT; + IDSetText(&TimeTP, "Date/Time is invalid: %s.", utc); + return false; + } + + utc_offset = atof(offset); + + if (updateTime(&utc_date, utc_offset)) + { + IUSaveText(&TimeT[0], utc); + IUSaveText(&TimeT[1], offset); + TimeTP.s = IPS_OK; + IDSetText(&TimeTP, NULL); + return true; + } + else + { + TimeTP.s = IPS_ALERT; + IDSetText(&TimeTP, NULL); + return false; + } +} + +bool INDI::Telescope::processLocationInfo(double latitude, double longitude, double elevation) +{ + if (updateLocation(latitude, longitude, elevation)) + { + LocationNP.s=IPS_OK; + LocationN[LOCATION_LATITUDE].value = latitude; + LocationN[LOCATION_LONGITUDE].value = longitude; + LocationN[LOCATION_ELEVATION].value = elevation; + // Update client display + IDSetNumber(&LocationNP,NULL); + + return true; + } + else + { + LocationNP.s=IPS_ALERT; + // Update client display + IDSetNumber(&LocationNP,NULL); + + return false; + } +} + bool INDI::Telescope::updateTime(ln_date *utc, double utc_offset) { INDI_UNUSED(utc); @@ -702,4 +1045,493 @@ capability.canPark = cap->canPark; capability.canSync = cap->canSync; capability.canAbort = cap->canAbort; + capability.hasTime = cap->hasTime; + capability.hasLocation = cap->hasLocation; + capability.nSlewRate = cap->nSlewRate; + + if (capability.canSync) + IUFillSwitchVector(&CoordSP,CoordS,3,getDeviceName(),"ON_COORD_SET","On Set",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); + else + IUFillSwitchVector(&CoordSP,CoordS,2,getDeviceName(),"ON_COORD_SET","On Set",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); + + if (capability.nSlewRate >= 4) + { + free(SlewRateS); + SlewRateS = (ISwitch *) malloc(sizeof(ISwitch) * capability.nSlewRate); + int step = capability.nSlewRate / 4; + for (int i=0; i < capability.nSlewRate; i++) + { + char name[4]; + snprintf(name, 4, "%dx", i+1); + IUFillSwitch(SlewRateS+i, name, name, ISS_OFF); + } + + strncpy( (SlewRateS+(step*0))->name, "SLEW_GUIDE", MAXINDINAME); + strncpy( (SlewRateS+(step*1))->name, "SLEW_CENTERING", MAXINDINAME); + strncpy( (SlewRateS+(step*2))->name, "SLEW_FIND", MAXINDINAME); + strncpy( (SlewRateS+(capability.nSlewRate-1))->name, "SLEW_MAX", MAXINDINAME); + + // By Default we set current Slew Rate to 0.5 of max + (SlewRateS+(capability.nSlewRate/2))->s = ISS_ON; + + IUFillSwitchVector(&SlewRateSP, SlewRateS, capability.nSlewRate, getDeviceName(), "TELESCOPE_SLEW_RATE", "Slew Rate", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + } +} + +void INDI::Telescope::SetParkDataType(TelescopeParkData type) +{ + parkDataType = type; + + if (parkDataType != PARK_NONE) + { + switch (parkDataType) + { + case PARK_RA_DEC: + IUFillNumber(&ParkPositionN[AXIS_RA],"PARK_RA","RA (hh:mm:ss)","%010.6m",0,24,0,0); + IUFillNumber(&ParkPositionN[AXIS_DE],"PARK_DEC","DEC (dd:mm:ss)","%010.6m",-90,90,0,0); + break; + + case PARK_AZ_ALT: + IUFillNumber(&ParkPositionN[AXIS_AZ],"PARK_AZ","AZ D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0); + IUFillNumber(&ParkPositionN[AXIS_ALT],"PARK_ALT", "Alt D:M:S", "%10.6m", -90., 90.0, 0.0, 0); + break; + + case PARK_RA_DEC_ENCODER: + IUFillNumber(&ParkPositionN[AXIS_RA],"PARK_RA" ,"RA Encoder","%.0f" ,0,16777215,1,0); + IUFillNumber(&ParkPositionN[AXIS_DE],"PARK_DEC","DEC Encoder","%.0f",0,16777215,1,0); + break; + + case PARK_AZ_ALT_ENCODER: + IUFillNumber(&ParkPositionN[AXIS_RA],"PARK_AZ" ,"AZ Encoder","%.0f" ,0,16777215,1,0); + IUFillNumber(&ParkPositionN[AXIS_DE],"PARK_ALT","ALT Encoder","%.0f",0,16777215,1,0); + break; + + default: + break; + } + + IUFillNumberVector(&ParkPositionNP,ParkPositionN,2,getDeviceName(),"TELESCOPE_PARK_POSITION","Park Position", SITE_TAB,IP_RW,60,IPS_IDLE); + } +} + +void INDI::Telescope::SetParked(bool isparked) +{ + IsParked=isparked; + IUResetSwitch(&ParkSP); + if (IsParked) + { + ParkSP.s = IPS_OK; + ParkS[0].s = ISS_ON; + TrackState = SCOPE_PARKED; + DEBUG(INDI::Logger::DBG_SESSION, "Mount is parked."); + } + else + { + ParkSP.s=IPS_IDLE; + ParkS[1].s = ISS_ON; + TrackState = SCOPE_IDLE; + DEBUG(INDI::Logger::DBG_SESSION, "Mount is unparked."); + } + + IDSetSwitch(&ParkSP, NULL); + + if (parkDataType != PARK_NONE) + WriteParkData(); +} + +bool INDI::Telescope::isParked() +{ + return IsParked; +} + +bool INDI::Telescope::InitPark() +{ + char *loadres; + loadres=LoadParkData(); + if (loadres) + { + DEBUGF(INDI::Logger::DBG_SESSION, "InitPark: No Park data in file %s: %s", Parkdatafile, loadres); + SetParked(false); + return false; + } + + SetParked(isParked()); + + ParkPositionN[AXIS_RA].value = Axis1ParkPosition; + ParkPositionN[AXIS_DE].value = Axis2ParkPosition; + IDSetNumber(&ParkPositionNP, NULL); + + return true; +} + +char *INDI::Telescope::LoadParkData() +{ + wordexp_t wexp; + FILE *fp; + LilXML *lp; + static char errmsg[512]; + + XMLEle *parkxml; + XMLAtt *ap; + bool devicefound=false; + + ParkDeviceName = getDeviceName(); + ParkstatusXml=NULL; + ParkdeviceXml=NULL; + ParkpositionXml = NULL; + ParkpositionAxis1Xml = NULL; + ParkpositionAxis2Xml = NULL; + + if (wordexp(Parkdatafile, &wexp, 0)) + { + wordfree(&wexp); + return (char *)("Badly formed filename."); + } + + if (!(fp=fopen(wexp.we_wordv[0], "r"))) + { + wordfree(&wexp); + return strerror(errno); + } + wordfree(&wexp); + + lp = newLilXML(); + + if (ParkdataXmlRoot) + delXMLEle(ParkdataXmlRoot); + + ParkdataXmlRoot = readXMLFile(fp, lp, errmsg); + + delLilXML(lp); + if (!ParkdataXmlRoot) + return errmsg; + + if (!strcmp(tagXMLEle(nextXMLEle(ParkdataXmlRoot, 1)), "parkdata")) + return (char *)("Not a park data file"); + + parkxml=nextXMLEle(ParkdataXmlRoot, 1); + + while (parkxml) + { + if (strcmp(tagXMLEle(parkxml), "device")) + { + parkxml=nextXMLEle(ParkdataXmlRoot, 0); + continue; + } + ap = findXMLAtt(parkxml, "name"); + if (ap && (!strcmp(valuXMLAtt(ap), ParkDeviceName))) + { + devicefound = true; + break; + } + parkxml=nextXMLEle(ParkdataXmlRoot, 0); + } + + if (!devicefound) + return (char *)"No park data found for this device"; + + ParkdeviceXml=parkxml; + ParkstatusXml = findXMLEle(parkxml, "parkstatus"); + ParkpositionXml = findXMLEle(parkxml, "parkposition"); + ParkpositionAxis1Xml = findXMLEle(ParkpositionXml, "axis1position"); + ParkpositionAxis2Xml = findXMLEle(ParkpositionXml, "axis2position"); + IsParked=false; + + if (ParkstatusXml == NULL || ParkpositionAxis1Xml == NULL || ParkpositionAxis2Xml == NULL) + { + return (char *)("Park data invalid or missing."); + } + + if (!strcmp(pcdataXMLEle(ParkstatusXml), "true")) + IsParked=true; + + sscanf(pcdataXMLEle(ParkpositionAxis1Xml), "%lf", &Axis1ParkPosition); + sscanf(pcdataXMLEle(ParkpositionAxis2Xml), "%lf", &Axis2ParkPosition); + + return NULL; +} + +bool INDI::Telescope::WriteParkData() +{ + wordexp_t wexp; + FILE *fp; + char pcdata[30]; + ParkDeviceName = getDeviceName(); + + if (wordexp(Parkdatafile, &wexp, 0)) + { + wordfree(&wexp); + DEBUGF(INDI::Logger::DBG_SESSION, "WriteParkData: can not write file %s: Badly formed filename.", Parkdatafile); + return false; + } + + if (!(fp=fopen(wexp.we_wordv[0], "w"))) + { + wordfree(&wexp); + DEBUGF(INDI::Logger::DBG_SESSION, "WriteParkData: can not write file %s: %s", Parkdatafile, strerror(errno)); + return false; + } + + if (!ParkdataXmlRoot) + ParkdataXmlRoot=addXMLEle(NULL, "parkdata"); + + if (!ParkdeviceXml) + { + ParkdeviceXml=addXMLEle(ParkdataXmlRoot, "device"); + addXMLAtt(ParkdeviceXml, "name", ParkDeviceName); + } + + if (!ParkstatusXml) + ParkstatusXml=addXMLEle(ParkdeviceXml, "parkstatus"); + if (!ParkpositionXml) + ParkpositionXml=addXMLEle(ParkdeviceXml, "parkposition"); + if (!ParkpositionAxis1Xml) + ParkpositionAxis1Xml=addXMLEle(ParkpositionXml, "axis1position"); + if (!ParkpositionAxis2Xml) + ParkpositionAxis2Xml=addXMLEle(ParkpositionXml, "axis2position"); + + editXMLEle(ParkstatusXml, (IsParked?"true":"false")); + + snprintf(pcdata, sizeof(pcdata), "%f", Axis1ParkPosition); + editXMLEle(ParkpositionAxis1Xml, pcdata); + snprintf(pcdata, sizeof(pcdata), "%f", Axis2ParkPosition); + editXMLEle(ParkpositionAxis2Xml, pcdata); + + prXMLEle(fp, ParkdataXmlRoot, 0); + fclose(fp); + + return true; +} + +double INDI::Telescope::GetAxis1Park() +{ + return Axis1ParkPosition; +} +double INDI::Telescope::GetAxis1ParkDefault() +{ + return Axis1DefaultParkPosition; +} +double INDI::Telescope::GetAxis2Park() +{ + return Axis2ParkPosition; +} +double INDI::Telescope::GetAxis2ParkDefault() +{ + return Axis2DefaultParkPosition; +} + +void INDI::Telescope::SetAxis1Park(double value) +{ + Axis1ParkPosition=value; + ParkPositionN[AXIS_RA].value = value; + IDSetNumber(&ParkPositionNP, NULL); +} + +void INDI::Telescope::SetAxis1ParkDefault(double value) +{ + Axis1DefaultParkPosition=value; +} + +void INDI::Telescope::SetAxis2Park(double value) +{ + Axis2ParkPosition=value; + ParkPositionN[AXIS_DE].value = value; + IDSetNumber(&ParkPositionNP, NULL); +} + +void INDI::Telescope::SetAxis2ParkDefault(double value) +{ + Axis2DefaultParkPosition=value; +} + +bool INDI::Telescope::SetSlewRate(int index) +{ + INDI_UNUSED(index); + return true; +} + +void INDI::Telescope::processButton(const char *button_n, ISState state) +{ + //ignore OFF + if (state == ISS_OFF) + return; + + if (!strcmp(button_n, "ABORTBUTTON")) + { + // Only abort if we have some sort of motion going on + if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY) + { + + Abort(); + } + } + else if (!strcmp(button_n, "PARKBUTTON")) + { + ISState states[2] = { ISS_ON, ISS_OFF }; + char *names[2] = { ParkS[0].name, ParkS[1].name }; + ISNewSwitch(getDeviceName(), ParkSP.name, states, names, 2); + } + else if (!strcmp(button_n, "UNPARKBUTTON")) + { + ISState states[2] = { ISS_OFF, ISS_ON }; + char *names[2] = { ParkS[0].name, ParkS[1].name }; + ISNewSwitch(getDeviceName(), ParkSP.name, states, names, 2); + } +} + +void INDI::Telescope::processJoystick(const char * joystick_n, double mag, double angle) +{ + if (!strcmp(joystick_n, "MOTIONDIR")) + { + if ((TrackState == SCOPE_PARKING) || (TrackState == SCOPE_PARKED)) + { + DEBUG(INDI::Logger::DBG_WARNING, "Can not slew while mount is parking/parked."); + return; + } + + processNSWE(mag, angle); + } + else if (!strcmp(joystick_n, "SLEWPRESET")) + processSlewPresets(mag, angle); +} + +void INDI::Telescope::processNSWE(double mag, double angle) +{ + if (mag < 0.5) + { + // Moving in the same direction will make it stop + if (MovementNSSP.s == IPS_BUSY) + { + if (MoveNS( MovementNSSP.sp[0].s == ISS_ON ? DIRECTION_NORTH : DIRECTION_SOUTH, MOTION_STOP)) + { + IUResetSwitch(&MovementNSSP); + MovementNSSP.s = IPS_IDLE; + IDSetSwitch(&MovementNSSP, NULL); + } + else + { + MovementNSSP.s = IPS_ALERT; + IDSetSwitch(&MovementNSSP, NULL); + } + } + + if (MovementWESP.s == IPS_BUSY) + { + if (MoveWE( MovementWESP.sp[0].s == ISS_ON ? DIRECTION_WEST : DIRECTION_EAST, MOTION_STOP)) + { + IUResetSwitch(&MovementWESP); + MovementWESP.s = IPS_IDLE; + IDSetSwitch(&MovementWESP, NULL); + } + else + { + MovementWESP.s = IPS_ALERT; + IDSetSwitch(&MovementWESP, NULL); + } + } + } + // Put high threshold + else if (mag > 0.9) + { + // North + if (angle > 0 && angle < 180) + { + // Don't try to move if you're busy and moving in the same direction + if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON) + MoveNS(DIRECTION_NORTH, MOTION_START); + + // If angle is close to 90, make it exactly 90 to reduce noise that could trigger east/west motion as well + if (angle > 80 && angle < 110) + angle = 90; + + MovementNSSP.s = IPS_BUSY; + MovementNSSP.sp[DIRECTION_NORTH].s = ISS_ON; + MovementNSSP.sp[DIRECTION_SOUTH].s = ISS_OFF; + IDSetSwitch(&MovementNSSP, NULL); + } + // South + if (angle > 180 && angle < 360) + { + // Don't try to move if you're busy and moving in the same direction + if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON) + MoveNS(DIRECTION_SOUTH, MOTION_START); + + // If angle is close to 270, make it exactly 270 to reduce noise that could trigger east/west motion as well + if (angle > 260 && angle < 280) + angle = 270; + + MovementNSSP.s = IPS_BUSY; + MovementNSSP.sp[DIRECTION_NORTH].s = ISS_OFF; + MovementNSSP.sp[DIRECTION_SOUTH].s = ISS_ON; + IDSetSwitch(&MovementNSSP, NULL); + } + // East + if (angle < 90 || angle > 270) + { + // Don't try to move if you're busy and moving in the same direction + if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON) + MoveWE(DIRECTION_EAST, MOTION_START); + + MovementWESP.s = IPS_BUSY; + MovementWESP.sp[DIRECTION_WEST].s = ISS_OFF; + MovementWESP.sp[DIRECTION_EAST].s = ISS_ON; + IDSetSwitch(&MovementWESP, NULL); + } + + // West + if (angle > 90 && angle < 270) + { + + // Don't try to move if you're busy and moving in the same direction + if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON) + MoveWE(DIRECTION_WEST, MOTION_START); + + MovementWESP.s = IPS_BUSY; + MovementWESP.sp[DIRECTION_WEST].s = ISS_ON; + MovementWESP.sp[DIRECTION_EAST].s = ISS_OFF; + IDSetSwitch(&MovementWESP, NULL); + } + } +} + +void INDI::Telescope::processSlewPresets(double mag, double angle) +{ + // high threshold, only 1 is accepted + if (mag != 1) + return; + + int currentIndex = IUFindOnSwitchIndex(&SlewRateSP); + + // Up + if (angle > 0 && angle < 180) + { + if (currentIndex <= 0) + return; + + IUResetSwitch(&SlewRateSP); + SlewRateS[currentIndex-1].s = ISS_ON; + SetSlewRate(currentIndex-1); + } + // Down + else + { + if (currentIndex >= SlewRateSP.nsp-1) + return; + + IUResetSwitch(&SlewRateSP); + SlewRateS[currentIndex+1].s = ISS_ON; + SetSlewRate(currentIndex-1); + } + + IDSetSwitch(&SlewRateSP, NULL); +} + +void INDI::Telescope::joystickHelper(const char * joystick_n, double mag, double angle, void *context) +{ + static_cast(context)->processJoystick(joystick_n, mag, angle); +} + +void INDI::Telescope::buttonHelper(const char * button_n, ISState state, void *context) +{ + static_cast(context)->processButton(button_n, state); } diff -Nru libindi-1.0.0/libs/indibase/inditelescope.h libindi-1.1.0/libs/indibase/inditelescope.h --- libindi-1.0.0/libs/indibase/inditelescope.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indibase/inditelescope.h 2015-09-06 13:17:35.000000000 +0000 @@ -22,6 +22,7 @@ #include #include "defaultdevice.h" +#include "indicontroller.h" /** * \class INDI::Telescope @@ -31,25 +32,29 @@ Implementing a basic telescope driver involves the child class performing the following steps:
      +
    • The child class should define the telescope capabilities via the TelescopeCapability structure and sets in the default constructor.
    • If the telescope has additional properties, the child class should override initProperties and initilize the respective additional properties.
    • Once the parent class calls Connect(), the child class attempts to connect to the telescope and return either success of failure
    • INDI::Telescope calls updateProperties() to enable the child class to define which properties to send to the client upon connection
    • INDI::Telescope calls ReadScopeStatus() to check the link to the telescope and update its state and position. The child class should call newRaDec() whenever a new value is read from the telescope.
    • -
    • The child class should implmenet Goto() and Sync(), and Park() if applicable.
    • +
    • The child class should implmenet Goto() and Sync(), and Park()/UnPark() if applicable.
    • INDI::Telescope calls disconnect() when the client request a disconnection. The child class should remove any additional properties it defined in updateProperties() if applicable
    -\author Gerry Rozema, Jasem Mutlaq +\author Jasem Mutlaq, Gerry Rozema \see TelescopeSimulator and SynScan drivers for examples of implementations of INDI::Telescope. */ class INDI::Telescope : public INDI::DefaultDevice { - private: - public: - Telescope(); - virtual ~Telescope(); + + enum TelescopeStatus { SCOPE_IDLE, SCOPE_SLEWING, SCOPE_TRACKING, SCOPE_PARKING, SCOPE_PARKED }; + enum TelescopeMotionCommand { MOTION_START, MOTION_STOP }; + enum TelescopeSlewRate { SLEW_GUIDE, SLEW_CENTERING, SLEW_FIND, SLEW_MAX }; + enum TelescopeTrackMode { TRACK_SIDEREAL, TRACK_SOLAR, TRACK_LUNAR, TRACK_CUSTOM }; + enum TelescopeParkData { PARK_NONE, PARK_RA_DEC, PARK_AZ_ALT, PARK_RA_DEC_ENCODER, PARK_AZ_ALT_ENCODER }; + enum TelescopeLocation { LOCATION_LATITUDE, LOCATION_LONGITUDE, LOCATION_ELEVATION }; /** \struct TelescopeCapability \brief Holds the capabilities of a telescope. @@ -62,8 +67,23 @@ bool canPark; /** Can the telescope abort motion? */ bool canAbort; + /** Does the telescope have configurable date and time settings? */ + bool hasTime; + /** Does the telescope have configuration location settings? */ + bool hasLocation; + /** Number of Slew Rate options. Set to 0 if telescope does not support slew rates. The minimum required # of slew rates is 4 */ + int nSlewRate; } TelescopeCapability; + Telescope(); + virtual ~Telescope(); + + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); + virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + virtual void ISGetProperties (const char *dev); + virtual bool ISSnoopDevice(XMLEle *root); + /** * @brief GetTelescopeCapability returns the capability of the Telescope */ @@ -73,18 +93,7 @@ * @brief SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized. * @param cap pointer to Telescope capability struct. */ - void SetTelescopeCapability(TelescopeCapability * cap); - - enum TelescopeStatus { SCOPE_IDLE, SCOPE_SLEWING, SCOPE_TRACKING, SCOPE_PARKING, SCOPE_PARKED }; - enum TelescopeMotionNS { MOTION_NORTH, MOTION_SOUTH }; - enum TelescopeMotionWE { MOTION_WEST, MOTION_EAST }; - enum TelescopeMotionCommand { MOTION_START, MOTION_STOP }; - - virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); - virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); - virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); - virtual void ISGetProperties (const char *dev); - virtual bool ISSnoopDevice(XMLEle *root); + void SetTelescopeCapability(TelescopeCapability * cap); /** \brief Called to initialize basic properties required all the time */ virtual bool initProperties(); @@ -106,10 +115,89 @@ /** \brief INDI::Telescope implementation of Connect() assumes 9600 baud, 8 bit word, even parity, and no stop bit. Override function if communication paramaters are different \param port Port to connect to + \param baud Baud rate \return True if connection is successful, false otherwise \warning Do not call this function directly, it is called by INDI::Telescope Connect() function. */ - virtual bool Connect(const char *port); + virtual bool Connect(const char *port, uint16_t baud); + + + //Park + /** + * \brief setParkDataType Sets the type of parking data stored in the park data file and presented to the user. + * \param type parking data type. If PARK_NONE then no properties will be presented to the user for custom parking position. + */ + void SetParkDataType(TelescopeParkData type); + + /** + * @brief InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status + * and parking position. + * @return True if loading is successful and data is read, false otherwise. On success, you must call + * SetAxis1ParkDefault() and SetAxis2ParkDefault() to set the default parking values. On failure, you must call + * SetAxis1ParkDefault() and SetAxis2ParkDefault() to set the default parking values in addition to SetAxis1Park() + * and SetAxis2Park() to set the current parking position. + */ + bool InitPark(); + + /** + * @brief isParked is mount currently parked? + * @return True if parked, false otherwise. + */ + bool isParked(); + + /** + * @brief SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData.xml) is updated in the process. + * @param isparked set to true if parked, false otherwise. + */ + void SetParked(bool isparked); + + /** + * @return Get current RA/AZ parking position. + */ + double GetAxis1Park(); + + /** + * @return Get default RA/AZ parking position. + */ + double GetAxis1ParkDefault(); + + /** + * @return Get current DEC/ALT parking position. + */ + double GetAxis2Park(); + + /** + * @return Get defailt DEC/ALT parking position. + */ + double GetAxis2ParkDefault(); + + /** + * @brief SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData.xml) is updated in the process. + * @param value current Axis 1 value (RA or AZ either in angles or encoder values as specificed by the TelescopeParkData type). + */ + void SetAxis1Park(double value); + + /** + * @brief SetRAPark Set default RA/AZ parking position. + * @param value Default Axis 1 value (RA or AZ either in angles or encoder values as specificed by the TelescopeParkData type). + */ + void SetAxis1ParkDefault(double steps); + + /** + * @brief SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData.xml) is updated in the process. + * @param value current Axis 1 value (DEC or ALT either in angles or encoder values as specificed by the TelescopeParkData type). + */ + void SetAxis2Park(double steps); + + /** + * @brief SetDEParkDefault Set default DEC/ALT parking position. + * @param value Default Axis 2 value (DEC or ALT either in angles or encoder values as specificed by the TelescopeParkData type). + */ + void SetAxis2ParkDefault(double steps); + + // Joystick helpers + static void joystickHelper(const char * joystick_n, double mag, double angle, void *context); + static void buttonHelper(const char * button_n, ISState state, void *context); protected: @@ -147,7 +235,7 @@ \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ - virtual bool MoveNS(TelescopeMotionNS dir, TelescopeMotionCommand command); + virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command); /** \brief Move the telescope in the direction dir. \param dir direction of motion @@ -155,7 +243,7 @@ \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ - virtual bool MoveWE(TelescopeMotionWE dir, TelescopeMotionCommand command); + virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command); /** \brief Park the telescope to its home position. \return True if successful, false otherewise @@ -163,6 +251,12 @@ */ virtual bool Park(); + /** \brief Unpark the telescope if already parked. + \return True if successful, false otherewise + *\note This function defaults to return false unless subclassed by the child class. + */ + virtual bool UnPark(); + /** \brief Abort telescope motion \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class @@ -184,7 +278,35 @@ \return True if successful, false otherewise \note This function performs no action unless subclassed by the child class if required. */ - virtual bool updateLocation(double latitude, double longitude, double elevation); + virtual bool updateLocation(double latitude, double longitude, double elevation); + + /** + * @brief SetCurrentPark Set current coordinates/encoders value as the desired parking position + * \note This function performs no action unless subclassed by the child class if required. + */ + virtual void SetCurrentPark(); + + /** + * @brief SetDefaultPark Set default coordinates/encoders value as the desired parking position + * \note This function performs no action unless subclassed by the child class if required. + */ + virtual void SetDefaultPark(); + + /** + * @brief SetSlewRate Set desired slew rate index. + * @param index Index of slew rate where 0 is slowest rate and capability.nSlewRate-1 is maximum rate. + * @return True is operation successful, false otherwise. + * + * \note This function as implemented in INDI::Telescope performs no function and always return true. Only reimplement it if you need to issue a command to change the slew rate at the hardware level. Most + * telescope drivers only utilize slew rate when issuing a motion command. + */ + virtual bool SetSlewRate(int index); + + // Joystick + void processNSWE(double mag, double angle); + void processJoystick(const char * joystick_n, double mag, double angle); + void processSlewPresets(double mag, double angle); + void processButton(const char * button_n, ISState state); // Since every mount I know of actually uses a serial port for control // We put the serial helper into the base telescope class @@ -201,36 +323,88 @@ INumberVectorProperty EqNP; INumber EqN[2]; - ISwitchVectorProperty AbortSP; // Abort motion + // Abort motion + ISwitchVectorProperty AbortSP; ISwitch AbortS[1]; - ISwitchVectorProperty CoordSP; // A switch vector that stores how we should readct - ISwitch CoordS[3]; // On a coord_set message, sync, or slew + // On a coord_set message, sync, or slew + ISwitchVectorProperty CoordSP; + ISwitch CoordS[3]; - INumberVectorProperty LocationNP; // A number vector that stores lattitude and longitude + // A number vector that stores lattitude and longitude + INumberVectorProperty LocationNP; INumber LocationN[3]; - ISwitchVectorProperty ParkSP; // A Switch in the client interface to park the scope - ISwitch ParkS[1]; + // A Switch in the client interface to park the scope + ISwitchVectorProperty ParkSP; + ISwitch ParkS[2]; + + // Custom parking position + INumber ParkPositionN[2]; + INumberVectorProperty ParkPositionNP; + + // Custom parking options + ISwitch ParkOptionS[3]; + ISwitchVectorProperty ParkOptionSP; - ITextVectorProperty PortTP; // A text vector that stores out physical port name + // Device physical port + ITextVectorProperty PortTP; IText PortT[1]; - ISwitch MovementNSS[2]; // A switch for North/South motion + // A switch for North/South motion + ISwitch MovementNSS[2]; ISwitchVectorProperty MovementNSSP; - ISwitch MovementWES[2]; // A switch for West/East motion + // A switch for West/East motion + ISwitch MovementWES[2]; ISwitchVectorProperty MovementWESP; + // Slew Rate + ISwitchVectorProperty SlewRateSP; + ISwitch *SlewRateS; + + // Telescope & guider aperture and focal length INumber ScopeParametersN[4]; INumberVectorProperty ScopeParametersNP; + // UTC and UTC Offset IText TimeT[2]; ITextVectorProperty TimeTP; - TelescopeCapability capability; + // Active devices to snoop + ITextVectorProperty ActiveDeviceTP; + IText ActiveDeviceT[1]; + + ISwitch BaudRateS[6]; + ISwitchVectorProperty BaudRateSP; + + TelescopeCapability capability; int last_we_motion, last_ns_motion; + //Park + char *LoadParkData(); + bool WriteParkData(); + +private: + + bool processTimeInfo(const char *utc, const char *offset); + bool processLocationInfo(double latitude, double longitude, double elevation); + + TelescopeParkData parkDataType; + bool IsParked; + const char *ParkDeviceName; + const char * Parkdatafile; + XMLEle *ParkdataXmlRoot, *ParkdeviceXml, *ParkstatusXml, *ParkpositionXml, *ParkpositionAxis1Xml, *ParkpositionAxis2Xml; + + double Axis1ParkPosition; + double Axis1DefaultParkPosition; + double Axis2ParkPosition; + double Axis2DefaultParkPosition; + + IPState lastEqState; + + INDI::Controller *controller; + }; #endif // INDI::Telescope_H diff -Nru libindi-1.0.0/libs/indibase/indiweather.cpp libindi-1.1.0/libs/indibase/indiweather.cpp --- libindi-1.0.0/libs/indibase/indiweather.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiweather.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,464 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI Weather Device Class + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#include "indiweather.h" + +#define POLLMS 5000 +#define PARAMETERS_TAB "Parameters" + +INDI::Weather::Weather() +{ + ParametersN=NULL; + critialParametersL=NULL; + updateTimerID=-1; + + ParametersRangeNP = NULL; + nRanges=0; +} + +INDI::Weather::~Weather() +{ + for (int i=0; i < ParametersNP.nnp; i++) + { + free(ParametersN[i].aux0); + free(ParametersN[i].aux1); + free(ParametersRangeNP[i].np); + } + + free(ParametersN); + free(ParametersRangeNP); + free(critialParametersL); +} + +bool INDI::Weather::initProperties() +{ + INDI::DefaultDevice::initProperties(); + + // Parameters + IUFillNumberVector(&ParametersNP, NULL, 0, getDeviceName(), "WEATHER_PARAMETERS", "Parameters", PARAMETERS_TAB, IP_RO, 60, IPS_OK); + + // Refresh + IUFillSwitch(&RefreshS[0], "REFRESH", "Refresh", ISS_OFF); + IUFillSwitchVector(&RefreshSP, RefreshS, 1, getDeviceName(), "WEATHER_REFRESH", "Weather", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Weather Status + IUFillLightVector(&critialParametersLP, NULL, 0, getDeviceName(), "WEATHER_STATUS", "Status", MAIN_CONTROL_TAB, IPS_IDLE); + + // Location + IUFillNumber(&LocationN[LOCATION_LATITUDE],"LAT","Lat (dd:mm:ss)","%010.6m",-90,90,0,0.0); + IUFillNumber(&LocationN[LOCATION_LONGITUDE],"LONG","Lon (dd:mm:ss)","%010.6m",0,360,0,0.0 ); + IUFillNumber(&LocationN[LOCATION_ELEVATION],"ELEV","Elevation (m)","%g",-200,10000,0,0 ); + IUFillNumberVector(&LocationNP,LocationN,3,getDeviceName(),"GEOGRAPHIC_COORD","Location", SITE_TAB,IP_RW,60,IPS_OK); + + // Update Period + IUFillNumber(&UpdatePeriodN[0],"PERIOD","Period (mins)","%4.2f",0,180,10,0); + IUFillNumberVector(&UpdatePeriodNP,UpdatePeriodN,1,getDeviceName(),"WEATHER_UPDATE","Update",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); + + // Active Devices + IUFillText(&ActiveDeviceT[0],"ACTIVE_GPS","GPS","GPS Simulator"); + IUFillTextVector(&ActiveDeviceTP,ActiveDeviceT,1,getDeviceName(),"ACTIVE_DEVICES","Snoop devices",OPTIONS_TAB,IP_RW,60,IPS_IDLE); + + IDSnoopDevice(ActiveDeviceT[0].text,"GEOGRAPHIC_COORD"); + + return true; +} + +bool INDI::Weather::updateProperties() +{ + INDI::DefaultDevice::updateProperties(); + + if (isConnected()) + { + updateTimerID = -1; + + if (critialParametersL) + defineLight(&critialParametersLP); + + defineNumber(&UpdatePeriodNP); + + defineSwitch(&RefreshSP); + + if (ParametersN) + defineNumber(&ParametersNP); + + if (ParametersRangeNP) + { + for (int i=0; i < nRanges; i++) + defineNumber(&ParametersRangeNP[i]); + } + + + defineNumber(&LocationNP); + defineText(&ActiveDeviceTP); + + DEBUG(INDI::Logger::DBG_SESSION, "Weather update is in progress..."); + TimerHit(); + + } + else + { + if (critialParametersL) + deleteProperty(critialParametersLP.name); + + deleteProperty(UpdatePeriodNP.name); + + deleteProperty(RefreshSP.name); + + if (ParametersN) + deleteProperty(ParametersNP.name); + + if (ParametersRangeNP) + { + for (int i=0; i < nRanges; i++) + deleteProperty(ParametersRangeNP[i].name); + } + + deleteProperty(LocationNP.name); + + deleteProperty(ActiveDeviceTP.name); + } + + return true; +} + +bool INDI::Weather::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) +{ + if(strcmp(dev,getDeviceName())==0) + { + if (!strcmp(name, RefreshSP.name)) + { + RefreshS[0].s = ISS_OFF; + RefreshSP.s = IPS_OK; + IDSetSwitch(&RefreshSP, NULL); + + TimerHit(); + } + } + + return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n); +} + +bool INDI::Weather::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) +{ + // first check if it's for our device + if(strcmp(dev,getDeviceName())==0) + { + if(strcmp(name,"GEOGRAPHIC_COORD")==0) + { + int latindex = IUFindIndex("LAT", names, n); + int longindex= IUFindIndex("LONG", names, n); + int elevationindex = IUFindIndex("ELEV", names, n); + + if (latindex == -1 || longindex==-1 || elevationindex == -1) + { + LocationNP.s=IPS_ALERT; + IDSetNumber(&LocationNP, "Location data missing or corrupted."); + } + + double targetLat = values[latindex]; + double targetLong = values[longindex]; + double targetElev = values[elevationindex]; + + return processLocationInfo(targetLat, targetLong, targetElev); + + } + + // Update period + if(strcmp(name,"WEATHER_UPDATE")==0) + { + IUUpdateNumber(&UpdatePeriodNP, values, names, n); + + UpdatePeriodNP.s = IPS_OK; + IDSetNumber(&UpdatePeriodNP, NULL); + + if (UpdatePeriodN[0].value == 0) + DEBUG(INDI::Logger::DBG_SESSION, "Periodic updates are disabled."); + else + { + if (updateTimerID > 0) + RemoveTimer(updateTimerID); + + updateTimerID = SetTimer(UpdatePeriodN[0].value*60000); + } + + return true; + } + + for (int i=0; i < nRanges; i++) + { + if (!strcmp(name, ParametersRangeNP[i].name)) + { + IUUpdateNumber(&ParametersRangeNP[i], values, names, n); + + ParametersN[i].min = ParametersRangeNP[i].np[0].value; + ParametersN[i].max = ParametersRangeNP[i].np[1].value; + *( (double *) ParametersN[i].aux0) = ParametersRangeNP[i].np[2].value; + *( (double *) ParametersN[i].aux1) = ParametersRangeNP[i].np[3].value; + + updateWeatherState(); + + ParametersRangeNP[i].s = IPS_OK; + IDSetNumber(&ParametersRangeNP[i], NULL); + + return true; + } + } + } + + return DefaultDevice::ISNewNumber(dev,name,values,names,n); +} + + +bool INDI::Weather::ISSnoopDevice(XMLEle *root) +{ + + XMLEle *ep=NULL; + const char *propName = findXMLAttValu(root, "name"); + + if (isConnected()) + { + if (!strcmp(propName, "GEOGRAPHIC_COORD")) + { + // Only accept IPS_OK state + if (strcmp(findXMLAttValu(root, "state"), "Ok")) + return false; + + double longitude=-1, latitude=-1, elevation=-1; + + for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) + { + const char *elemName = findXMLAttValu(ep, "name"); + + if (!strcmp(elemName, "LAT")) + latitude = atof(pcdataXMLEle(ep)); + else if (!strcmp(elemName, "LONG")) + longitude = atof(pcdataXMLEle(ep)); + else if (!strcmp(elemName, "ELEV")) + elevation = atof(pcdataXMLEle(ep)); + + } + + return processLocationInfo(latitude, longitude, elevation); + } + } + + return INDI::DefaultDevice::ISSnoopDevice(root); +} + +void INDI::Weather::TimerHit() +{ + if (isConnected() == false) + return; + + if (updateTimerID > 0) + RemoveTimer(updateTimerID); + + IPState state = updateWeather(); + + switch (state) + { + // Ok + case IPS_OK: + + updateWeatherState(); + ParametersNP.s = state; + IDSetNumber(&ParametersNP, NULL); + + // If update period is set, then set up the timer + if (UpdatePeriodN[0].value > 0) + updateTimerID = SetTimer( (int) (UpdatePeriodN[0].value * 60000)); + + return; + + // Alert + case IPS_ALERT: + ParametersNP.s = state; + IDSetNumber(&ParametersNP, NULL); + return; + + // Weather update is in progress + default: + break; + } + + updateTimerID = SetTimer(POLLMS); +} + +IPState INDI::Weather::updateWeather() +{ + DEBUG(INDI::Logger::DBG_ERROR, "updateWeather() must be implemented in Weather device child class to update GEOGRAPHIC_COORD properties."); + return IPS_ALERT; +} + +bool INDI::Weather::updateLocation(double latitude, double longitude, double elevation) +{ + INDI_UNUSED(latitude); + INDI_UNUSED(longitude); + INDI_UNUSED(elevation); + + return true; +} + +bool INDI::Weather::processLocationInfo(double latitude, double longitude, double elevation) +{ + if (updateLocation(latitude, longitude, elevation)) + { + LocationNP.s=IPS_OK; + LocationN[LOCATION_LATITUDE].value = latitude; + LocationN[LOCATION_LONGITUDE].value = longitude; + LocationN[LOCATION_ELEVATION].value = elevation; + // Update client display + IDSetNumber(&LocationNP,NULL); + + return true; + } + else + { + LocationNP.s=IPS_ALERT; + // Update client display + IDSetNumber(&LocationNP,NULL); + return false; + } +} + +INumber * INDI::Weather::addParameter(std::string name, double minimumOK, double maximumOK, double minimumWarning, double maximumWarning) +{ + DEBUGF(INDI::Logger::DBG_DEBUG, "Parameter %s is added. Ok (%g,%g) Warn (%g,%g)", name.c_str(), minimumOK, maximumOK, minimumWarning, maximumWarning); + + ParametersN = (ParametersN == NULL) ? (INumber *) malloc(sizeof(INumber)) : (INumber *) realloc(ParametersN, (ParametersNP.nnp+1) * sizeof(INumber)); + + double *minWarn = (double *) malloc(sizeof(double)); + double *maxWarn = (double *) malloc(sizeof(double)); + + *minWarn = minimumWarning; + *maxWarn = maximumWarning; + + IUFillNumber(&ParametersN[ParametersNP.nnp], name.c_str(), name.c_str(), "%4.2f", minimumOK, maximumOK, 0, 0); + + ParametersN[ParametersNP.nnp].aux0 = minWarn; + ParametersN[ParametersNP.nnp].aux1 = maxWarn; + + ParametersNP.np = ParametersN; + + //createParameterRange(name); + + return &ParametersN[ParametersNP.nnp++]; +} + +ILight * INDI::Weather::setCriticalParameter(std::string param) +{ + for (int i=0; i < ParametersNP.nnp; i++) + { + if (!strcmp(ParametersN[i].name, param.c_str())) + { + critialParametersL = (critialParametersL == NULL) ? (ILight*) malloc(sizeof(ILight)) : (ILight *) realloc(critialParametersL, (critialParametersLP.nlp+1) * sizeof(ILight)); + + IUFillLight(&critialParametersL[critialParametersLP.nlp], param.c_str(), param.c_str(), IPS_IDLE); + + critialParametersLP.lp = critialParametersL; + + return &critialParametersL[critialParametersLP.nlp++]; + } + } + + DEBUGF(INDI::Logger::DBG_WARNING, "Unable to find parameter %s in list of existing parameters!", param.c_str()); + return NULL; + +} + +void INDI::Weather::updateWeatherState() +{ + if (critialParametersL == NULL) + return; + + critialParametersLP.s = IPS_IDLE; + + for (int i=0; i < critialParametersLP.nlp; i++) + { + for (int j=0; j < ParametersNP.nnp; j++) + { + if (!strcmp(critialParametersL[i].name, ParametersN[j].name)) + { + double minWarn = *(static_cast(ParametersN[j].aux0)); + double maxWarn = *(static_cast(ParametersN[j].aux1)); + + if ( (ParametersN[j].value >= ParametersN[j].min) && (ParametersN[i].value <= ParametersN[j].max) ) + critialParametersL[i].s = IPS_OK; + else if ( (ParametersN[j].value >= minWarn) && (ParametersN[j].value <= maxWarn) ) + { + critialParametersL[i].s = IPS_BUSY; + DEBUGF(INDI::Logger::DBG_WARNING, "Warning: Parameter %s value (%g) is in the warning zone!", ParametersN[j].name, ParametersN[j].value); + } + else + { + critialParametersL[i].s = IPS_ALERT; + DEBUGF(INDI::Logger::DBG_WARNING, "Caution: Parameter %s value (%g) is in the danger zone!", ParametersN[j].name, ParametersN[j].value); + } + break; + } + } + + // The overall state is the worst individual state. + if (critialParametersL[i].s > critialParametersLP.s) + critialParametersLP.s = critialParametersL[i].s; + } + + IDSetLight(&critialParametersLP, NULL); +} + +void INDI::Weather::syncParameters() +{ + for (int i=0; i < ParametersNP.nnp; i++) + createParameterRange(ParametersN[i].name); +} + +void INDI::Weather::createParameterRange(std::string param) +{ + ParametersRangeNP = (ParametersRangeNP == NULL) ? (INumberVectorProperty *) malloc(sizeof(INumberVectorProperty)) : (INumberVectorProperty *) realloc(ParametersRangeNP, (nRanges+1) * sizeof(INumberVectorProperty)); + + INumber *rangesN = (INumber *) malloc(sizeof(INumber)*4); + + IUFillNumber(&rangesN[0], "MIN_OK", "Min OK", "%4.2f", -1e6, 1e6, 0, ParametersN[nRanges].min); + IUFillNumber(&rangesN[1], "MAX_OK", "Max OK", "%4.2f", -1e6, 1e6, 0, ParametersN[nRanges].max); + IUFillNumber(&rangesN[2], "MIN_WARN", "Min Warn", "%4.2f", -1e6, 1e6, 0, *( (double *) ParametersN[nRanges].aux0)); + IUFillNumber(&rangesN[3], "MAX_WARN", "Max Warn", "%4.2f", -1e6, 1e6, 0, *( (double *) ParametersN[nRanges].aux1)); + + char propName[MAXINDINAME]; + snprintf(propName, MAXINDINAME, "%s Range", param.c_str()); + + IUFillNumberVector(&ParametersRangeNP[nRanges], rangesN, 4, getDeviceName(), propName, propName, PARAMETERS_TAB, IP_RW, 60, IPS_IDLE); + + nRanges++; + +} + +bool INDI::Weather::saveConfigItems(FILE *fp) +{ + INDI::DefaultDevice::saveConfigItems(fp); + + for (int i=0; i < nRanges; i++) + IUSaveConfigNumber(fp, &ParametersRangeNP[i]); + + return true; +} diff -Nru libindi-1.0.0/libs/indibase/indiweather.h libindi-1.1.0/libs/indibase/indiweather.h --- libindi-1.0.0/libs/indibase/indiweather.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/indibase/indiweather.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,148 @@ +/******************************************************************************* + Copyright(c) 2015 Jasem Mutlaq. All rights reserved. + + INDI Weather Device Class + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program 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 General Public License for + more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + The full GNU General Public License is included in this distribution in the + file called LICENSE. +*******************************************************************************/ + +#ifndef INDIWEATHER_H +#define INDIWEATHER_H + +#include +#include + +/** + * \class INDI::Weather + \brief Class to provide general functionality of a weather device. + + The INDI::Weather provides a simple interface for weather devices. Parameters such as temperature, wind, humidity..etc can be added by the child class + as supported by the physical device. With each parameter, the caller specifies the minimum and maximum ranges of OK and WARNING zones. Any value outside of + the warning zone is automatically treated as ALERT. + + The class also specifies the list of critical parameters for observatory operations. When any of the parameters changes state to WARNING or ALERT, then + the overall state of the WEATHER_STATUS propery reflects the worst state of any individual parameter. + + \e IMPORTANT: GEOGRAPHIC_COORD stores latitude and longitude in INDI specific format, refer to INDI Standard Properties for details. + +\author Jasem Mutlaq +*/ +class INDI::Weather : public INDI::DefaultDevice +{ + public: + + enum WeatherLocation { LOCATION_LATITUDE, LOCATION_LONGITUDE, LOCATION_ELEVATION }; + + Weather(); + virtual ~Weather(); + + virtual bool initProperties(); + virtual bool updateProperties(); + virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); + virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); + + virtual bool ISSnoopDevice(XMLEle *root); + + protected: + + /** + * @brief updateWeather Update weather conditions from device or service. The function should not change the state of any property in the device as this is handled by INDI::Weather. It should only update + * the raw values. + * @return Return overall state. The state should be IPS_OK if data is valid. IPS_BUSY if weather update is in progress. IPS_ALERT is there is an error. The clients will only accept values with IPS_OK state. + */ + virtual IPState updateWeather(); + + /** + * @brief TimerHit Keep calling updateWeather() until it is successfull, if it fails upon first connection. + */ + virtual void TimerHit(); + + /** \brief Update telescope location settings + * \param latitude Site latitude in degrees. + * \param longitude Site latitude in degrees increasing eastward from Greenwich (0 to 360). + * \param elevation Site elevation in meters. + \return True if successful, false otherewise + \note This function performs no action unless subclassed by the child class if required. + */ + virtual bool updateLocation(double latitude, double longitude, double elevation); + + /** + * @brief addParameter Add a physical weather measurable parameter to the weather driver. The weather value has three zones: + *
      + *
    1. OK: Set minimum and maximum values for acceptable values.
    2. + *
    3. Warning: Set minimum and maximum values for values outside of Ok range and in the dangerous warning zone.
    4. + *
    5. Alert: Any value outsize of Ok and Warning zone is marked as Alert.
    6. + *
    + * @param name Name of parameter + * @param minimumOK Minimum OK value. + * @param maximumOK Maximum OK value. + * @param minimumWarning Minimum Warning value. + * @param maximumWarning Maximum Warning value. + * @return Pointer to created parameter. + */ + INumber * addParameter(std::string name, double minimumOK, double maximumOK, double minimumWarning, double maximumWarning); + + /** + * @brief setCriticalParameter Set parameter that is considered critical to the operation of the observatory. The parameter state can + * affect the overall weather driver state which signals the client to take appropiate action depending on the severity of the state. + * @param param Name of critial parameter. + * @return Pointer to created critical parameter light property. + */ + ILight * setCriticalParameter(std::string param); + + virtual bool saveConfigItems(FILE *fp); + + void syncParameters(); + + // A number vector that stores lattitude and longitude + INumberVectorProperty LocationNP; + INumber LocationN[3]; + + // Refresh data + ISwitch RefreshS[1]; + ISwitchVectorProperty RefreshSP; + + // Parameters + INumber *ParametersN; + INumberVectorProperty ParametersNP; + + // Parameter Ranges + INumberVectorProperty *ParametersRangeNP; + uint8_t nRanges; + + // Weather status + ILight *critialParametersL; + ILightVectorProperty critialParametersLP; + + // Active devices to snoop + ITextVectorProperty ActiveDeviceTP; + IText ActiveDeviceT[1]; + + // Update Period + INumber UpdatePeriodN[1]; + INumberVectorProperty UpdatePeriodNP; + +private: + bool processLocationInfo(double latitude, double longitude, double elevation); + void createParameterRange(std::string param); + void updateWeatherState(); + int updateTimerID; +}; + +#endif // INDIWeather_H diff -Nru libindi-1.0.0/libs/indicom.c libindi-1.1.0/libs/indicom.c --- libindi-1.0.0/libs/indicom.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indicom.c 2015-09-06 13:17:35.000000000 +0000 @@ -32,6 +32,7 @@ #include #include #include +#include #if defined(BSD) && !defined(__GNU__) #include @@ -39,12 +40,11 @@ #endif #include - -#ifdef HAVE_NOVA_H #include -#endif - +#include #include "indicom.h" +#include "indidevapi.h" + #ifdef _WIN32 #undef CX #undef CY @@ -59,15 +59,10 @@ #define MAXRBUF 2048 -#include "indidevapi.h" - int tty_debug = 0; -void getSexComponents(double value, int *d, int *m, int *s); - -int extractISOTime(char *timestr, struct ln_date *iso_date) +int extractISOTime(const char *timestr, struct ln_date *iso_date) { - #ifdef HAVE_NOVA_H struct tm utm; if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm)) @@ -81,7 +76,6 @@ ln_get_date_from_tm(&utm, iso_date); return (0); } - #endif return (-1); } @@ -95,9 +89,7 @@ * 3600: :mm:ss * 600: :mm.m * 60: :mm - * return number of characters written to out, not counting finaif (NOVA_FOUND) - include_directories(${NOVA_INCLUDE_DIR}) -endif (NOVA_FOUND)l '\0'. + * return number of characters written to out, not counting final '\0'. */ int fs_sexa (char *out, double a, int w, int fracbase) @@ -122,33 +114,33 @@ /* form the whole part; "negative 0" is a special case */ if (isneg && d == 0) - out += sprintf (out, "%*s-0", w-2, ""); + out += snprintf (out, MAXINDIFORMAT, "%*s-0", w-2, ""); else - out += sprintf (out, "%*d", w, isneg ? -d : d); + out += snprintf (out, MAXINDIFORMAT, "%*d", w, isneg ? -d : d); /* do the rest */ switch (fracbase) { case 60: /* dd:mm */ m = f/(fracbase/60); - out += sprintf (out, ":%02d", m); + out += snprintf (out, MAXINDIFORMAT, ":%02d", m); break; case 600: /* dd:mm.m */ - out += sprintf (out, ":%02d.%1d", f/10, f%10); + out += snprintf (out, MAXINDIFORMAT, ":%02d.%1d", f/10, f%10); break; case 3600: /* dd:mm:ss */ m = f/(fracbase/60); s = f%(fracbase/60); - out += sprintf (out, ":%02d:%02d", m, s); + out += snprintf (out, MAXINDIFORMAT, ":%02d:%02d", m, s); break; case 36000: /* dd:mm:ss.s*/ m = f/(fracbase/60); s = f%(fracbase/60); - out += sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10); + out += snprintf (out, MAXINDIFORMAT, ":%02d:%02d.%1d", m, s/10, s%10); break; case 360000: /* dd:mm:ss.ss */ m = f/(fracbase/60); s = f%(fracbase/60); - out += sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100); + out += snprintf (out, MAXINDIFORMAT, ":%02d:%02d.%02d", m, s/100, s%100); break; default: printf ("fs_sexa: unknown fracbase: %d\n", fracbase); @@ -168,6 +160,8 @@ const char *str0, /* input string */ double *dp) /* cracked value, if return 0 */ { + setlocale(LC_NUMERIC,"C"); + double a = 0, b = 0, c = 0; char str[128]; char *neg; @@ -180,7 +174,17 @@ neg = strchr(str, '-'); if (neg) *neg = ' '; - r = sscanf (str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c); + // JM 2015-09-04 Search for decimal point, and if found, process it + if (strchr(str, '.')) + { + r = sscanf (str, "%lf%*[^0-9]%lf", &a, &b); + c=0; + } + else + r = sscanf (str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c); + + setlocale(LC_NUMERIC,""); + if (r < 1) return (-1); *dp = a + b/60 + c/3600; @@ -192,9 +196,9 @@ void getSexComponents(double value, int *d, int *m, int *s) { - *d = (int) fabs(value); - *m = (int) ((fabs(value) - *d) * 60.0); - *s = (int) rint(((fabs(value) - *d) * 60.0 - *m) *60.0); + *d = (int32_t) fabs(value); + *m = (int32_t) ((fabs(value) - *d) * 60.0); + *s = (int32_t) rint(((fabs(value) - *d) * 60.0 - *m) *60.0); if (value < 0) *d *= -1; @@ -219,7 +223,7 @@ return (fs_sexa (buf, value, w-f, s)); } else { /* normal printf format */ - return (sprintf (buf, format, value)); + return (snprintf (buf, MAXINDIFORMAT, format, value)); } } @@ -294,17 +298,24 @@ int bytes_w = 0; *nbytes_written = 0; - + + if (tty_debug) + { + int i=0; + for (i=0; i < nbytes; i++) + IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char) buf[i], buf[i]); + } + while (nbytes > 0) { - bytes_w = write(fd, buf, nbytes); + bytes_w = write(fd, buf+(*nbytes_written), nbytes); if (bytes_w < 0) return TTY_WRITE_ERROR; *nbytes_written += bytes_w; - buf += bytes_w; + //buf += bytes_w; nbytes -= bytes_w; } @@ -322,16 +333,23 @@ nbytes = strlen(buf); + if (tty_debug) + { + int i=0; + for (i=0; i < nbytes; i++) + IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char) buf[i], buf[i]); + } + while (nbytes > 0) { - bytes_w = write(fd, buf, nbytes); + bytes_w = write(fd, buf+(*nbytes_written), nbytes); if (bytes_w < 0) return TTY_WRITE_ERROR; *nbytes_written += bytes_w; - buf += bytes_w; + //buf += bytes_w; nbytes -= bytes_w; } @@ -358,21 +376,22 @@ if ( (err = tty_timeout(fd, timeout)) ) return err; - bytesRead = read(fd, buf, ((unsigned) nbytes)); + bytesRead = read(fd, buf+(*nbytes_read), ((uint32_t) nbytes)); if (bytesRead < 0 ) return TTY_READ_ERROR; - buf += bytesRead; - *nbytes_read += bytesRead; - nbytes -= bytesRead; - if (tty_debug) { + IDLog("%d bytes read and %d bytes remaining...\n", bytesRead, nbytes-bytesRead); int i=0; - for (i=0; i < (nbytes+*nbytes_read); i++) - IDLog("%s: buffer[%d]=%c\n", __FUNCTION__, i, buf[i]); + for (i=*nbytes_read; i < (*nbytes_read+bytesRead); i++) + IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, i, (unsigned char) buf[i], buf[i]); } + + *nbytes_read += bytesRead; + nbytes -= bytesRead; + } return TTY_OK; @@ -387,6 +406,8 @@ int err = TTY_OK; *nbytes_read = 0; + uint8_t *read_char = 0; + if (tty_debug) IDLog("%s: Request to read until stop char '%c' with %d timeout for fd %d\n", __FUNCTION__, stop_char, timeout, fd); @@ -395,22 +416,19 @@ if ( (err = tty_timeout(fd, timeout)) ) return err; - bytesRead = read(fd, buf, 1); + read_char = buf+*nbytes_read; + bytesRead = read(fd, read_char, 1); if (bytesRead < 0 ) return TTY_READ_ERROR; if (tty_debug) - IDLog("%s: buffer[%d]=%c\n", __FUNCTION__, (*nbytes_read), buf[(*nbytes_read)]); + IDLog("%s: buffer[%d]=%#X (%c)\n", __FUNCTION__, (*nbytes_read), *read_char, *read_char); - if (bytesRead) (*nbytes_read)++; - if (*buf == stop_char) + if (*read_char == stop_char) return TTY_OK; - - buf += bytesRead; - } return TTY_TIME_OUT; @@ -1215,3 +1233,59 @@ /* copy in fresh string */ tp->text = strcpy (realloc (tp->text, strlen(newtext)+1), newtext); } + +double rangeHA(double r) +{ + double res = r; + while (res< -12.0) res+=24.0; + while (res>= 12.0) res-=24.0; + return res; +} + + +double range24(double r) +{ + double res = r; + while (res<0.0) res+=24.0; + while (res>24.0) res-=24.0; + return res; +} + +double range360(double r) +{ + double res = r; + while (res<0.0) res+=360.0; + while (res>360.0) res-=360.0; + return res; +} + +double rangeDec(double decdegrees) +{ + if ((decdegrees >= 270.0) && (decdegrees <= 360.0)) + return (decdegrees - 360.0); + if ((decdegrees >= 180.0) && (decdegrees < 270.0)) + return (180.0 - decdegrees); + if ((decdegrees >= 90.0) && (decdegrees < 180.0)) + return (180.0 - decdegrees); + return decdegrees; +} + +double get_local_sideral_time(double longitude) +{ + double SD = ln_get_apparent_sidereal_time(ln_get_julian_from_sys()) - (360.0 - longitude)/15.0; + + return range24(SD); +} + +double get_local_hour_angle(double sideral_time, double ra) +{ + + double HA = sideral_time - ra; + + if (HA > 12) + HA -= 12; + else if (HA < -12) + HA += 12; + + return HA; +} diff -Nru libindi-1.0.0/libs/indicom.h libindi-1.1.0/libs/indicom.h --- libindi-1.0.0/libs/indicom.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/indicom.h 2015-09-06 13:17:35.000000000 +0000 @@ -179,7 +179,7 @@ \param iso_date a pointer to a \e ln_date structure to store the extracted time and date (libnova). \return 0 on success, -1 on failure. */ -int extractISOTime(char *timestr, struct ln_date *iso_date); +int extractISOTime(const char *timestr, struct ln_date *iso_date); void getSexComponents(double value, int *d, int *m, int *s); @@ -188,6 +188,8 @@ \param format format in sprintf style. \param value the number to format. \return length of string. + + \note buf must be of length MAXINDIFORMAT at minimum */ int numberFormat (char *buf, const char *format, double value); @@ -196,6 +198,49 @@ */ const char *timestamp (void); +/** + * @brief rangeHA Limits the hour angle value to be between -12 ---> 12 + * @param r current hour angle value + * @return Limited value (-12,12) + */ +double rangeHA(double r); + +/** + * @brief range24 Limits a number to be between 0-24 range. + * @param r number to be limited + * @return Limited number + */ +double range24(double r); + +/** + * @brief range360 Limits an angle to be between 0-360 degrees. + * @param r angle + * @return Limited angle + */ +double range360(double r); + +/** + * @brief rangeDec Limits declination value to be in -90 to 90 range. + * @param r declination angle + * @return limited declination + */ +double rangeDec(double r); + +/** + * @brief get_local_sideral_time Returns local sideral time given longitude and system clock. + * @param longitude Longitude in INDI format (0 to 360) increasing eastward. + * @return Local Sideral Time. + */ +double get_local_sideral_time(double longitude); + +/** + * @brief get_local_hour_angle Returns local hour angle of an object + * @param local_sideral_time Local Sideral Time + * @param ra RA of object + * @return Hour angle in hours (-12 to 12) + */ +double get_local_hour_angle(double local_sideral_time, double ra); + /*@}*/ #ifdef __cplusplus diff -Nru libindi-1.0.0/libs/lx/Lx.cpp libindi-1.1.0/libs/lx/Lx.cpp --- libindi-1.0.0/libs/lx/Lx.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/lx/Lx.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -87,11 +87,15 @@ IUFillSwitch(&LxSerialAddeolS[2], "LF (0xA, \\n)", "", ISS_OFF); IUFillSwitch(&LxSerialAddeolS[3], "CR+LF", "", ISS_OFF); IUFillSwitchVector(&LxSerialAddeolSP, LxSerialAddeolS, NARRAY(LxSerialAddeolS), device_name, "Add EOL", "", LX_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); + FlashStrobeSP=NULL; + FlashStrobeStopSP=NULL; + ledmethod=PWCIOCTL; return true; } bool Lx::updateProperties() { if (dev->isConnected()) { + INDI::Property *pfound; dev->defineSwitch(&LxEnableSP); dev->defineSwitch(&LxModeSP); dev->defineText(&LxPortTP); @@ -104,6 +108,12 @@ dev->defineSwitch(&LxSerialParitySP); dev->defineSwitch(&LxSerialStopSP); dev->defineSwitch(&LxSerialAddeolSP); + pfound=findbyLabel(dev, (char *)"Strobe"); + if (pfound) { + FlashStrobeSP=dev->getSwitch(pfound->getName()); + pfound=findbyLabel(dev, (char *)"Stop Strobe"); + FlashStrobeStopSP=dev->getSwitch(pfound->getName()); + } } else { dev->deleteProperty(LxEnableSP.name); dev->deleteProperty(LxModeSP.name); @@ -117,6 +127,8 @@ dev->deleteProperty(LxSerialParitySP.name); dev->deleteProperty(LxSerialStopSP.name); dev->deleteProperty(LxSerialAddeolSP.name); + FlashStrobeSP=NULL; + FlashStrobeStopSP=NULL; } return true; } @@ -437,6 +449,7 @@ case 2: return "\n"; case 3: return "\r\n"; } + return NULL; } bool Lx::startLxSerial() { @@ -501,10 +514,24 @@ return 0; } +INDI::Property *Lx::findbyLabel(INDI::DefaultDevice *dev, char *label) { + std::vector< INDI::Property * > *allprops=dev->getProperties(); + + for (std::vector< INDI::Property *>::iterator it = allprops->begin() ; it != allprops->end(); ++it) { + if (!(strcmp((*it)->getLabel(), label))) + return *it; + } + return NULL; +} // PWC Stuff -bool Lx::checkPWC() { +bool Lx::checkPWC() { + if (FlashStrobeSP && FlashStrobeStopSP) { + IDMessage(device_name, "Using Flash control for led Lx Mode"); + ledmethod=FLASHLED; + return true; + } if (ioctl(camerafd, VIDIOCPWCPROBE, &probe) != 0) { IDMessage(device_name, "ERROR: device does not support PWC ioctl"); return false; @@ -513,7 +540,7 @@ IDMessage(device_name, "ERROR: camera type %d does not support led control", probe.type); return false; } - + IDMessage(device_name, "Using PWC ioctl for led Lx Mode"); return true; } @@ -527,18 +554,58 @@ } } +void Lx::pwcsetflashon() { + ISState states[2]={ISS_ON, ISS_OFF}; + const char *names[2]={FlashStrobeSP->sp[0].name, FlashStrobeStopSP->sp[0].name}; + dev->ISNewSwitch(device_name, FlashStrobeSP->name, &(states[0]), (char **)names, 1); + //dev->ISNewSwitch(device_name, FlashStrobeStopSP->name, &(states[1]), (char **)(names + 1), 1); + FlashStrobeSP->s = IPS_OK; + IDSetSwitch(FlashStrobeSP, NULL); + FlashStrobeStopSP->s = IPS_IDLE; + IDSetSwitch(FlashStrobeStopSP, NULL); +} + +void Lx::pwcsetflashoff() { + ISState states[2]={ISS_OFF, ISS_ON}; + const char *names[2]={FlashStrobeSP->sp[0].name, FlashStrobeStopSP->sp[0].name}; + //dev->ISNewSwitch(device_name, FlashStrobeSP->name, &(states[0]), (char **)names, 1); + dev->ISNewSwitch(device_name, FlashStrobeStopSP->name, &(states[1]), (char **)(names + 1), 1); + FlashStrobeStopSP->s = IPS_OK; + IDSetSwitch(FlashStrobeStopSP, NULL); + FlashStrobeSP->s = IPS_IDLE; + IDSetSwitch(FlashStrobeSP, NULL); +} + bool Lx::startLxPWC() { - if (LxLogicalLevelS[0].s == ISS_ON) - pwcsetLed(25500, 0); - else - pwcsetLed(0,25500); - return true; + switch (ledmethod) { + case PWCIOCTL: + if (LxLogicalLevelS[0].s == ISS_ON) + pwcsetLed(25500, 0); + else + pwcsetLed(0,25500); + return true; + case FLASHLED: + if (LxLogicalLevelS[0].s == ISS_ON) + pwcsetflashon(); + else + pwcsetflashoff(); + return true; + } } int Lx::stopLxPWC() { - if (LxLogicalLevelS[0].s == ISS_ON) - pwcsetLed(0,25500); - else - pwcsetLed(25500, 0); - return 0; + switch (ledmethod) { + case PWCIOCTL: + if (LxLogicalLevelS[0].s == ISS_ON) + pwcsetLed(0,25500); + else + pwcsetLed(25500, 0); + return 0; + case FLASHLED: + if (LxLogicalLevelS[0].s == ISS_ON) + pwcsetflashoff(); + else + pwcsetflashon(); + return 0; + } } diff -Nru libindi-1.0.0/libs/lx/Lx.h libindi-1.1.0/libs/lx/Lx.h --- libindi-1.0.0/libs/lx/Lx.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/lx/Lx.h 2015-09-06 13:17:35.000000000 +0000 @@ -76,11 +76,17 @@ int stopLxSerial(); void getSerialOptions(unsigned int *speed, unsigned int *wordsize, unsigned int *parity, unsigned int *stops); const char * getSerialEOL(); - +INDI::Property *findbyLabel(INDI::DefaultDevice *dev, char *label); // PWC Cameras +ISwitchVectorProperty *FlashStrobeSP; +ISwitchVectorProperty *FlashStrobeStopSP; +enum pwcledmethod { PWCIOCTL, FLASHLED }; +char ledmethod; struct pwc_probe probe; bool checkPWC(); void pwcsetLed(int on, int off); +void pwcsetflashon(); +void pwcsetflashoff(); bool startLxPWC(); int stopLxPWC(); }; diff -Nru libindi-1.0.0/libs/webcam/ccvt.h libindi-1.1.0/libs/webcam/ccvt.h --- libindi-1.0.0/libs/webcam/ccvt.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/ccvt.h 2015-09-06 13:17:35.000000000 +0000 @@ -55,69 +55,92 @@ extern "C" { #endif -/* Colour ConVerT: going from one colour space to another. - ** NOTE: the set of available functions is far from complete! ** - - Format descriptions: - 420i = "4:2:0 interlaced" - YYYY UU YYYY UU even lines - YYYY VV YYYY VV odd lines - U/V data is subsampled by 2 both in horizontal - and vertical directions, and intermixed with the Y values. +/** + * \defgroup colorSpace Color space conversion functions + Colour ConVerT: going from one colour space to another. + + Format descriptions:\n + 420i = "4:2:0 interlaced"\n + YYYY UU YYYY UU even lines\n + YYYY VV YYYY VV odd lines\n + U/V data is subsampled by 2 both in horizontal and vertical directions, and intermixed with the Y values.\n\n - 420p = "4:2:0 planar" - YYYYYYYY N lines - UUUU N/2 lines - VVVV N/2 lines - U/V is again subsampled, but all the Ys, Us and Vs are placed - together in separate buffers. The buffers may be placed in - one piece of contiguous memory though, with Y buffer first, + 420p = "4:2:0 planar"\n + YYYYYYYY N lines\n + UUUU N/2 lines\n + VVVV N/2 lines\n + U/V is again subsampled, but all the Ys, Us and Vs are placed together in separate buffers. The buffers may be placed in one piece of contiguous memory though, with Y buffer first, followed by U, followed by V. - yuyv = "4:2:2 interlaced" - YUYV YUYV YUYV ... N lines - The U/V data is subsampled by 2 in horizontal direction only. - - bgr24 = 3 bytes per pixel, in the order Blue Green Red (whoever came up - with that idea...) - rgb24 = 3 bytes per pixel, in the order Red Green Blue (which is sensible) - rgb32 = 4 bytes per pixel, in the order Red Green Blue Alpha, with - Alpha really being a filler byte (0) - bgr32 = last but not least, 4 bytes per pixel, in the order Blue Green Red - Alpha, Alpha again a filler byte (0) + yuyv = "4:2:2 interlaced"\n + YUYV YUYV YUYV ... N lines\n + The U/V data is subsampled by 2 in horizontal direction only.\n\n + + bgr24 = 3 bytes per pixel, in the order Blue Green Red (whoever came up with that idea...)\n + rgb24 = 3 bytes per pixel, in the order Red Green Blue (which is sensible)\n + rgb32 = 4 bytes per pixel, in the order Red Green Blue Alpha, with Alpha really being a filler byte (0)\n + bgr32 = last but not least, 4 bytes per pixel, in the order Blue Green Red Alpha, Alpha again a filler byte (0)\n */ -/* 4:2:0 YUV planar to RGB/BGR */ +/*@{*/ + +/** 4:2:0 YUV planar to RGB/BGR */ void ccvt_420p_bgr24(int width, int height, const void *src, void *dst); +/** 4:2:0 YUV planar to RGB/BGR */ void ccvt_420p_rgb24(int width, int height, const void *src, void *dst); +/** 4:2:0 YUV planar to RGB/BGR */ void ccvt_420p_bgr32(int width, int height, const void *src, void *dst); +/** 4:2:0 YUV planar to RGB/BGR */ void ccvt_420p_rgb32(int width, int height, const void *src, void *dst); -/* 4:2:2 YUYV interlaced to RGB/BGR */ +/** 4:2:2 YUYV interlaced to RGB/BGR */ void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst); +/** 4:2:2 YUYV interlaced to RGB/BGR */ void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst); -/* 4:2:2 YUYV interlaced to 4:2:0 YUV planar */ +/** 4:2:2 YUYV interlaced to 4:2:0 YUV planar */ void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); /* RGB/BGR to 4:2:0 YUV interlaced */ -/* RGB/BGR to 4:2:0 YUV planar */ +/** RGB/BGR to 4:2:0 YUV planar */ void ccvt_rgb24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); +/** RGB/BGR to 4:2:0 YUV planar */ void ccvt_bgr24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); -/* RGB/BGR to RGB/BGR */ +/** RGB/BGR to RGB/BGR */ void ccvt_bgr24_bgr32(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_bgr24_rgb32(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_bgr32_bgr24(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_bgr32_rgb24(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_rgb24_bgr32(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_rgb24_rgb32(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_rgb32_bgr24(int width, int height, const void *const src, void *const dst); +/** RGB/BGR to RGB/BGR */ void ccvt_rgb32_rgb24(int width, int height, const void *const src, void *const dst); +/** RGB to YUV */ int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip); +/** + * @short mjpegtoyuv420p MPEG to YUV 420 P + * + * Return values + * -1 on fatal error + * 0 on success + * 2 if jpeg lib threw a "corrupt jpeg data" warning. + * in this case, "a damaged output image is likely." + * + * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) + * 2006 by Krzysztof Blaszkowski (kb@sysmikro.com.pl) + * 2007 by Angel Carpinteo (ack@telefonica.net) + */ int mjpegtoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height, unsigned int size); /* @@ -148,10 +171,15 @@ * SUCH DAMAGE. */ +/** Bayer 8bit to RGB 24 */ void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); +/** Bayer 16 bit to RGB 24 */ void bayer16_2_rgb24(unsigned short *dst, unsigned short *src, long int WIDTH, long int HEIGHT); +/** Bayer RGGB to RGB 24 */ void bayer_rggb_2rgb24(unsigned char *dst, unsigned char *srcc, long int WIDTH, long int HEIGHT); +/*@}*/ + #ifdef __cplusplus } #endif diff -Nru libindi-1.0.0/libs/webcam/ccvt_misc.c libindi-1.1.0/libs/webcam/ccvt_misc.c --- libindi-1.0.0/libs/webcam/ccvt_misc.c 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/ccvt_misc.c 2015-09-06 13:17:35.000000000 +0000 @@ -382,20 +382,6 @@ } -/* - * mjpegtoyuv420p - * - * Return values - * -1 on fatal error - * 0 on success - * 2 if jpeg lib threw a "corrupt jpeg data" warning. - * in this case, "a damaged output image is likely." - * - * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) - * 2006 by Krzysztof Blaszkowski (kb@sysmikro.com.pl) - * 2007 by Angel Carpinteo (ack@telefonica.net) - */ - int mjpegtoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height, unsigned int size) { unsigned char *yuv[3]; diff -Nru libindi-1.0.0/libs/webcam/jpegutils.h libindi-1.1.0/libs/webcam/jpegutils.h --- libindi-1.0.0/libs/webcam/jpegutils.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/jpegutils.h 2015-09-06 13:17:35.000000000 +0000 @@ -11,50 +11,65 @@ #ifndef __JPEGUTILS_H__ #define __JPEGUTILS_H__ - /* - * jpeg_data: buffer with input / output jpeg - * len: Length of jpeg buffer - * itype: Y4M_ILACE_NONE: Not interlaced - * Y4M_ILACE_TOP_FIRST: Interlaced, top-field-first - * Y4M_ILACE_BOTTOM_FIRST: Interlaced, bottom-field-first - * ctype Chroma format for decompression. - * Currently always 420 and hence ignored. - * raw0 buffer with input / output raw Y channel - * raw1 buffer with input / output raw U/Cb channel - * raw2 buffer with input / output raw V/Cr channel - * width width of Y channel (width of U/V is width/2) - * height height of Y channel (height of U/V is height/2) +/** + * \defgroup jpegSpace Functions to encode and decode JPEG + + jpeg_data: buffer with input / output jpeg\n + len: Length of jpeg buffer\n + itype: Y4M_ILACE_NONE: Not interlaced\n + Y4M_ILACE_TOP_FIRST: Interlaced, top-field-first\n + Y4M_ILACE_BOTTOM_FIRST: Interlaced, bottom-field-first\n + ctype Chroma format for decompression.\n + Currently always 420 and hence ignored.\n + raw0 buffer with input / output raw Y channel\n + raw1 buffer with input / output raw U/Cb channel\n + raw2 buffer with input / output raw V/Cr channel\n + width width of Y channel (width of U/V is width/2)\n + height height of Y channel (height of U/V is height/2)\n */ +/*@{*/ -#define Y4M_ILACE_NONE 0 /* non-interlaced, progressive frame */ -#define Y4M_ILACE_TOP_FIRST 1 /* interlaced, top-field first */ -#define Y4M_ILACE_BOTTOM_FIRST 2 /* interlaced, bottom-field first */ -#define Y4M_ILACE_MIXED 3 /* mixed, "refer to frame header" */ - -#define Y4M_CHROMA_420JPEG 0 /* 4:2:0, H/V centered, for JPEG/MPEG-1 */ -#define Y4M_CHROMA_420MPEG2 1 /* 4:2:0, H cosited, for MPEG-2 */ -#define Y4M_CHROMA_420PALDV 2 /* 4:2:0, alternating Cb/Cr, for PAL-DV */ -#define Y4M_CHROMA_444 3 /* 4:4:4, no subsampling, phew. */ -#define Y4M_CHROMA_422 4 /* 4:2:2, H cosited */ -#define Y4M_CHROMA_411 5 /* 4:1:1, H cosited */ -#define Y4M_CHROMA_MONO 6 /* luma plane only */ -#define Y4M_CHROMA_444ALPHA 7 /* 4:4:4 with an alpha channel */ +#define Y4M_ILACE_NONE 0 /** non-interlaced, progressive frame */ +#define Y4M_ILACE_TOP_FIRST 1 /** interlaced, top-field first */ +#define Y4M_ILACE_BOTTOM_FIRST 2 /** interlaced, bottom-field first */ +#define Y4M_ILACE_MIXED 3 /** mixed, "refer to frame header" */ + +#define Y4M_CHROMA_420JPEG 0 /** 4:2:0, H/V centered, for JPEG/MPEG-1 */ +#define Y4M_CHROMA_420MPEG2 1 /** 4:2:0, H cosited, for MPEG-2 */ +#define Y4M_CHROMA_420PALDV 2 /** 4:2:0, alternating Cb/Cr, for PAL-DV */ +#define Y4M_CHROMA_444 3 /** 4:4:4, no subsampling, phew. */ +#define Y4M_CHROMA_422 4 /** 4:2:2, H cosited */ +#define Y4M_CHROMA_411 5 /** 4:1:1, H cosited */ +#define Y4M_CHROMA_MONO 6 /** luma plane only */ +#define Y4M_CHROMA_444ALPHA 7 /** 4:4:4 with an alpha channel */ +/** + * @short decode JPEG buffer + */ int decode_jpeg_raw(unsigned char *jpeg_data, int len, int itype, int ctype, unsigned int width, unsigned int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2); +/** + * @short decode JPEG raw gray buffer + */ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len, int itype, int ctype, unsigned int width, unsigned int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2); +/** + * @short encode raw JPEG buffer + */ int encode_jpeg_raw(unsigned char *jpeg_data, int len, int quality, int itype, int ctype, unsigned int width, unsigned int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2); + +/*@}*/ + #endif diff -Nru libindi-1.0.0/libs/webcam/port.cpp libindi-1.1.0/libs/webcam/port.cpp --- libindi-1.0.0/libs/webcam/port.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/port.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,177 +0,0 @@ -/* libcqcam - shared Color Quickcam routines - * Copyright (C) 1996-1998 by Patrick Reynolds - * Email: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -// I/O ports wrapper code -// This file might need tweaking if you're trying to port my code to other -// x86 Unix platforms. Code is already available for Linux, FreeBSD, and -// QNX; see the Makefile. -// -// QNX code by: Anders Arpteg -// FreeBSD code by: Patrick Reynolds and Charles -// Henrich - - -//#include "config.h" - -#include -#include - -#ifdef LOCKING -#include -#include -#endif /* LOCKING */ - -#include "port.h" - -port_t::port_t(int iport) { - port = -1; - -#ifdef LOCKING - if (lock(iport) == -1) { -#ifdef DEBUG - fprintf(stderr, "port 0x%x already locked\n", iport); -#endif /* DEBUG */ - return; - } -#endif /* LOCKING */ - -#ifdef LINUX -#ifdef NO_SYSIO - if ((devport = open("/dev/port", O_RDWR)) < 0) { - perror("open /dev/port"); - return; - } -#else - if (ioperm(iport, 3, 1) == -1) { - perror("ioperm()"); - return; - } -#endif /* NO_SYSIO */ -#elif defined(FREEBSD) - if ((devio = fopen("/dev/io", "r+")) == NULL) { - perror("fopen /dev/io"); - return; - } -#elif defined(OPENBSD) - if (i386_iopl(1) == -1) { - perror("i386_iopl"); - return; - } -#elif defined(LYNX) - if (io_access() < 0) { - perror("io_access"); - return; - } -#elif defined(SOLARIS) - if (openiop()) { - perror("openiop"); - return; - } -#endif /* which OS */ - - port = iport; - port1 = port + 1; - port2 = port + 2; - control_reg = read_control(); -} - -port_t::~port_t(void) { -#ifdef LOCKING - unlock(port); -#endif /* LOCKING */ -#ifdef LINUX -#ifdef NO_SYSIO - if (devport >= 0) - close(devport); -#else - if (port > 0 && geteuid() == 0) - if (ioperm(port, 3, 0) != 0) // drop port permissions -- still must - // be root - perror("ioperm()"); -#endif /* NO_SYSIO */ -#elif defined(FREEBSD) - if (devio != NULL) - fclose(devio); -#elif defined(SOLARIS) - close(iopfd); -#endif /* which OS */ -} - -#ifdef LOCKING -int port_t::lock(int portnum) { - char lockfile[80]; - sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum); - while ((lock_fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) { - if (errno != EEXIST) { - perror(lockfile); - return -1; - } - struct stat stat_buf; - if (lstat(lockfile, &stat_buf) < 0) continue; - if (S_ISLNK(stat_buf.st_mode) || stat_buf.st_uid != 0) { - if (unlink(lockfile)) { - if (errno == ENOENT) continue; - if (errno != EISDIR || (rmdir(lockfile) && errno != ENOENT)) { - /* known problem: if lockfile exists and is a non-empty - directory, we give up instead of doing an rm-r of it */ - perror(lockfile); - return -1; - } - } - continue; - } - lock_fd = open(lockfile, O_WRONLY, 0600); - if (lock_fd == -1) { - perror(lockfile); - return -1; - } - break; - } - - static struct flock lock_info; - lock_info.l_type = F_WRLCK; -#ifdef LOCK_FAIL - if (fcntl(lock_fd, F_SETLK, &lock_info) != 0) { -#else - if (fcntl(lock_fd, F_SETLKW, &lock_info) != 0) { -#endif /* LOCK_FAIL */ - if (errno != EAGAIN) - perror("fcntl"); - return -1; - } - chown(lockfile, getuid(), getgid()); -#ifdef DEBUG - fprintf(stderr, "Locked port 0x%x\n", portnum); -#endif /* DEBUG */ - return 0; -} - -void port_t::unlock(int portnum) { - if (portnum == -1) - return; - close(lock_fd); // this clears the lock - char lockfile[80]; - sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum); - if (unlink(lockfile)) perror(lockfile); -#ifdef DEBUG - fprintf(stderr, "Unlocked port 0x%x\n", portnum); -#endif /* DEBUG */ -} -#endif /* LOCKING */ diff -Nru libindi-1.0.0/libs/webcam/port.h libindi-1.1.0/libs/webcam/port.h --- libindi-1.0.0/libs/webcam/port.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/port.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/* libcqcam - shared Color Quickcam routines - * Copyright (C) 1996-1998 by Patrick Reynolds -* Email: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -// I/O ports wrapper definitions and prototypes -// This file might need tweaking if you're trying to port my code to other -// x86 Unix platforms. Code is already available for Linux, FreeBSD, and -// QNX; see the Makefile. -// -// QNX code by: Anders Arpteg -// FreeBSD code by: Patrick Reynolds and Charles -// Henrich -// Inlining implemented by: Philip Blundell - -#ifndef PORT_H -#define PORT_H - -//#include "config.h" - -#include - -#ifdef __linux__ -#if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) \ - || defined(__powerpc__) || defined(__s390__) || defined(__s390x__)\ - || defined(__mips__) || defined(__mc68000__) || defined(__sh__)\ - || defined(__aarch64__) -#define NO_SYSIO -#endif /* architechtures */ -#endif /* __linux__ */ - -#ifdef __linux__ - #if defined(NO_SYSIO) - #include - #else - #include - #endif /* NO_SYSIO */ -#elif defined(QNX) -#include -#elif defined(__FreeBSD__) -#include -#include -#elif defined(BSDI) -#include -#elif defined(OPENBSD) -#include -#elif defined(LYNX) -#include "lynx-io.h" -#elif defined(SOLARIS) -#include "solaris-io.h" -#else -#error Please define a platform in the Makefile -#endif - -#if defined(NO_SYSIO) -static char ports_temp; - -#ifdef inb -#undef inb -#endif /* inb */ -#define inb(port) \ - lseek(devport, port, SEEK_SET), \ - read(devport, &ports_temp, 1), \ - ports_temp - -#ifdef outb -#undef outb -#endif /* inb */ -#define outb(data, port) \ - lseek(devport, port, SEEK_SET); \ - ports_temp = data; \ - write(devport, &ports_temp, 1); - -#endif /* arm, hppa */ - -class port_t { -public: - port_t(int iport); - ~port_t(void); - - inline int read_data(void) { return inb(port); } - inline int read_status(void) { return inb(port1); } - inline int read_control(void) { return inb(port2); } - -#if defined(LINUX) || defined(LYNX) - inline void write_data(int data) { outb(data, port); } - inline void write_control(int data) { outb(control_reg = data, port2); } - inline void setbit_control(int data) { outb(control_reg |= data, port2); } - inline void clearbit_control(int data) { outb(control_reg &= ~data, port2); } -#else // Solaris, QNX, and *BSD use (port, data) instead - inline void write_data(int data) { outb(port, data); } - inline void write_control(int data) { outb(port2, control_reg = data); } - inline void setbit_control(int data) { outb(port2, control_reg |= data); } - inline void clearbit_control(int data) { outb(port2, control_reg &= ~data); } -#endif - - inline int get_port() { return port; } - inline operator bool () const { return port != -1; } - -private: - int port; // number of the base port - int port1; // port+1, precalculated for speed - int port2; // port+2, precalculated for speed - int control_reg; // current contents of the control register -#ifdef LOCKING - int lock_fd; - int lock(int portnum); - void unlock(int portnum); -#endif - -#ifdef FREEBSD - FILE *devio; -#endif -#if defined(NO_SYSIO) - int devport; -#endif -}; - -#endif diff -Nru libindi-1.0.0/libs/webcam/PPort.cpp libindi-1.1.0/libs/webcam/PPort.cpp --- libindi-1.0.0/libs/webcam/PPort.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/PPort.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - Copyright (C) 1996-1998 by Patrick Reynolds - Email: - - 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 "PPort.h" -#include "port.h" - -#include -#include -#include - -using namespace std; - -#define TEST_VALIDITY {if (this==NULL) return false;} - -PPort::PPort() { - reset(); -} - -PPort::PPort(int ioPort) { - reset(); - setPort(ioPort); -} - -PPort::~PPort() -{ - delete currentPort; -} - -void PPort::reset() { - bitArray=0; - for (int i=0;i<8;++i) { - assignedBit[i]=NULL; - } - currentPort=NULL; -} - -bool PPort::setPort(int ioPort) { - TEST_VALIDITY; - if (geteuid() != 0) { - cerr << "must be setuid root control parallel port"<write_data(bitArray); - return true; - } else { - return false; - } -} - -bool PPort::setBit(const void * ID,int bit,bool stat) { - TEST_VALIDITY; - if (ID != assignedBit[bit]) { - return false; - } - - if (stat) { - bitArray |= (1<getDefaultDecoder(); decoder->init(); dodecode=true; + bpp=8; + has_ext_pix_format=false; const std::vector &vsuppformats=decoder->getsupportedformats(); IDLog("Using default decoder '%s'\n Supported V4L2 formats are:\n ", decoder->getName()); for (std::vector::const_iterator it=vsuppformats.begin(); it!=vsuppformats.end(); ++it) @@ -116,7 +119,10 @@ s, errno, strerror (errno)); snprintf(errmsg, ERRMSGSIZ, "%s error %d, %s\n", s, errno, strerror (errno)); - + + if (streamactive) + stop_capturing(errmsg); + return -1; } @@ -136,7 +142,6 @@ int V4L2_Base::connectCam(const char * devpath, char *errmsg , int pixelFormat , int width , int height) { selectCallBackID = -1; - dropFrame = false; cancrop=true; cansetrate=true; streamedonce=false; @@ -225,6 +230,28 @@ } assert (buf.index < n_buffers); + //IDLog("drop %c %d on %d\n", (dropFrameEnabled?'Y':'N'),dropFrame, dropFrameCount); + if (dropFrameEnabled && (dropFrame > 0)) + { + dropFrame -= 1; + if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) + return errno_exit ("ReadFrame IO_METHOD_MMAP: VIDIOC_QBUF", errmsg); + return 0; + } + + /* + switch (buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) { + case V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN: IDLog("Timestamp Unknown\n"); break; + case V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC : IDLog("Timestamp Monotonic\n"); break; + case V4L2_BUF_FLAG_TIMESTAMP_COPY : IDLog("Timestamp Copy\n"); break; + default: break; + } + switch (buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) { + case V4L2_BUF_FLAG_TSTAMP_SRC_EOF: IDLog("Timestamp at End of Frame\n"); break; + case V4L2_BUF_FLAG_TSTAMP_SRC_SOE : IDLog("Timestamp at Start of Exposure\n"); break; + default: break; + } + */ //IDLog("v4l2_base: dequeuing buffer %d, bytesused = %d, flags = 0x%X, field = %d, sequence = %d\n", buf.index, buf.bytesused, buf.flags, buf.field, buf.sequence); //IDLog("v4l2_base: dequeuing buffer %d for fd=%d, cropset %c\n", buf.index, fd, (cropset?'Y':'N')); //IDLog("V4L2_base read_frame: calling decoder (@ %x) %c\n", decoder, (dodecode?'Y':'N')); @@ -232,19 +259,20 @@ //IDLog("V4L2_base read_frame: calling recorder(@ %x) %c\n", recorder, (dorecord?'Y':'N')); if (dorecord) recorder->writeFrame((unsigned char *)(buffers[buf.index].start)); + //IDLog("lxstate is %d, dropFrame %c\n", lxstate, (dropFrame?'Y':'N')); + - if (dropFrame) - { - dropFrame = false; - return 0; - } if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) return errno_exit ("ReadFrame IO_METHOD_MMAP: VIDIOC_QBUF", errmsg); + + if( lxstate == LX_ACTIVE ) { + /* Call provided callback function if any */ - if (callback && !dorecord) + //if (callback && !dorecord) + if (callback) (*callback)(uptr); } @@ -305,20 +333,19 @@ case IO_METHOD_USERPTR: // N.B. I used this as a hack to solve a problem with capturing a frame // long time ago. I recently tried taking this hack off, and it worked fine! - if (dropFrameEnabled) - dropFrame = true; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; IERmCallback(selectCallBackID); selectCallBackID = -1; + streamactive = false; if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) return errno_exit ("VIDIOC_STREAMOFF", errmsg); break; } //uninit_device(errmsg); - streamactive = false; + return 0; } @@ -372,8 +399,7 @@ if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) return errno_exit ("StartCapturing IO_METHOD_USERPTR: VIDIOC_QBUF", errmsg); } - - + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) @@ -381,7 +407,8 @@ break; } - + //if (dropFrameEnabled) + dropFrame = dropFrameCount; streamedonce=true; return 0; } @@ -605,7 +632,10 @@ IDLog(" V4L2_CAP_ASYNCIO\n"); if (cap.capabilities & V4L2_CAP_STREAMING) IDLog(" V4L2_CAP_STREAMING\n"); - + /*if (cap.capabilities & V4L2_CAP_EXT_PIX_FORMAT) { + has_ext_pix_format=true; + IDLog(" V4L2_CAP_EXT_PIX_FORMAT\n"); + }*/ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf (stderr, "%s is no video capture device\n", dev_name); @@ -816,7 +846,9 @@ if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt)) return errno_exit ("VIDIOC_G_FMT", errmsg); - decoder->setformat(fmt); + decoder->setformat(fmt, has_ext_pix_format); + bpp=decoder->getBpp(); + /* DEBUGF(INDI::Logger::DBG_SESSION,"Current capture settings: %dx%d image size, %c%c%c%c (%s) image format", fmt.fmt.pix.width, fmt.fmt.pix.height, (fmt.fmt.pixelformat)&0xFF, (fmt.fmt.pixelformat >> 8)&0xFF, @@ -971,7 +1003,7 @@ if (fmt.fmt.pix.pixelformat == *((int *) (formats[i].aux))) { formats[i].s=ISS_ON; //initial=i; - IDLog("Current Capture format is (%d.) %c%c%c%c\n", i, (fmt.fmt.pix.pixelformat)&0xFF, (fmt.fmt.pix.pixelformat >> 8)&0xFF, + IDLog("Current Capture format is (%d.) %c%c%c%c.\n", i, (fmt.fmt.pix.pixelformat)&0xFF, (fmt.fmt.pix.pixelformat >> 8)&0xFF, (fmt.fmt.pix.pixelformat >> 16)&0xFF, (fmt.fmt.pix.pixelformat >> 24)&0xFF); //break; } @@ -996,7 +1028,8 @@ return errno_exit ("VIDIOC_S_FMT", errmsg); } //decode reallocate_buffers=true; - decoder->setformat(fmt); + decoder->setformat(fmt, has_ext_pix_format); + bpp=decoder->getBpp(); return 0; } @@ -1078,7 +1111,8 @@ fmt.fmt.pix.height = oldh; return errno_exit ("VIDIOC_G_FMT", errmsg); } - decoder->setformat(fmt); + decoder->setformat(fmt, has_ext_pix_format); + bpp=decoder->getBpp(); //decode reallocate_buffers=true; //decode cropset=false; //decode allocBuffers(); @@ -1198,6 +1232,11 @@ return fmt.fmt.pix.height; } +int V4L2_Base::getBpp() +{ + return bpp; +} + int V4L2_Base::getFormat() { return fmt.fmt.pix.pixelformat; @@ -1290,6 +1329,13 @@ return 0; } +void V4L2_Base::setColorProcessing(bool quantization, bool colorconvert, bool linearization) +{ + decoder->setQuantization(quantization); + decoder->setLinearization(linearization); + bpp=decoder->getBpp(); +} + unsigned char * V4L2_Base::getY() { return decoder->getY(); @@ -1315,6 +1361,12 @@ return decoder->getRGBBuffer(); } +float * V4L2_Base::getLinearY() +{ + return decoder->getLinearY(); +} + + void V4L2_Base::registerCallback(WPF *fp, void *ud) { callback = fp; @@ -2059,6 +2111,25 @@ IDLog("Adding switch %s (%s)\n", queryctrl.name, (control.value?"On":"Off")); nopt += 1; } + if (queryctrl.type == V4L2_CTRL_TYPE_BUTTON) + { + ISwitch *sw = (ISwitch *)malloc(sizeof(ISwitch)); + snprintf(optname+3, 4, "%03d", nopt); + snprintf(swonname+7, 4, "%03d", nopt); + //snprintf(swoffname+9, 4, "%03d", nopt); + + opt = (opt == NULL) ? (ISwitchVectorProperty *) malloc (sizeof(ISwitchVectorProperty)) : + (ISwitchVectorProperty *) realloc (opt, (nopt+1) * sizeof (ISwitchVectorProperty)); + + queryctrl.name[31]='\0'; + IUFillSwitch(sw, swonname, (const char *)entityXML((char *)queryctrl.name), ISS_OFF); + sw->aux=NULL; + IUFillSwitchVector (&opt[nopt], sw, 1, dev, optname, (const char *)entityXML((char *)queryctrl.name), group, IP_RW, ISR_NOFMANY, 0.0, IPS_IDLE); + opt[nopt].aux=malloc(sizeof(unsigned int)); + *(unsigned int *)(opt[nopt].aux)=(queryctrl.id); + IDLog("Adding Button \"%s\" \n", queryctrl.name); + nopt += 1; + } if (queryctrl.type == V4L2_CTRL_TYPE_MENU) { ISwitch *sw = NULL; diff -Nru libindi-1.0.0/libs/webcam/v4l2_base.h libindi-1.1.0/libs/webcam/v4l2_base.h --- libindi-1.0.0/libs/webcam/v4l2_base.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_base.h 2015-09-06 13:17:35.000000000 +0000 @@ -74,6 +74,7 @@ int getFormat(); int getWidth(); int getHeight(); + int getBpp(); virtual int setSize(int x, int y); virtual void getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min); @@ -86,6 +87,7 @@ unsigned char * getV(); unsigned char * getColorBuffer(); unsigned char * getRGBBuffer(); + float * getLinearY(); void registerCallback(WPF *fp, void *ud); @@ -94,6 +96,7 @@ static void newFrame(int fd, void *p); void setDropFrame(bool enable) { dropFrameEnabled = enable;} + void setDropFrameCount(unsigned int count) { dropFrameCount = count;} void enumerate_ctrl (void); void enumerate_menu (void); bool enumerate_ext_ctrl (void); @@ -116,9 +119,9 @@ int setcroprect(int x, int y, int w, int h, char *errmsg); struct v4l2_rect getcroprect(); + void setColorProcessing(bool quantization, bool colorconvert, bool linearization); - - void setlxstate( short s ) { lxstate = s; } + void setlxstate( short s ) { IDLog("setlexstate to %d\n", s);lxstate = s; } short getlxstate() { return lxstate; } bool isstreamactive() { return streamactive; } @@ -166,6 +169,7 @@ struct v4l2_queryctrl queryctrl; struct v4l2_querymenu querymenu; + bool has_ext_pix_format; WPF *callback; void *uptr; @@ -176,8 +180,9 @@ struct buffer *buffers; unsigned int n_buffers; bool reallocate_buffers; - bool dropFrame; + int dropFrame; bool dropFrameEnabled; + unsigned int dropFrameCount; struct v4l2_fract frameRate; @@ -192,6 +197,8 @@ V4L2_Recorder *recorder; bool dorecord; + int bpp; + friend class V4L2_Driver; }; diff -Nru libindi-1.0.0/libs/webcam/v4l2_colorspace.c libindi-1.1.0/libs/webcam/v4l2_colorspace.c --- libindi-1.0.0/libs/webcam/v4l2_colorspace.c 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_colorspace.c 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,159 @@ +#include "v4l2_colorspace.h" +#include + +unsigned char lutrangey8[256]; +unsigned short lutrangey10[1024]; +unsigned short lutrangey12[4096]; +unsigned short lutrangey16[65536]; +unsigned char lutrangecbcr8[256]; +unsigned short lutrangecbcr10[1024]; +unsigned short lutrangecbcr12[4096]; +unsigned short lutrangecbcr16[65536]; + +void initColorSpace() { + unsigned int i; + + for (i=0; i < 256; i++) { + lutrangey8[i] = (unsigned char)((255.0 / 219.0) * (i - 16)); + if (i > 235) lutrangey8[i] = 255; + lutrangecbcr8[i] = (unsigned char)((255.0 / 224.0) * i); + } +} + +void rangeY8(unsigned char *buf, unsigned int len) { + unsigned int i; + unsigned char *s=buf; + for (i=0; i < len; i++) { + *s++ = lutrangey8[*s]; + } +} + +void linearize(float *buf, unsigned int len, struct v4l2_format *fmt) { + unsigned int i; + float *src=buf; + switch (fmt->fmt.pix.colorspace) { + case V4L2_COLORSPACE_SMPTE240M: + // Old obsolete HDTV standard. Replaced by REC 709. + // This is the transfer function for SMPTE 240M + for (i = 0; i < len; i++) + *src++ = (*src < 0.0913) ? *src / 4.0 : pow((*src + 0.1115) / 1.1115, 1.0 / 0.45); + break; + case V4L2_COLORSPACE_SRGB: + // This is used for sRGB as specified by the IEC FDIS 61966-2-1 standard + for (i = 0; i < len; i++) + *src++ = (*src < -0.04045) ? -pow((-*src + 0.055) / 1.055, 2.4) : + ((*src <= 0.04045) ? *src / 12.92 : pow((*src + 0.055) / 1.055, 2.4)); + break; + //case V4L2_COLORSPACE_ADOBERGB: + //r = pow(r, 2.19921875); + //break; + case V4L2_COLORSPACE_REC709: + //case V4L2_COLORSPACE_BT2020: + default: + // All others use the transfer function specified by REC 709 + for (i = 0; i < len; i++) + *src++ = (*src <= -0.081) ? -pow((*src - 0.099) / -1.099, 1.0 / 0.45) : + ((*src < 0.081) ? *src / 4.5 : pow((*src + 0.099) / 1.099, 1.0 / 0.45)); + } +} + +const char * getColorSpaceName(struct v4l2_format *fmt) { + switch (fmt->fmt.pix.colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + return "SMPTE170M (SDTV)"; + case V4L2_COLORSPACE_SMPTE240M: + return "SMPTE240M (early HDTV)"; + case V4L2_COLORSPACE_REC709: + return "REC709 (HDTV)"; + case V4L2_COLORSPACE_BT878: + return "BT878"; + case V4L2_COLORSPACE_470_SYSTEM_M: + return "470 SYSTEM M (old NTSC)"; + case V4L2_COLORSPACE_470_SYSTEM_BG: + return "470 SYSTEM BG (old PAL/SECAM)"; + case V4L2_COLORSPACE_JPEG: + return "JPEG"; + case V4L2_COLORSPACE_SRGB: + return "SRGB"; + /* since Kernel 3.19 + case V4L2_COLORSPACE_ADOBERGB: + return "Adobe RGB"; + case V4L2_COLORSPACE_BT2020: + return "BT2020 (UHDTV)"; + */ + default: + return "Unknown"; + } +} + +unsigned int getYCbCrEncoding(struct v4l2_format *fmt) { + switch (fmt->fmt.pix.colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_BT878: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + case V4L2_COLORSPACE_JPEG: + return YCBCR_ENC_601; + case V4L2_COLORSPACE_REC709: + return YCBCR_ENC_709; + case V4L2_COLORSPACE_SRGB: + return YCBCR_ENC_SYCC; + case V4L2_COLORSPACE_SMPTE240M: + return YCBCR_ENC_SMPTE240M; + /* since Kernel 3.19 + case V4L2_COLORSPACE_ADOBERGB: + return return V4L2_YCBCR_ENC_601; + case V4L2_COLORSPACE_BT2020: + return return V4L2_YCBCR_ENC_BT2020; + */ + default: + return YCBCR_ENC_601; + } +} + +const char * getYCbCrEncodingName(struct v4l2_format *fmt) { + switch(getYCbCrEncoding(fmt)) { + case YCBCR_ENC_601: + return "ITU-R 601 -- SDTV"; + case YCBCR_ENC_709: + return "Rec. 709 -- HDTV"; + case YCBCR_ENC_SYCC: + return "sYCC (Y'CbCr encoding of sRGB)"; + case YCBCR_ENC_SMPTE240M: + return "SMPTE 240M -- Obsolete HDTV"; + default: + return "Unknown"; + } +} + +unsigned int getQuantization(struct v4l2_format *fmt) { + switch (fmt->fmt.pix.colorspace) { + /* since Kernel 3.19 + case V4L2_COLORSPACE_ADOBERGB: + case V4L2_COLORSPACE_BT2020: + */ + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_BT878: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SMPTE240M: + return QUANTIZATION_LIM_RANGE; + case V4L2_COLORSPACE_SRGB: + return QUANTIZATION_FULL_RANGE; + default: + return QUANTIZATION_LIM_RANGE; + } +} + +const char * getQuantizationName(struct v4l2_format *fmt) { + switch(getQuantization(fmt)) { + case QUANTIZATION_FULL_RANGE: + return "Full Range"; + case QUANTIZATION_LIM_RANGE: + return "Limited Range"; + default: + return "Unknown"; + } +} diff -Nru libindi-1.0.0/libs/webcam/v4l2_colorspace.h libindi-1.1.0/libs/webcam/v4l2_colorspace.h --- libindi-1.0.0/libs/webcam/v4l2_colorspace.h 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_colorspace.h 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,37 @@ +#ifndef V4L2_COLORSPACE_H +#define V4L2_COLORSPACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/* for kernel < 3.19 */ +/* ITU-R 601 -- SDTV */ +#define YCBCR_ENC_601 1 +/* Rec. 709 -- HDTV */ +#define YCBCR_ENC_709 2 +/* sYCC (Y'CbCr encoding of sRGB) */ +#define YCBCR_ENC_SYCC 5 +/* SMPTE 240M -- Obsolete HDTV */ +#define YCBCR_ENC_SMPTE240M 8 +#define QUANTIZATION_FULL_RANGE 1 +#define QUANTIZATION_LIM_RANGE 2 + + + +void initColorSpace(); +const char * getColorSpaceName(struct v4l2_format *fmt); +unsigned int getYCbCrEncoding(struct v4l2_format *fmt); +const char * getYCbCrEncodingName(struct v4l2_format *fmt); +unsigned int getQuantization(struct v4l2_format *fmt); +const char * getQuantizationName(struct v4l2_format *fmt); + +void rangeY8(unsigned char *buf, unsigned int len); +void linearize(float *buf, unsigned int len, struct v4l2_format *fmt); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.cpp libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.cpp --- libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -4,6 +4,17 @@ V4L2 Builtin Decoder + As of August 2015 gst-lauch-1.0 and v4l2loopback do not work together well (https://github.com/umlaeute/v4l2loopback/issues/83) + Still use v4l2loopback (see below) but with ffmpeg: + ffmpeg -f lavfi -re -i "smptebars=size=640x480:rate=30" -pix_fmt yuv420p -f v4l2 /dev/video8 + Use the -re flag to really get frame rate otherwise ffmpeg outputs frames as fast as possible (400 to 700fps). + With indi-opencv-ccd use /dev/video1 as v4l2loopback device + for 16 bits gray + ffmpeg -f lavfi -re -i "testsrc=size=640x480:rate=30" -pix_fmt gray16le -f v4l2 /dev/video1 + Profiling + cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_CXX_FLAGS=-pg /nfs/devel/sourceforge/indi-code/libindi/ + kill indiserver with the kill command, not ctrl-c + To test decoders, use gstreamer and the v4l2loopback kernel module Use the experimental git branch of v4l2loopback to get more pixel formats git clone https://github.com/umlaeute/v4l2loopback/ -b experimental @@ -16,6 +27,20 @@ modprobe v4l2loopback video_nr=8 card_label="Indi Loopback" exclusive_caps=0,0 gst-launch-0.10 -v videotestsrc ! 'video/x-raw-bayer, format=(string)bggr, width=640, height=480, framerate=(fraction)2/1' ! v4l2sink device=/dev/video8 + For Gray16 format I use gst-launch with a videotstsrc in GRAY16 format writing in a FIFO and a C program reding the FIFO into the v4l2loopback device + mkfifo /tmp/videopipe + gst-launch-1.0 -v videotestsrc ! video/x-raw,format=\(string\)GRAY16_LE,width=1024,height=576,framerate=\(fraction\)25/1 ! filesink location =/tmp/videopipe + ./gray16_to_v4l2 /dev/video8 < /tmp/videopipe & + The C program ./gray16_to_v4l2 is adpated from https://github.com/umlaeute/v4l2loopback/blob/master/examples/yuv4mpeg_to_v4l2.c : + process_header/read_header calls are suppressed (copy_frames uses a while (1) loop), frame_width and frame_height are constant + and V4L2 pixel format is set to V4L2_PIX_FMT_Y16. + + To repeat an avi stream + ./v4l2loopback-ctl set-caps 'video/x-raw-yuv,width=720,height=576' /dev/video8 + ./v4l2loopback-ctl set-fps 25/1 /dev/video8 + as normal user + while true; do gst-launch-0.10 -vvv filesrc location=chi-aquarius.avi ! avidemux name=demux demux.video_00 ! queue ! decodebin ! videoscale add-borders=true ! v4l2sink device=/dev/video8 ; done + 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 @@ -37,6 +62,7 @@ #include // memcpy //#include // FILE * #include "../ccvt.h" +#include "../v4l2_colorspace.h" //#include @@ -45,6 +71,7 @@ name="Builtin decoder"; useSoftCrop=false; doCrop=false; + doQuantization=false; YBuf = NULL; UBuf = NULL; VBuf = NULL; @@ -52,6 +79,7 @@ yuyvBuffer = NULL; colorBuffer = NULL; rgb24_buffer = NULL; + linearBuffer = NULL; //cropbuf = NULL; for (i=0; i< 32; i++) { lut5[i] = (char)(((float)i * 255.0) / 31.0); @@ -59,6 +87,8 @@ for (i=0; i< 64; i++) { lut6[i] = (char)(((float)i * 255.0) / 63.0); } + initColorSpace(); + bpp=8; } V4L2_Builtin_Decoder::~V4L2_Builtin_Decoder() { @@ -69,6 +99,7 @@ if (yuyvBuffer) delete [] (yuyvBuffer); yuyvBuffer = NULL; if (colorBuffer) delete [] (colorBuffer); colorBuffer = NULL; if (rgb24_buffer) delete [] (rgb24_buffer); rgb24_buffer = NULL; + if (linearBuffer) delete [] (linearBuffer); linearBuffer = NULL; }; void V4L2_Builtin_Decoder::init() { @@ -99,6 +130,22 @@ memcpy(YBuf, frame, bufwidth * bufheight); } break; + + case V4L2_PIX_FMT_Y16: + if (useSoftCrop && doCrop) { + unsigned char *src=frame + 2*(crop.c.left) + (crop.c.top * fmt.fmt.pix.bytesperline); + unsigned char *dest=yuyvBuffer; + unsigned int i; + for (i= 0; i < crop.c.height; i++) + { + memcpy(dest, src, 2*crop.c.width); + src += fmt.fmt.pix.bytesperline; + dest += 2*crop.c.width; + } + } else { + memcpy(yuyvBuffer, frame, 2*bufwidth*bufheight); + } + break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: @@ -182,11 +229,7 @@ unsigned char *destv=VBuf; unsigned int i, j; unsigned char *s; - //FILE *f=fopen("/home/levaire/Images/indicvt.data","w"); - //FILE *fi=fopen("/home/levaire/Images/indifframe.data","w"); - //fwrite(frame, 1, (bufwidth*bufheight)+ ((bufwidth*bufheight) / 2), fi); - //fwrite(frame, 1, buf->bytesused, fi); - //fclose(fi); + for (i=0; i< bufheight; i++) { memcpy(dest,src, bufwidth); src+=fmt.fmt.pix.bytesperline; dest+=bufwidth; } @@ -202,8 +245,6 @@ } src += fmt.fmt.pix.bytesperline; } - //fwrite(yuvBuffer, 1, (bufwidth*bufheight)+ ((bufwidth*bufheight) / 2), f); - //fclose(f); } break; @@ -330,13 +371,16 @@ case V4L2_PIX_FMT_SRGGB8: bayer_rggb_2rgb24(rgb24_buffer, frame, fmt.fmt.pix.width, fmt.fmt.pix.height); break; + + case V4L2_PIX_FMT_SBGGR16: + bayer16_2_rgb24((unsigned short *)rgb24_buffer, (unsigned short *)frame, fmt.fmt.pix.width, fmt.fmt.pix.height); + break; case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_MJPEG: //mjpegtoyuv420p(yuvBuffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[buf.index].length); mjpegtoyuv420p(yuvBuffer, frame, fmt.fmt.pix.width, fmt.fmt.pix.height, buf->bytesused); break; - default: { unsigned int i; @@ -372,14 +416,38 @@ useSoftCrop=c; } -void V4L2_Builtin_Decoder::setformat(struct v4l2_format f) { +void V4L2_Builtin_Decoder::setformat(struct v4l2_format f, bool use_ext_pix_format) { fmt=f; - IDLog("Decoder set format: %c%c%c%c size %dx%d\n", (fmt.fmt.pix.pixelformat)&0xFF, (fmt.fmt.pix.pixelformat >> 8)&0xFF, - (fmt.fmt.pix.pixelformat >> 16)&0xFF, (fmt.fmt.pix.pixelformat >> 24)&0xFF, f.fmt.pix.width, f.fmt.pix.height); + if (supported_formats.count(fmt.fmt.pix.pixelformat) == 1) + bpp = supported_formats.at(fmt.fmt.pix.pixelformat)->bpp; + else + bpp = 8; + IDLog("Decoder set format: %c%c%c%c size %dx%d bpp %d\n", (fmt.fmt.pix.pixelformat)&0xFF, (fmt.fmt.pix.pixelformat >> 8)&0xFF, + (fmt.fmt.pix.pixelformat >> 16)&0xFF, (fmt.fmt.pix.pixelformat >> 24)&0xFF, f.fmt.pix.width, f.fmt.pix.height, bpp); + /* kernel 3.19 + if (use_ext_pix_format && fmt.fmt.pix.priv == V4L2_PIX_FMT_PRIV_MAGIC) + IDLog("Decoder: Colorspace is %d, YCbCr encoding is %d, Quantization is %d\n", fmt.fmt.pix.colorspace, fmt.fmt.pix.ycbcr_enc, fmt.fmt.pix.quantization); + else + */ + IDLog("Decoder: Colorspace is %d, using default ycbcr encoding and quantization\n", fmt.fmt.pix.colorspace); doCrop=false; allocBuffers(); } +void V4L2_Builtin_Decoder::setQuantization(bool doquantization) +{ + doQuantization=doquantization; +} +void V4L2_Builtin_Decoder::setLinearization(bool dolinearization) +{ + doLinearization=dolinearization; + if (doLinearization) bpp = 16; + else + if (supported_formats.count(fmt.fmt.pix.pixelformat) == 1) + bpp = supported_formats.at(fmt.fmt.pix.pixelformat)->bpp; + else + bpp = 8; +} void V4L2_Builtin_Decoder::allocBuffers() { YBuf = NULL; UBuf = NULL; VBuf = NULL; @@ -387,6 +455,7 @@ if (yuyvBuffer) delete [] (yuyvBuffer); yuyvBuffer = NULL; if (colorBuffer) delete [] (colorBuffer); colorBuffer = NULL; if (rgb24_buffer) delete [] (rgb24_buffer); rgb24_buffer = NULL; + if (linearBuffer) delete [](linearBuffer); linearBuffer = NULL; //if (cropbuf) free(cropbuf); cropbuf=NULL; if (doCrop) { @@ -409,6 +478,7 @@ YBuf=yuvBuffer; UBuf=yuvBuffer + (bufwidth * bufheight); VBuf=UBuf + ((bufwidth * bufheight) / 4); // bzero(Ubuf, ((bufwidth * bufheight) / 2)); break; + case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: @@ -420,7 +490,9 @@ case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SRGGB8: - rgb24_buffer = new unsigned char[(bufwidth * bufheight) * 3]; + case V4L2_PIX_FMT_SBGGR16: + rgb24_buffer = new unsigned char[(bufwidth * bufheight) * (bpp / 8) * 3]; + break; default: yuvBuffer=new unsigned char[(bufwidth * bufheight) + ((bufwidth * bufheight) / 2)]; YBuf=yuvBuffer; UBuf=yuvBuffer + (bufwidth * bufheight); VBuf=UBuf + ((bufwidth * bufheight) / 4); @@ -429,7 +501,21 @@ IDLog("Decoder allocBuffers cropping %s\n",(doCrop?"true":"false")); } -unsigned char * V4L2_Builtin_Decoder::getY() +void V4L2_Builtin_Decoder::makeLinearY() +{ + unsigned char *src=YBuf; + float *dest; + unsigned int i; + if (!linearBuffer) { + linearBuffer = new float[(bufwidth * bufheight)]; + } + dest=linearBuffer; + for (i=0; i < bufwidth * bufheight; i++) + *dest++ = (*src++) / 255.0; + linearize(linearBuffer, bufwidth * bufheight, &fmt); + +} +void V4L2_Builtin_Decoder::makeY() { if (!yuvBuffer) { yuvBuffer = new unsigned char[(bufwidth * bufheight) + ((bufwidth * bufheight) / 2)]; @@ -446,13 +532,45 @@ case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_YVYU: + // todo handcopy only Ybuf using an int, byfwidth should be even ccvt_yuyv_420p(bufwidth, bufheight, yuyvBuffer, YBuf, UBuf, VBuf); break; } +} + +unsigned char * V4L2_Builtin_Decoder::getY() +{ + if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_Y16) + return yuyvBuffer; + makeY(); + if (doQuantization && getQuantization(&fmt) == QUANTIZATION_LIM_RANGE) + rangeY8(YBuf, (bufwidth * bufheight)); + if (doLinearization) { + unsigned int i; + float *src; + unsigned short *dest; + if (!yuyvBuffer) + yuyvBuffer=new unsigned char[(bufwidth * bufheight) * 2]; + makeLinearY(); + src=linearBuffer; + dest=(unsigned short *)yuyvBuffer; + for (i=0; i < bufwidth * bufheight; i++) + *dest++ = (unsigned short)(*src++ * 65535.0); + return yuyvBuffer; + } return YBuf; } +float * V4L2_Builtin_Decoder::getLinearY() +{ + makeY(); + if (doQuantization && getQuantization(&fmt) == QUANTIZATION_LIM_RANGE) + rangeY8(YBuf, (bufwidth * bufheight)); + makeLinearY(); + return linearBuffer; +} + unsigned char * V4L2_Builtin_Decoder::getU() { return UBuf; @@ -463,11 +581,12 @@ return VBuf; } +/* used for streaming/exposure */ unsigned char * V4L2_Builtin_Decoder::getColorBuffer() { //cerr << "in get color buffer " << endl; //IDLog("Decoder getColorBuffer %s\n", (doCrop?"true":"false")); - if (!colorBuffer) colorBuffer = new unsigned char[(bufwidth * bufheight) * 4]; + if (!colorBuffer) colorBuffer = new unsigned char[(bufwidth * bufheight) * (bpp / 8) * 4]; switch (fmt.fmt.pix.pixelformat) { case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_JPEG: @@ -478,6 +597,7 @@ case V4L2_PIX_FMT_NV21: ccvt_420p_bgr32(bufwidth, bufheight, (void *)yuvBuffer, (void*)colorBuffer); break; + case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: @@ -491,13 +611,47 @@ case V4L2_PIX_FMT_SRGGB8: ccvt_rgb24_bgr32(bufwidth, bufheight,rgb24_buffer, (void*)colorBuffer); break; + case V4L2_PIX_FMT_Y16: + /* OOOps this is planar ARGB */ + /* + bzero(colorBuffer, bufwidth * bufheight * 2); + memcpy(colorBuffer + (bufwidth * bufheight * 2), yuyvBuffer, bufwidth * bufheight * 2); + memcpy(colorBuffer + 2 * (bufwidth * bufheight * 2), yuyvBuffer, bufwidth * bufheight * 2); + memcpy(colorBuffer + 3 * (bufwidth * bufheight * 2), yuyvBuffer, bufwidth * bufheight * 2); + */ + { /* this is bgra , use unsigned short here... */ + unsigned int i; + unsigned char *src = yuyvBuffer; + unsigned char *dest = colorBuffer; + for (i = 0; i < bufwidth * bufheight; i += 1) { + *dest++=*src; *dest++=*(src+1); + *dest++=*src; *dest++=*(src+1); + *dest++=*src; *dest++=*(src+1); + *dest++=0; *dest++=0; + src += 2; + } + } + break; + case V4L2_PIX_FMT_SBGGR16: + { /* this is bgra , now I use unsigned short! */ + unsigned int i; + unsigned short *src = (unsigned short *)rgb24_buffer; + unsigned short *dest = (unsigned short *)colorBuffer; + for (i = 0; i < bufwidth * bufheight; i += 1) { + *dest++=*(src + 2); + *dest++=*(src + 1); + *dest++=*(src); + *dest++=0; + src += 3; + } + } default: ccvt_420p_bgr32(bufwidth, bufheight, (void *)yuvBuffer, (void*)colorBuffer); break; } return colorBuffer; } - +/* used for SER recorder */ unsigned char * V4L2_Builtin_Decoder::getRGBBuffer() { //cerr << "in get color buffer " << endl; @@ -521,6 +675,13 @@ ccvt_yuyv_bgr32(bufwidth, bufheight, yuyvBuffer, (void*)colorBuffer); ccvt_bgr32_rgb24(bufwidth, bufheight, colorBuffer, (void*)rgb24_buffer); break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR16: + break; default: ccvt_420p_rgb24(bufwidth, bufheight, (void *)yuvBuffer, (void*)rgb24_buffer); break; @@ -528,6 +689,9 @@ return rgb24_buffer; } +int V4L2_Builtin_Decoder::getBpp() { + return (int)(bpp); +} bool V4L2_Builtin_Decoder::issupportedformat(unsigned int format) { @@ -565,6 +729,7 @@ // V4L2_PIX_FMT_Y10 , // v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ // V4L2_PIX_FMT_Y12 , // v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ // V4L2_PIX_FMT_Y16 , // v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ + supported_formats.insert(std::make_pair(V4L2_PIX_FMT_Y16, new V4L2_Builtin_Decoder::format(V4L2_PIX_FMT_Y16, 16, true))); /* Grey bit-packed formats */ // V4L2_PIX_FMT_Y10BPACK , // v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ @@ -654,6 +819,7 @@ * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... */ // V4L2_PIX_FMT_SBGGR16 , // v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ + supported_formats.insert(std::make_pair(V4L2_PIX_FMT_SBGGR16, new V4L2_Builtin_Decoder::format(V4L2_PIX_FMT_SBGGR16, 16, false))); /* compressed formats */ // V4L2_PIX_FMT_MJPEG , // v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ diff -Nru libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.h libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.h --- libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_builtin_decoder.h 2015-09-06 13:17:35.000000000 +0000 @@ -43,7 +43,7 @@ virtual bool setcrop(struct v4l2_crop c); virtual void resetcrop(); virtual void usesoftcrop(bool c); - virtual void setformat(struct v4l2_format f); + virtual void setformat(struct v4l2_format f, bool use_ext_pix_format); virtual bool issupportedformat(unsigned int format); virtual const std::vector &getsupportedformats(); virtual void decode(unsigned char *frame, struct v4l2_buffer *buf); @@ -52,16 +52,25 @@ virtual unsigned char * getV(); virtual unsigned char * getColorBuffer(); virtual unsigned char * getRGBBuffer(); + virtual float *getLinearY(); + virtual int getBpp(); + virtual void setQuantization(bool); + virtual void setLinearization(bool); protected: void init_supported_formats(); std::map supported_formats; std::vector vsuppformats; void allocBuffers(); + void makeY(); + void makeLinearY(); + struct v4l2_crop crop; struct v4l2_format fmt; bool useSoftCrop; // uses software cropping bool doCrop; // do software cropping when decoding frames + bool doQuantization; + bool doLinearization; unsigned char *YBuf; unsigned char *UBuf; @@ -70,11 +79,12 @@ unsigned char *yuyvBuffer; unsigned char *colorBuffer; unsigned char *rgb24_buffer; + float *linearBuffer; //unsigned char *cropbuf; unsigned int bufwidth; unsigned int bufheight; char lut5[32]; char lut6[64]; - + unsigned char bpp; }; #endif diff -Nru libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_decode.h libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_decode.h --- libindi-1.0.0/libs/webcam/v4l2_decode/v4l2_decode.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_decode/v4l2_decode.h 2015-09-06 13:17:35.000000000 +0000 @@ -41,7 +41,7 @@ virtual bool setcrop(struct v4l2_crop c)=0; virtual void resetcrop()=0; virtual void usesoftcrop(bool c)=0; -virtual void setformat(struct v4l2_format f)=0; + virtual void setformat(struct v4l2_format f, bool use_ext_pix_format)=0; virtual bool issupportedformat(unsigned int format)=0; virtual const std::vector &getsupportedformats()=0; virtual void decode(unsigned char *frame, struct v4l2_buffer *buf)=0; @@ -49,7 +49,11 @@ virtual unsigned char * getU()=0; virtual unsigned char * getV()=0; virtual unsigned char * getColorBuffer()=0; -virtual unsigned char * getRGBBuffer()=0; + virtual unsigned char * getRGBBuffer()=0; +virtual float * getLinearY()=0; +virtual int getBpp()=0; +virtual void setQuantization(bool)=0; +virtual void setLinearization(bool)=0; protected: const char *name; diff -Nru libindi-1.0.0/libs/webcam/v4l2_record/ser_recorder.cpp libindi-1.1.0/libs/webcam/v4l2_record/ser_recorder.cpp --- libindi-1.0.0/libs/webcam/v4l2_record/ser_recorder.cpp 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/v4l2_record/ser_recorder.cpp 2015-09-06 13:17:35.000000000 +0000 @@ -104,44 +104,96 @@ number_of_planes=1; switch (format) { case V4L2_PIX_FMT_GREY: +#ifdef V4L2_PIX_FMT_Y10 case V4L2_PIX_FMT_Y10: +#endif +#ifdef V4L2_PIX_FMT_Y12 case V4L2_PIX_FMT_Y12: +#endif +#ifdef V4L2_PIX_FMT_Y16 case V4L2_PIX_FMT_Y16: +#endif serh.ColorID=SER_MONO; +#ifdef V4L2_PIX_FMT_Y10 if (format == V4L2_PIX_FMT_Y10) serh.PixelDepth=10; +#endif +#ifdef V4L2_PIX_FMT_Y12 if (format == V4L2_PIX_FMT_Y12) serh.PixelDepth=12; +#endif +#ifdef V4L2_PIX_FMT_Y16 if (format == V4L2_PIX_FMT_Y16) serh.PixelDepth=16; +#endif return true; case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SBGGR10: +#ifdef V4L2_PIX_FMT_SBGGR10 + case V4L2_PIX_FMT_SBGGR10: +#endif +#ifdef V4L2_PIX_FMT_SBGGR12 case V4L2_PIX_FMT_SBGGR12: +#endif case V4L2_PIX_FMT_SBGGR16: serh.ColorID=SER_BAYER_BGGR; +#ifdef V4L2_PIX_FMT_SBGGR10 if (format == V4L2_PIX_FMT_SBGGR10) serh.PixelDepth=10; +#endif +#ifdef V4L2_PIX_FMT_SBGGR12 if (format == V4L2_PIX_FMT_SBGGR12) serh.PixelDepth=12; +#endif if (format == V4L2_PIX_FMT_SBGGR16) serh.PixelDepth=16; return true; case V4L2_PIX_FMT_SGBRG8: +#ifdef V4L2_PIX_FMT_SGBRG10 case V4L2_PIX_FMT_SGBRG10: +#endif +#ifdef V4L2_PIX_FMT_SGBRG12 case V4L2_PIX_FMT_SGBRG12: +#endif serh.ColorID=SER_BAYER_GBRG; +#ifdef V4L2_PIX_FMT_SGBRG10 if (format == V4L2_PIX_FMT_SGBRG10) serh.PixelDepth=10; +#endif +#ifdef V4L2_PIX_FMT_SGBRG12 if (format == V4L2_PIX_FMT_SGBRG12) serh.PixelDepth=12; +#endif return true; +#if defined(V4L2_PIX_FMT_SGRBG8) || defined(V4L2_PIX_FMT_SGRBG10) || defined(V4L2_PIX_FMT_SGRBG12) +#ifdef V4L2_PIX_FMT_SGRBG8 case V4L2_PIX_FMT_SGRBG8: +#endif +#ifdef V4L2_PIX_FMT_SGRBG10 case V4L2_PIX_FMT_SGRBG10: +#endif +#ifdef V4L2_PIX_FMT_SGRBG12 case V4L2_PIX_FMT_SGRBG12: +#endif serh.ColorID=SER_BAYER_GRBG; - if (format == V4L2_PIX_FMT_SGRBG10) serh.PixelDepth=10; +#ifdef V4L2_PIX_FMT_SGRBG10 + if (format == V4L2_PIX_FMT_SGRBG10) serh.PixelDepth=10; +#endif +#ifdef V4L2_PIX_FMT_SGRBG12 if (format == V4L2_PIX_FMT_SGRBG12) serh.PixelDepth=12; +#endif return true; +#endif +#if defined(V4L2_PIX_FMT_SRGGB8) || defined(V4L2_PIX_FMT_SRGGB10) || defined(V4L2_PIX_FMT_SRGGB12) +#ifdef V4L2_PIX_FMT_SRGGB8 case V4L2_PIX_FMT_SRGGB8: +#endif +#ifdef V4L2_PIX_FMT_SRGGB10 case V4L2_PIX_FMT_SRGGB10: +#endif +#ifdef V4L2_PIX_FMT_SRGGB12 case V4L2_PIX_FMT_SRGGB12: +#endif serh.ColorID=SER_BAYER_RGGB; - if (format == V4L2_PIX_FMT_SRGGB10) serh.PixelDepth=10; - if (format == V4L2_PIX_FMT_SRGGB12) serh.PixelDepth=12; +#ifdef V4L2_PIX_FMT_SRGGB10 + if (format == V4L2_PIX_FMT_SRGGB10) serh.PixelDepth=10; +#endif +#ifdef V4L2_PIX_FMT_SRGGB12 + if (format == V4L2_PIX_FMT_SRGGB12) serh.PixelDepth=12; +#endif return true; +#endif case V4L2_PIX_FMT_RGB24: if (!useSER_V3) return false; number_of_planes=3; @@ -169,8 +221,8 @@ bool SER_Recorder::open(const char *filename, char *errmsg) { if (streaming_active) return false; serh.FrameCount = 0; - serh.DateTime=-1; // no timestamp - serh.DateTime_UTC=-1; // no timestamp + serh.DateTime=0; // no timestamp + serh.DateTime_UTC=0; // no timestamp if ((f=fopen(filename, "w")) == NULL) { snprintf(errmsg, ERRMSGSIZ, "recorder open error %d, %s\n", errno, strerror (errno)); return false; @@ -182,9 +234,13 @@ } bool SER_Recorder::close() { - fseek(f, 0L, SEEK_SET); - write_header(&serh); - fclose(f); + if (f) + { + fseek(f, 0L, SEEK_SET); + write_header(&serh); + fclose(f); + } + streaming_active = false; return true; } diff -Nru libindi-1.0.0/libs/webcam/videodev2.h libindi-1.1.0/libs/webcam/videodev2.h --- libindi-1.0.0/libs/webcam/videodev2.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/videodev2.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,2646 +0,0 @@ -/* - * Video for Linux Two header file - * - * Copyright (C) 1999-2007 the contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * 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 above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. The names of its contributors may not 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 THE COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - * - * Header file for v4l or V4L2 drivers and applications - * with public API. - * All kernel-specific stuff were moved to media/v4l2-dev.h, so - * no #if __KERNEL tests are allowed here - * - * See http://linuxtv.org for more info - * - * Author: Bill Dirks - * Justin Schoeman - * Hans Verkuil - * et al. - */ -#ifndef __LINUX_VIDEODEV2_H -#define __LINUX_VIDEODEV2_H - -#include - -#include -#include - -/* - * Common stuff for both V4L1 and V4L2 - * Moved from videodev.h - */ -#define VIDEO_MAX_FRAME 32 -#define VIDEO_MAX_PLANES 8 - - -/* These defines are V4L1 specific and should not be used with the V4L2 API! - They will be removed from this header in the future. */ - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ - -/* - * M I S C E L L A N E O U S - */ - -/* Four-character-code (FOURCC) */ -#define v4l2_fourcc(a, b, c, d)\ - ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) - -/* - * E N U M S - */ -enum v4l2_field { - V4L2_FIELD_ANY = 0, /* driver can choose from none, - top, bottom, interlaced - depending on whatever it thinks - is approximate ... */ - V4L2_FIELD_NONE = 1, /* this device has no fields ... */ - V4L2_FIELD_TOP = 2, /* top field only */ - V4L2_FIELD_BOTTOM = 3, /* bottom field only */ - V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ - V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one - buffer, top-bottom order */ - V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ - V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into - separate buffers */ - V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field - first and the top field is - transmitted first */ - V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field - first and the bottom field is - transmitted first */ -}; -#define V4L2_FIELD_HAS_TOP(field) \ - ((field) == V4L2_FIELD_TOP ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTTOM(field) \ - ((field) == V4L2_FIELD_BOTTOM ||\ - (field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) -#define V4L2_FIELD_HAS_BOTH(field) \ - ((field) == V4L2_FIELD_INTERLACED ||\ - (field) == V4L2_FIELD_INTERLACED_TB ||\ - (field) == V4L2_FIELD_INTERLACED_BT ||\ - (field) == V4L2_FIELD_SEQ_TB ||\ - (field) == V4L2_FIELD_SEQ_BT) - -enum v4l2_buf_type { - V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, - V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, - V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, - V4L2_BUF_TYPE_VBI_CAPTURE = 4, - V4L2_BUF_TYPE_VBI_OUTPUT = 5, - V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, - V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, -#if 1 - /* Experimental */ - V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, -#endif - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, - V4L2_BUF_TYPE_PRIVATE = 0x80, -}; - -#define V4L2_TYPE_IS_MULTIPLANAR(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - -#define V4L2_TYPE_IS_OUTPUT(type) \ - ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \ - || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \ - || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \ - || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - -enum v4l2_tuner_type { - V4L2_TUNER_RADIO = 1, - V4L2_TUNER_ANALOG_TV = 2, - V4L2_TUNER_DIGITAL_TV = 3, -}; - -enum v4l2_memory { - V4L2_MEMORY_MMAP = 1, - V4L2_MEMORY_USERPTR = 2, - V4L2_MEMORY_OVERLAY = 3, -}; - -/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ -enum v4l2_colorspace { - /* ITU-R 601 -- broadcast NTSC/PAL */ - V4L2_COLORSPACE_SMPTE170M = 1, - - /* 1125-Line (US) HDTV */ - V4L2_COLORSPACE_SMPTE240M = 2, - - /* HD and modern captures. */ - V4L2_COLORSPACE_REC709 = 3, - - /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ - V4L2_COLORSPACE_BT878 = 4, - - /* These should be useful. Assume 601 extents. */ - V4L2_COLORSPACE_470_SYSTEM_M = 5, - V4L2_COLORSPACE_470_SYSTEM_BG = 6, - - /* I know there will be cameras that send this. So, this is - * unspecified chromaticities and full 0-255 on each of the - * Y'CbCr components - */ - V4L2_COLORSPACE_JPEG = 7, - - /* For RGB colourspaces, this is probably a good start. */ - V4L2_COLORSPACE_SRGB = 8, -}; - -enum v4l2_priority { - V4L2_PRIORITY_UNSET = 0, /* not initialized */ - V4L2_PRIORITY_BACKGROUND = 1, - V4L2_PRIORITY_INTERACTIVE = 2, - V4L2_PRIORITY_RECORD = 3, - V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, -}; - -struct v4l2_rect { - __s32 left; - __s32 top; - __s32 width; - __s32 height; -}; - -struct v4l2_fract { - __u32 numerator; - __u32 denominator; -}; - -/** - * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP - * - * @driver: name of the driver module (e.g. "bttv") - * @card: name of the card (e.g. "Hauppauge WinTV") - * @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) ) - * @version: KERNEL_VERSION - * @capabilities: capabilities of the physical device as a whole - * @device_caps: capabilities accessed via this particular device (node) - * @reserved: reserved fields for future extensions - */ -struct v4l2_capability { - __u8 driver[16]; - __u8 card[32]; - __u8 bus_info[32]; - __u32 version; - __u32 capabilities; - __u32 device_caps; - __u32 reserved[3]; -}; - -/* Values for 'capabilities' field */ -#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ -#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ -#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ -#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */ -#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */ -#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */ -#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ -#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ -#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */ -#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */ -#define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */ - -/* Is a video capture device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000 -/* Is a video output device that supports multiplanar formats */ -#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000 - -#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ -#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ -#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ -#define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */ - -#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ -#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ -#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ - -#define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ - -/* - * V I D E O I M A G E F O R M A T - */ -struct v4l2_pix_format { - __u32 width; - __u32 height; - __u32 pixelformat; - __u32 field; /* enum v4l2_field */ - __u32 bytesperline; /* for padding, zero if unused */ - __u32 sizeimage; - __u32 colorspace; /* enum v4l2_colorspace */ - __u32 priv; /* private data, depends on pixelformat */ -}; - -/* Pixel format FOURCC depth Description */ - -/* RGB formats */ -#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ -#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ -#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ -#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ -#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ -#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ -#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ -#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ -#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ -#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ -#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ - -/* Grey formats */ -#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ -#define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ -#define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ -#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ -#define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ -#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ - -/* Grey bit-packed formats */ -#define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ - -/* Palette formats */ -#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ - -/* Luminance+Chrominance formats */ -#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ -#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ -#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ -#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ -#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ -#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ -#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ -#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ -#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ -#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ -#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ -#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ -#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ - -/* two planes -- one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ -#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ -#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ -#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ -#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ - -/* two non contiguous planes - one Y, one Cr + Cb interleaved */ -#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ -#define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ - -/* three non contiguous planes - Y, Cb, Cr */ -#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ - -/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ -#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ -#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ -#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ -#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ -#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ - /* 10bit raw bayer DPCM compressed to 8 bits */ -#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8') -#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8') -#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') -#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8') - /* - * 10bit raw bayer, expanded to 16 bits - * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... - */ -#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ - -/* compressed formats */ -#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ -#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ -#define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ -#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ -#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ -#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ -#define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ -#define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ -#define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ -#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 ES */ -#define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ -#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ -#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ - -/* Vendor-specific formats */ -#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ -#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */ -#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */ -#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */ -#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */ -#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */ -#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */ -#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */ -#define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */ -#define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ -#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ -#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */ -#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ -#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ -#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ -#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */ -#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ -#define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */ -#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */ -#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ -#define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ -#define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ -#define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ - -/* - * F O R M A T E N U M E R A T I O N - */ -struct v4l2_fmtdesc { - __u32 index; /* Format number */ - __u32 type; /* enum v4l2_buf_type */ - __u32 flags; - __u8 description[32]; /* Description string */ - __u32 pixelformat; /* Format fourcc */ - __u32 reserved[4]; -}; - -#define V4L2_FMT_FLAG_COMPRESSED 0x0001 -#define V4L2_FMT_FLAG_EMULATED 0x0002 - -#if 1 - /* Experimental Frame Size and frame rate enumeration */ -/* - * F R A M E S I Z E E N U M E R A T I O N - */ -enum v4l2_frmsizetypes { - V4L2_FRMSIZE_TYPE_DISCRETE = 1, - V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, - V4L2_FRMSIZE_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmsize_discrete { - __u32 width; /* Frame width [pixel] */ - __u32 height; /* Frame height [pixel] */ -}; - -struct v4l2_frmsize_stepwise { - __u32 min_width; /* Minimum frame width [pixel] */ - __u32 max_width; /* Maximum frame width [pixel] */ - __u32 step_width; /* Frame width step size [pixel] */ - __u32 min_height; /* Minimum frame height [pixel] */ - __u32 max_height; /* Maximum frame height [pixel] */ - __u32 step_height; /* Frame height step size [pixel] */ -}; - -struct v4l2_frmsizeenum { - __u32 index; /* Frame size number */ - __u32 pixel_format; /* Pixel format */ - __u32 type; /* Frame size type the device supports. */ - - union { /* Frame size */ - struct v4l2_frmsize_discrete discrete; - struct v4l2_frmsize_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; - -/* - * F R A M E R A T E E N U M E R A T I O N - */ -enum v4l2_frmivaltypes { - V4L2_FRMIVAL_TYPE_DISCRETE = 1, - V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, - V4L2_FRMIVAL_TYPE_STEPWISE = 3, -}; - -struct v4l2_frmival_stepwise { - struct v4l2_fract min; /* Minimum frame interval [s] */ - struct v4l2_fract max; /* Maximum frame interval [s] */ - struct v4l2_fract step; /* Frame interval step size [s] */ -}; - -struct v4l2_frmivalenum { - __u32 index; /* Frame format index */ - __u32 pixel_format; /* Pixel format */ - __u32 width; /* Frame width */ - __u32 height; /* Frame height */ - __u32 type; /* Frame interval type the device supports. */ - - union { /* Frame interval */ - struct v4l2_fract discrete; - struct v4l2_frmival_stepwise stepwise; - }; - - __u32 reserved[2]; /* Reserved space for future use */ -}; -#endif - -/* - * T I M E C O D E - */ -struct v4l2_timecode { - __u32 type; - __u32 flags; - __u8 frames; - __u8 seconds; - __u8 minutes; - __u8 hours; - __u8 userbits[4]; -}; - -/* Type */ -#define V4L2_TC_TYPE_24FPS 1 -#define V4L2_TC_TYPE_25FPS 2 -#define V4L2_TC_TYPE_30FPS 3 -#define V4L2_TC_TYPE_50FPS 4 -#define V4L2_TC_TYPE_60FPS 5 - -/* Flags */ -#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ -#define V4L2_TC_FLAG_COLORFRAME 0x0002 -#define V4L2_TC_USERBITS_field 0x000C -#define V4L2_TC_USERBITS_USERDEFINED 0x0000 -#define V4L2_TC_USERBITS_8BITCHARS 0x0008 -/* The above is based on SMPTE timecodes */ - -struct v4l2_jpegcompression { - int quality; - - int APPn; /* Number of APP segment to be written, - * must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - __u32 jpeg_markers; /* Which markers should go into the JPEG - * output. Unless you exactly know what - * you do, leave them untouched. - * Inluding less markers will make the - * resulting code smaller, but there will - * be fewer applications which can read it. - * The presence of the APP and COM marker - * is influenced by APP_len and COM_len - * ONLY, not by this property! */ - -#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will - * allways use APP0 */ -}; - -/* - * M E M O R Y - M A P P I N G B U F F E R S - */ -struct v4l2_requestbuffers { - __u32 count; - __u32 type; /* enum v4l2_buf_type */ - __u32 memory; /* enum v4l2_memory */ - __u32 reserved[2]; -}; - -/** - * struct v4l2_plane - plane info for multi-planar buffers - * @bytesused: number of bytes occupied by data in the plane (payload) - * @length: size of this plane (NOT the payload) in bytes - * @mem_offset: when memory in the associated struct v4l2_buffer is - * V4L2_MEMORY_MMAP, equals the offset from the start of - * the device memory for this plane (or is a "cookie" that - * should be passed to mmap() called on the video node) - * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer - * pointing to this plane - * @data_offset: offset in the plane to the start of data; usually 0, - * unless there is a header in front of the data - * - * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer - * with two planes can have one plane for Y, and another for interleaved CbCr - * components. Each plane can reside in a separate memory buffer, or even in - * a completely separate memory node (e.g. in embedded devices). - */ -struct v4l2_plane { - __u32 bytesused; - __u32 length; - union { - __u32 mem_offset; - unsigned long userptr; - } m; - __u32 data_offset; - __u32 reserved[11]; -}; - -/** - * struct v4l2_buffer - video buffer info - * @index: id number of the buffer - * @type: enum v4l2_buf_type; buffer type (type == *_MPLANE for - * multiplanar buffers); - * @bytesused: number of bytes occupied by data in the buffer (payload); - * unused (set to 0) for multiplanar buffers - * @flags: buffer informational flags - * @field: enum v4l2_field; field order of the image in the buffer - * @timestamp: frame timestamp - * @timecode: frame timecode - * @sequence: sequence count of this frame - * @memory: enum v4l2_memory; the method, in which the actual video data is - * passed - * @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP; - * offset from the start of the device memory for this plane, - * (or a "cookie" that should be passed to mmap() as offset) - * @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR; - * a userspace pointer pointing to this buffer - * @planes: for multiplanar buffers; userspace pointer to the array of plane - * info structs for this buffer - * @length: size in bytes of the buffer (NOT its payload) for single-plane - * buffers (when type != *_MPLANE); number of elements in the - * planes array for multi-plane buffers - * @input: input number from which the video data has has been captured - * - * Contains data exchanged by application and driver using one of the Streaming - * I/O methods. - */ -struct v4l2_buffer { - __u32 index; - __u32 type; - __u32 bytesused; - __u32 flags; - __u32 field; - struct timeval timestamp; - struct v4l2_timecode timecode; - __u32 sequence; - - /* memory location */ - __u32 memory; - union { - __u32 offset; - unsigned long userptr; - struct v4l2_plane *planes; - } m; - __u32 length; - __u32 input; - __u32 reserved; -}; - -/* Flags for 'flags' field */ -#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ -#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ -#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ -#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ -#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ -#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ -/* Buffer is ready, but the data contained within is corrupted. */ -#define V4L2_BUF_FLAG_ERROR 0x0040 -#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ -#define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ -#define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */ -/* Cache handling flags */ -#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 -#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 - -/* - * O V E R L A Y P R E V I E W - */ -struct v4l2_framebuffer { - __u32 capability; - __u32 flags; -/* FIXME: in theory we should pass something like PCI device + memory - * region + offset instead of some physical address */ - void *base; - struct v4l2_pix_format fmt; -}; -/* Flags for the 'capability' field. Read only */ -#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 -#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 -#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 -#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 -#define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 -#define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 -#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 -#define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 -/* Flags for the 'flags' field. */ -#define V4L2_FBUF_FLAG_PRIMARY 0x0001 -#define V4L2_FBUF_FLAG_OVERLAY 0x0002 -#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 -#define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 -#define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 -#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 -#define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 - -struct v4l2_clip { - struct v4l2_rect c; - struct v4l2_clip *next; -}; - -struct v4l2_window { - struct v4l2_rect w; - __u32 field; /* enum v4l2_field */ - __u32 chromakey; - struct v4l2_clip *clips; - __u32 clipcount; - void *bitmap; - __u8 global_alpha; -}; - -/* - * C A P T U R E P A R A M E T E R S - */ -struct v4l2_captureparm { - __u32 capability; /* Supported modes */ - __u32 capturemode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in .1us units */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 readbuffers; /* # of buffers for read */ - __u32 reserved[4]; -}; - -/* Flags for 'capability' and 'capturemode' fields */ -#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ -#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ - -struct v4l2_outputparm { - __u32 capability; /* Supported modes */ - __u32 outputmode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in seconds */ - __u32 extendedmode; /* Driver-specific extensions */ - __u32 writebuffers; /* # of buffers for write */ - __u32 reserved[4]; -}; - -/* - * I N P U T I M A G E C R O P P I N G - */ -struct v4l2_cropcap { - __u32 type; /* enum v4l2_buf_type */ - struct v4l2_rect bounds; - struct v4l2_rect defrect; - struct v4l2_fract pixelaspect; -}; - -struct v4l2_crop { - __u32 type; /* enum v4l2_buf_type */ - struct v4l2_rect c; -}; - -/* Hints for adjustments of selection rectangle */ -#define V4L2_SEL_FLAG_GE 0x00000001 -#define V4L2_SEL_FLAG_LE 0x00000002 - -/* Selection targets */ - -/* Current cropping area */ -#define V4L2_SEL_TGT_CROP_ACTIVE 0x0000 -/* Default cropping area */ -#define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 -/* Cropping bounds */ -#define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 -/* Current composing area */ -#define V4L2_SEL_TGT_COMPOSE_ACTIVE 0x0100 -/* Default composing area */ -#define V4L2_SEL_TGT_COMPOSE_DEFAULT 0x0101 -/* Composing bounds */ -#define V4L2_SEL_TGT_COMPOSE_BOUNDS 0x0102 -/* Current composing area plus all padding pixels */ -#define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103 - -/** - * struct v4l2_selection - selection info - * @type: buffer type (do not use *_MPLANE types) - * @target: selection target, used to choose one of possible rectangles - * @flags: constraints flags - * @r: coordinates of selection window - * @reserved: for future use, rounds structure size to 64 bytes, set to zero - * - * Hardware may use multiple helper windows to process a video stream. - * The structure is used to exchange this selection areas between - * an application and a driver. - */ -struct v4l2_selection { - __u32 type; - __u32 target; - __u32 flags; - struct v4l2_rect r; - __u32 reserved[9]; -}; - - -/* - * A N A L O G V I D E O S T A N D A R D - */ - -typedef __u64 v4l2_std_id; - -/* one bit for each */ -#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) -#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) -#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) -#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) -#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) -#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) -#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) -#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) - -#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) -#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) -#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) -#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) - -#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) /* BTSC */ -#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) /* EIA-J */ -#define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000) -#define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) /* FM A2 */ - -#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) -#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) -#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) -#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) -#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) -#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) -#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) -#define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000) - -/* ATSC/HDTV */ -#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) -#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) - -/* FIXME: - Although std_id is 64 bits, there is an issue on PPC32 architecture that - makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding - this value to 32 bits. - As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide), - it should work fine. However, if needed to add more than two standards, - v4l2-common.c should be fixed. - */ - -/* - * Some macros to merge video standards in order to make live easier for the - * drivers and V4L2 applications - */ - -/* - * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is - * Missing here. - */ -#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ - V4L2_STD_NTSC_M_JP |\ - V4L2_STD_NTSC_M_KR) -/* Secam macros */ -#define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D |\ - V4L2_STD_SECAM_K |\ - V4L2_STD_SECAM_K1) -/* All Secam Standards */ -#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ - V4L2_STD_SECAM_G |\ - V4L2_STD_SECAM_H |\ - V4L2_STD_SECAM_DK |\ - V4L2_STD_SECAM_L |\ - V4L2_STD_SECAM_LC) -/* PAL macros */ -#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ - V4L2_STD_PAL_B1 |\ - V4L2_STD_PAL_G) -#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ - V4L2_STD_PAL_D1 |\ - V4L2_STD_PAL_K) -/* - * "Common" PAL - This macro is there to be compatible with the old - * V4L1 concept of "PAL": /BGDKHI. - * Several PAL standards are mising here: /M, /N and /Nc - */ -#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ - V4L2_STD_PAL_DK |\ - V4L2_STD_PAL_H |\ - V4L2_STD_PAL_I) -/* Chroma "agnostic" standards */ -#define V4L2_STD_B (V4L2_STD_PAL_B |\ - V4L2_STD_PAL_B1 |\ - V4L2_STD_SECAM_B) -#define V4L2_STD_G (V4L2_STD_PAL_G |\ - V4L2_STD_SECAM_G) -#define V4L2_STD_H (V4L2_STD_PAL_H |\ - V4L2_STD_SECAM_H) -#define V4L2_STD_L (V4L2_STD_SECAM_L |\ - V4L2_STD_SECAM_LC) -#define V4L2_STD_GH (V4L2_STD_G |\ - V4L2_STD_H) -#define V4L2_STD_DK (V4L2_STD_PAL_DK |\ - V4L2_STD_SECAM_DK) -#define V4L2_STD_BG (V4L2_STD_B |\ - V4L2_STD_G) -#define V4L2_STD_MN (V4L2_STD_PAL_M |\ - V4L2_STD_PAL_N |\ - V4L2_STD_PAL_Nc |\ - V4L2_STD_NTSC) - -/* Standards where MTS/BTSC stereo could be found */ -#define V4L2_STD_MTS (V4L2_STD_NTSC_M |\ - V4L2_STD_PAL_M |\ - V4L2_STD_PAL_N |\ - V4L2_STD_PAL_Nc) - -/* Standards for Countries with 60Hz Line frequency */ -#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ - V4L2_STD_PAL_60 |\ - V4L2_STD_NTSC |\ - V4L2_STD_NTSC_443) -/* Standards for Countries with 50Hz Line frequency */ -#define V4L2_STD_625_50 (V4L2_STD_PAL |\ - V4L2_STD_PAL_N |\ - V4L2_STD_PAL_Nc |\ - V4L2_STD_SECAM) - -#define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ - V4L2_STD_ATSC_16_VSB) -/* Macros with none and all analog standards */ -#define V4L2_STD_UNKNOWN 0 -#define V4L2_STD_ALL (V4L2_STD_525_60 |\ - V4L2_STD_625_50) - -struct v4l2_standard { - __u32 index; - v4l2_std_id id; - __u8 name[24]; - struct v4l2_fract frameperiod; /* Frames, not fields */ - __u32 framelines; - __u32 reserved[4]; -}; - -/* The DV Preset API is deprecated in favor of the DV Timings API. - New drivers shouldn't use this anymore! */ - -/* - * V I D E O T I M I N G S D V P R E S E T - */ -struct v4l2_dv_preset { - __u32 preset; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T S E N U M E R A T I O N - */ -struct v4l2_dv_enum_preset { - __u32 index; - __u32 preset; - __u8 name[32]; /* Name of the preset timing */ - __u32 width; - __u32 height; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T V A L U E S - */ -#define V4L2_DV_INVALID 0 -#define V4L2_DV_480P59_94 1 /* BT.1362 */ -#define V4L2_DV_576P50 2 /* BT.1362 */ -#define V4L2_DV_720P24 3 /* SMPTE 296M */ -#define V4L2_DV_720P25 4 /* SMPTE 296M */ -#define V4L2_DV_720P30 5 /* SMPTE 296M */ -#define V4L2_DV_720P50 6 /* SMPTE 296M */ -#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ -#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ -#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I25 11 /* BT.1120 */ -#define V4L2_DV_1080I50 12 /* SMPTE 296M */ -#define V4L2_DV_1080I60 13 /* SMPTE 296M */ -#define V4L2_DV_1080P24 14 /* SMPTE 296M */ -#define V4L2_DV_1080P25 15 /* SMPTE 296M */ -#define V4L2_DV_1080P30 16 /* SMPTE 296M */ -#define V4L2_DV_1080P50 17 /* BT.1120 */ -#define V4L2_DV_1080P60 18 /* BT.1120 */ - -/* - * D V B T T I M I N G S - */ - -/** struct v4l2_bt_timings - BT.656/BT.1120 timing data - * @width: total width of the active video in pixels - * @height: total height of the active video in lines - * @interlaced: Interlaced or progressive - * @polarities: Positive or negative polarities - * @pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 - * @hfrontporch:Horizontal front porch in pixels - * @hsync: Horizontal Sync length in pixels - * @hbackporch: Horizontal back porch in pixels - * @vfrontporch:Vertical front porch in lines - * @vsync: Vertical Sync length in lines - * @vbackporch: Vertical back porch in lines - * @il_vfrontporch:Vertical front porch for the even field - * (aka field 2) of interlaced field formats - * @il_vsync: Vertical Sync length for the even field - * (aka field 2) of interlaced field formats - * @il_vbackporch:Vertical back porch for the even field - * (aka field 2) of interlaced field formats - * @standards: Standards the timing belongs to - * @flags: Flags - * @reserved: Reserved fields, must be zeroed. - * - * A note regarding vertical interlaced timings: height refers to the total - * height of the active video frame (= two fields). The blanking timings refer - * to the blanking of each field. So the height of the total frame is - * calculated as follows: - * - * tot_height = height + vfrontporch + vsync + vbackporch + - * il_vfrontporch + il_vsync + il_vbackporch - * - * The active height of each field is height / 2. - */ -struct v4l2_bt_timings { - __u32 width; - __u32 height; - __u32 interlaced; - __u32 polarities; - __u64 pixelclock; - __u32 hfrontporch; - __u32 hsync; - __u32 hbackporch; - __u32 vfrontporch; - __u32 vsync; - __u32 vbackporch; - __u32 il_vfrontporch; - __u32 il_vsync; - __u32 il_vbackporch; - __u32 standards; - __u32 flags; - __u32 reserved[14]; -} __attribute__ ((packed)); - -/* Interlaced or progressive format */ -#define V4L2_DV_PROGRESSIVE 0 -#define V4L2_DV_INTERLACED 1 - -/* Polarities. If bit is not set, it is assumed to be negative polarity */ -#define V4L2_DV_VSYNC_POS_POL 0x00000001 -#define V4L2_DV_HSYNC_POS_POL 0x00000002 - -/* Timings standards */ -#define V4L2_DV_BT_STD_CEA861 (1 << 0) /* CEA-861 Digital TV Profile */ -#define V4L2_DV_BT_STD_DMT (1 << 1) /* VESA Discrete Monitor Timings */ -#define V4L2_DV_BT_STD_CVT (1 << 2) /* VESA Coordinated Video Timings */ -#define V4L2_DV_BT_STD_GTF (1 << 3) /* VESA Generalized Timings Formula */ - -/* Flags */ - -/* CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary - GTF' curve (GTF). In both cases the horizontal and/or vertical blanking - intervals are reduced, allowing a higher resolution over the same - bandwidth. This is a read-only flag. */ -#define V4L2_DV_FL_REDUCED_BLANKING (1 << 0) -/* CEA-861 specific: set for CEA-861 formats with a framerate of a multiple - of six. These formats can be optionally played at 1 / 1.001 speed. - This is a read-only flag. */ -#define V4L2_DV_FL_CAN_REDUCE_FPS (1 << 1) -/* CEA-861 specific: only valid for video transmitters, the flag is cleared - by receivers. - If the framerate of the format is a multiple of six, then the pixelclock - used to set up the transmitter is divided by 1.001 to make it compatible - with 60 Hz based standards such as NTSC and PAL-M that use a framerate of - 29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate - such frequencies, then the flag will also be cleared. */ -#define V4L2_DV_FL_REDUCED_FPS (1 << 2) -/* Specific to interlaced formats: if set, then field 1 is really one half-line - longer and field 2 is really one half-line shorter, so each field has - exactly the same number of half-lines. Whether half-lines can be detected - or used depends on the hardware. */ -#define V4L2_DV_FL_HALF_LINE (1 << 0) - - -/** struct v4l2_dv_timings - DV timings - * @type: the type of the timings - * @bt: BT656/1120 timings - */ -struct v4l2_dv_timings { - __u32 type; - union { - struct v4l2_bt_timings bt; - __u32 reserved[32]; - }; -} __attribute__ ((packed)); - -/* Values for the type field */ -#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ - - -/** struct v4l2_enum_dv_timings - DV timings enumeration - * @index: enumeration index - * @reserved: must be zeroed - * @timings: the timings for the given index - */ -struct v4l2_enum_dv_timings { - __u32 index; - __u32 reserved[3]; - struct v4l2_dv_timings timings; -}; - -/** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities - * @min_width: width in pixels - * @max_width: width in pixels - * @min_height: height in lines - * @max_height: height in lines - * @min_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 - * @max_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 - * @standards: Supported standards - * @capabilities: Supported capabilities - * @reserved: Must be zeroed - */ -struct v4l2_bt_timings_cap { - __u32 min_width; - __u32 max_width; - __u32 min_height; - __u32 max_height; - __u64 min_pixelclock; - __u64 max_pixelclock; - __u32 standards; - __u32 capabilities; - __u32 reserved[16]; -} __attribute__ ((packed)); - -/* Supports interlaced formats */ -#define V4L2_DV_BT_CAP_INTERLACED (1 << 0) -/* Supports progressive formats */ -#define V4L2_DV_BT_CAP_PROGRESSIVE (1 << 1) -/* Supports CVT/GTF reduced blanking */ -#define V4L2_DV_BT_CAP_REDUCED_BLANKING (1 << 2) -/* Supports custom formats */ -#define V4L2_DV_BT_CAP_CUSTOM (1 << 3) - -/** struct v4l2_dv_timings_cap - DV timings capabilities - * @type: the type of the timings (same as in struct v4l2_dv_timings) - * @bt: the BT656/1120 timings capabilities - */ -struct v4l2_dv_timings_cap { - __u32 type; - __u32 reserved[3]; - union { - struct v4l2_bt_timings_cap bt; - __u32 raw_data[32]; - }; -}; - - -/* - * V I D E O I N P U T S - */ -struct v4l2_input { - __u32 index; /* Which input */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of input */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 tuner; /* enum v4l2_tuner_type */ - v4l2_std_id std; - __u32 status; - __u32 capabilities; - __u32 reserved[3]; -}; - -/* Values for the 'type' field */ -#define V4L2_INPUT_TYPE_TUNER 1 -#define V4L2_INPUT_TYPE_CAMERA 2 - -/* field 'status' - general */ -#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ -#define V4L2_IN_ST_NO_SIGNAL 0x00000002 -#define V4L2_IN_ST_NO_COLOR 0x00000004 - -/* field 'status' - sensor orientation */ -/* If sensor is mounted upside down set both bits */ -#define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */ -#define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */ - -/* field 'status' - analog */ -#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ -#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ - -/* field 'status' - digital */ -#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ -#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ -#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ - -/* field 'status' - VCR and set-top box */ -#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ -#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ -#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ - -/* capabilities flags */ -#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * V I D E O O U T P U T S - */ -struct v4l2_output { - __u32 index; /* Which output */ - __u8 name[32]; /* Label */ - __u32 type; /* Type of output */ - __u32 audioset; /* Associated audios (bitfield) */ - __u32 modulator; /* Associated modulator */ - v4l2_std_id std; - __u32 capabilities; - __u32 reserved[3]; -}; -/* Values for the 'type' field */ -#define V4L2_OUTPUT_TYPE_MODULATOR 1 -#define V4L2_OUTPUT_TYPE_ANALOG 2 -#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 - -/* capabilities flags */ -#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ -#define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ -#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ - -/* - * C O N T R O L S - */ -struct v4l2_control { - __u32 id; - __s32 value; -}; - -struct v4l2_ext_control { - __u32 id; - __u32 size; - __u32 reserved2[1]; - union { - __s32 value; - __s64 value64; - char *string; - }; -} __attribute__ ((packed)); - -struct v4l2_ext_controls { - __u32 ctrl_class; - __u32 count; - __u32 error_idx; - __u32 reserved[2]; - struct v4l2_ext_control *controls; -}; - -/* Values for ctrl_class field */ -#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ -#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ -#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ -#define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ -#define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */ -#define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */ -#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */ -#define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */ - -#define V4L2_CTRL_ID_MASK (0x0fffffff) -#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) -#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) - -enum v4l2_ctrl_type { - V4L2_CTRL_TYPE_INTEGER = 1, - V4L2_CTRL_TYPE_BOOLEAN = 2, - V4L2_CTRL_TYPE_MENU = 3, - V4L2_CTRL_TYPE_BUTTON = 4, - V4L2_CTRL_TYPE_INTEGER64 = 5, - V4L2_CTRL_TYPE_CTRL_CLASS = 6, - V4L2_CTRL_TYPE_STRING = 7, - V4L2_CTRL_TYPE_BITMASK = 8, - V4L2_CTRL_TYPE_INTEGER_MENU = 9, -}; - -/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ -struct v4l2_queryctrl { - __u32 id; - __u32 type; /* enum v4l2_ctrl_type */ - __u8 name[32]; /* Whatever */ - __s32 minimum; /* Note signedness */ - __s32 maximum; - __s32 step; - __s32 default_value; - __u32 flags; - __u32 reserved[2]; -}; - -/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ -struct v4l2_querymenu { - __u32 id; - __u32 index; - union { - __u8 name[32]; /* Whatever */ - __s64 value; - }; - __u32 reserved; -} __attribute__ ((packed)); - -/* Control flags */ -#define V4L2_CTRL_FLAG_DISABLED 0x0001 -#define V4L2_CTRL_FLAG_GRABBED 0x0002 -#define V4L2_CTRL_FLAG_READ_ONLY 0x0004 -#define V4L2_CTRL_FLAG_UPDATE 0x0008 -#define V4L2_CTRL_FLAG_INACTIVE 0x0010 -#define V4L2_CTRL_FLAG_SLIDER 0x0020 -#define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 -#define V4L2_CTRL_FLAG_VOLATILE 0x0080 - -/* Query flag, to be ORed with the control ID */ -#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 - -/* User-class control IDs defined by V4L2 */ -#define V4L2_CID_MAX_CTRLS 1024 -#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) -#define V4L2_CID_USER_BASE V4L2_CID_BASE -/* IDs reserved for driver specific controls */ -#define V4L2_CID_PRIVATE_BASE 0x08000000 - -#define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1) -#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) -#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) -#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) -#define V4L2_CID_HUE (V4L2_CID_BASE+3) -#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) -#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) -#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) -#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) -#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) -#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) -#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) /* Deprecated */ -#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) -#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) -#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) -#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) -#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) -#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* Deprecated */ -#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) -#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) -#define V4L2_CID_GAIN (V4L2_CID_BASE+19) -#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) -#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) - -/* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */ -#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) -#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) - -#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24) -enum v4l2_power_line_frequency { - V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, - V4L2_CID_POWER_LINE_FREQUENCY_AUTO = 3, -}; -#define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) -#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) -#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) -#define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28) -#define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29) -#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30) -#define V4L2_CID_COLORFX (V4L2_CID_BASE+31) -enum v4l2_colorfx { - V4L2_COLORFX_NONE = 0, - V4L2_COLORFX_BW = 1, - V4L2_COLORFX_SEPIA = 2, - V4L2_COLORFX_NEGATIVE = 3, - V4L2_COLORFX_EMBOSS = 4, - V4L2_COLORFX_SKETCH = 5, - V4L2_COLORFX_SKY_BLUE = 6, - V4L2_COLORFX_GRASS_GREEN = 7, - V4L2_COLORFX_SKIN_WHITEN = 8, - V4L2_COLORFX_VIVID = 9, - V4L2_COLORFX_AQUA = 10, - V4L2_COLORFX_ART_FREEZE = 11, - V4L2_COLORFX_SILHOUETTE = 12, - V4L2_COLORFX_SOLARIZATION = 13, - V4L2_COLORFX_ANTIQUE = 14, - V4L2_COLORFX_SET_CBCR = 15, -}; -#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32) -#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33) - -#define V4L2_CID_ROTATE (V4L2_CID_BASE+34) -#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35) - -#define V4L2_CID_CHROMA_GAIN (V4L2_CID_BASE+36) - -#define V4L2_CID_ILLUMINATORS_1 (V4L2_CID_BASE+37) -#define V4L2_CID_ILLUMINATORS_2 (V4L2_CID_BASE+38) - -#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE (V4L2_CID_BASE+39) -#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT (V4L2_CID_BASE+40) - -#define V4L2_CID_ALPHA_COMPONENT (V4L2_CID_BASE+41) -#define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42) - -/* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+43) - -/* MPEG-class control IDs defined by V4L2 */ -#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) - -/* MPEG streams, specific to multiplexed streams */ -#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0) -enum v4l2_mpeg_stream_type { - V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */ - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */ -}; -#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1) -#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2) -#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3) -#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4) -#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5) -#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6) -#define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_MPEG_BASE+7) -enum v4l2_mpeg_stream_vbi_fmt { - V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */ - V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV format */ -}; - -/* MPEG audio controls specific to multiplexed streams */ -#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100) -enum v4l2_mpeg_audio_sampling_freq { - V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101) -enum v4l2_mpeg_audio_encoding { - V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2, - V4L2_MPEG_AUDIO_ENCODING_AAC = 3, - V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, -}; -#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) -enum v4l2_mpeg_audio_l1_bitrate { - V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1, - V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2, - V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3, - V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4, - V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5, - V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6, - V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7, - V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8, - V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9, - V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10, - V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11, - V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12, - V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103) -enum v4l2_mpeg_audio_l2_bitrate { - V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1, - V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2, - V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3, - V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4, - V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5, - V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6, - V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7, - V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8, - V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9, - V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10, - V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11, - V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12, - V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104) -enum v4l2_mpeg_audio_l3_bitrate { - V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13, -}; -#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105) -enum v4l2_mpeg_audio_mode { - V4L2_MPEG_AUDIO_MODE_STEREO = 0, - V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1, - V4L2_MPEG_AUDIO_MODE_DUAL = 2, - V4L2_MPEG_AUDIO_MODE_MONO = 3, -}; -#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106) -enum v4l2_mpeg_audio_mode_extension { - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3, -}; -#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107) -enum v4l2_mpeg_audio_emphasis { - V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0, - V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2, -}; -#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108) -enum v4l2_mpeg_audio_crc { - V4L2_MPEG_AUDIO_CRC_NONE = 0, - V4L2_MPEG_AUDIO_CRC_CRC16 = 1, -}; -#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) -#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) -#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) -enum v4l2_mpeg_audio_ac3_bitrate { - V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, - V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, - V4L2_MPEG_AUDIO_AC3_BITRATE_48K = 2, - V4L2_MPEG_AUDIO_AC3_BITRATE_56K = 3, - V4L2_MPEG_AUDIO_AC3_BITRATE_64K = 4, - V4L2_MPEG_AUDIO_AC3_BITRATE_80K = 5, - V4L2_MPEG_AUDIO_AC3_BITRATE_96K = 6, - V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7, - V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8, - V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9, - V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10, - V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11, - V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12, - V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14, - V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15, - V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16, - V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, - V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, -}; -#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_MPEG_BASE+112) -enum v4l2_mpeg_audio_dec_playback { - V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO = 0, - V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO = 1, - V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT = 2, - V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT = 3, - V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO = 4, - V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5, -}; -#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113) - -/* MPEG video controls specific to multiplexed streams */ -#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) -enum v4l2_mpeg_video_encoding { - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, -}; -#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) -enum v4l2_mpeg_video_aspect { - V4L2_MPEG_VIDEO_ASPECT_1x1 = 0, - V4L2_MPEG_VIDEO_ASPECT_4x3 = 1, - V4L2_MPEG_VIDEO_ASPECT_16x9 = 2, - V4L2_MPEG_VIDEO_ASPECT_221x100 = 3, -}; -#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202) -#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203) -#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204) -#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205) -#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206) -enum v4l2_mpeg_video_bitrate_mode { - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, -}; -#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) -#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) -#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) -#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) -#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) -#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE (V4L2_CID_MPEG_BASE+212) -#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER (V4L2_CID_MPEG_BASE+213) -#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB (V4L2_CID_MPEG_BASE+214) -#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (V4L2_CID_MPEG_BASE+215) -#define V4L2_CID_MPEG_VIDEO_HEADER_MODE (V4L2_CID_MPEG_BASE+216) -enum v4l2_mpeg_video_header_mode { - V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0, - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1, - -}; -#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217) -#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_MPEG_BASE+218) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES (V4L2_CID_MPEG_BASE+219) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB (V4L2_CID_MPEG_BASE+220) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE (V4L2_CID_MPEG_BASE+221) -enum v4l2_mpeg_video_multi_slice_mode { - V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, -}; -#define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) -#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) -#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) - -#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) -#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) -#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) -#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP (V4L2_CID_MPEG_BASE+303) -#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP (V4L2_CID_MPEG_BASE+304) -#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP (V4L2_CID_MPEG_BASE+350) -#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP (V4L2_CID_MPEG_BASE+351) -#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP (V4L2_CID_MPEG_BASE+352) -#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP (V4L2_CID_MPEG_BASE+353) -#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP (V4L2_CID_MPEG_BASE+354) -#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM (V4L2_CID_MPEG_BASE+355) -#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE (V4L2_CID_MPEG_BASE+356) -#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE (V4L2_CID_MPEG_BASE+357) -enum v4l2_mpeg_video_h264_entropy_mode { - V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC = 0, - V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC = 1, -}; -#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD (V4L2_CID_MPEG_BASE+358) -#define V4L2_CID_MPEG_VIDEO_H264_LEVEL (V4L2_CID_MPEG_BASE+359) -enum v4l2_mpeg_video_h264_level { - V4L2_MPEG_VIDEO_H264_LEVEL_1_0 = 0, - V4L2_MPEG_VIDEO_H264_LEVEL_1B = 1, - V4L2_MPEG_VIDEO_H264_LEVEL_1_1 = 2, - V4L2_MPEG_VIDEO_H264_LEVEL_1_2 = 3, - V4L2_MPEG_VIDEO_H264_LEVEL_1_3 = 4, - V4L2_MPEG_VIDEO_H264_LEVEL_2_0 = 5, - V4L2_MPEG_VIDEO_H264_LEVEL_2_1 = 6, - V4L2_MPEG_VIDEO_H264_LEVEL_2_2 = 7, - V4L2_MPEG_VIDEO_H264_LEVEL_3_0 = 8, - V4L2_MPEG_VIDEO_H264_LEVEL_3_1 = 9, - V4L2_MPEG_VIDEO_H264_LEVEL_3_2 = 10, - V4L2_MPEG_VIDEO_H264_LEVEL_4_0 = 11, - V4L2_MPEG_VIDEO_H264_LEVEL_4_1 = 12, - V4L2_MPEG_VIDEO_H264_LEVEL_4_2 = 13, - V4L2_MPEG_VIDEO_H264_LEVEL_5_0 = 14, - V4L2_MPEG_VIDEO_H264_LEVEL_5_1 = 15, -}; -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360) -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361) -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE+362) -enum v4l2_mpeg_video_h264_loop_filter_mode { - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED = 0, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED = 1, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2, -}; -#define V4L2_CID_MPEG_VIDEO_H264_PROFILE (V4L2_CID_MPEG_BASE+363) -enum v4l2_mpeg_video_h264_profile { - V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE = 0, - V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE = 1, - V4L2_MPEG_VIDEO_H264_PROFILE_MAIN = 2, - V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED = 3, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH = 4, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10 = 5, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422 = 6, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE = 7, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA = 8, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA = 9, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA = 10, - V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA = 11, - V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE = 12, - V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH = 13, - V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA = 14, - V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH = 15, - V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16, -}; -#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE (V4L2_CID_MPEG_BASE+366) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC (V4L2_CID_MPEG_BASE+367) -enum v4l2_mpeg_video_h264_vui_sar_idc { - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED = 0, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 = 1, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 = 2, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 = 3, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 = 4, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 = 5, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 = 6, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 = 7, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 = 8, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 = 9, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 = 10, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 = 11, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 = 12, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 = 13, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 = 14, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 = 15, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, - V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, -}; -#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) -#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) -#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) -#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_MPEG_BASE+403) -#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_MPEG_BASE+404) -#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_MPEG_BASE+405) -enum v4l2_mpeg_video_mpeg4_level { - V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 = 0, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B = 1, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 = 2, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 = 3, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 = 4, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B = 5, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 = 6, - V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 = 7, -}; -#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE (V4L2_CID_MPEG_BASE+406) -enum v4l2_mpeg_video_mpeg4_profile { - V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE = 0, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE = 1, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE = 2, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE = 3, - V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY = 4, -}; -#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_MPEG_BASE+407) - -/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ -#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) -enum v4l2_mpeg_cx2341x_video_spatial_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2) -enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3) -enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type { - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4) -enum v4l2_mpeg_cx2341x_video_temporal_filter_mode { - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5) -#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6) -enum v4l2_mpeg_cx2341x_video_median_filter_type { - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4, -}; -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) -#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) - -/* MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */ -#define V4L2_CID_MPEG_MFC51_BASE (V4L2_CTRL_CLASS_MPEG | 0x1100) - -#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0) -#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1) -#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE (V4L2_CID_MPEG_MFC51_BASE+2) -enum v4l2_mpeg_mfc51_video_frame_skip_mode { - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED = 0, - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT = 1, - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT = 2, -}; -#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE (V4L2_CID_MPEG_MFC51_BASE+3) -enum v4l2_mpeg_mfc51_video_force_frame_type { - V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED = 0, - V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME = 1, - V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED = 2, -}; -#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING (V4L2_CID_MPEG_MFC51_BASE+4) -#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV (V4L2_CID_MPEG_MFC51_BASE+5) -#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT (V4L2_CID_MPEG_MFC51_BASE+6) -#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF (V4L2_CID_MPEG_MFC51_BASE+7) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY (V4L2_CID_MPEG_MFC51_BASE+50) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK (V4L2_CID_MPEG_MFC51_BASE+51) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH (V4L2_CID_MPEG_MFC51_BASE+52) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54) - -/* Camera class control IDs */ -#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) -#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1) - -#define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1) -enum v4l2_exposure_auto_type { - V4L2_EXPOSURE_AUTO = 0, - V4L2_EXPOSURE_MANUAL = 1, - V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, - V4L2_EXPOSURE_APERTURE_PRIORITY = 3 -}; -#define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2) -#define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3) - -#define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4) -#define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5) -#define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6) -#define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7) - -#define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8) -#define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9) - -#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) -#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) -#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) - -#define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) -#define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) -#define V4L2_CID_ZOOM_CONTINUOUS (V4L2_CID_CAMERA_CLASS_BASE+15) - -#define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16) - -#define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17) -#define V4L2_CID_IRIS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+18) - -#define V4L2_CID_AUTO_EXPOSURE_BIAS (V4L2_CID_CAMERA_CLASS_BASE+19) - -#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE (V4L2_CID_CAMERA_CLASS_BASE+20) -enum v4l2_auto_n_preset_white_balance { - V4L2_WHITE_BALANCE_MANUAL = 0, - V4L2_WHITE_BALANCE_AUTO = 1, - V4L2_WHITE_BALANCE_INCANDESCENT = 2, - V4L2_WHITE_BALANCE_FLUORESCENT = 3, - V4L2_WHITE_BALANCE_FLUORESCENT_H = 4, - V4L2_WHITE_BALANCE_HORIZON = 5, - V4L2_WHITE_BALANCE_DAYLIGHT = 6, - V4L2_WHITE_BALANCE_FLASH = 7, - V4L2_WHITE_BALANCE_CLOUDY = 8, - V4L2_WHITE_BALANCE_SHADE = 9, -}; - -#define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) -#define V4L2_CID_IMAGE_STABILIZATION (V4L2_CID_CAMERA_CLASS_BASE+22) - -#define V4L2_CID_ISO_SENSITIVITY (V4L2_CID_CAMERA_CLASS_BASE+23) -#define V4L2_CID_ISO_SENSITIVITY_AUTO (V4L2_CID_CAMERA_CLASS_BASE+24) -enum v4l2_iso_sensitivity_auto_type { - V4L2_ISO_SENSITIVITY_MANUAL = 0, - V4L2_ISO_SENSITIVITY_AUTO = 1, -}; - -#define V4L2_CID_EXPOSURE_METERING (V4L2_CID_CAMERA_CLASS_BASE+25) -enum v4l2_exposure_metering { - V4L2_EXPOSURE_METERING_AVERAGE = 0, - V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1, - V4L2_EXPOSURE_METERING_SPOT = 2, -}; - -#define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26) -enum v4l2_scene_mode { - V4L2_SCENE_MODE_NONE = 0, - V4L2_SCENE_MODE_BACKLIGHT = 1, - V4L2_SCENE_MODE_BEACH_SNOW = 2, - V4L2_SCENE_MODE_CANDLE_LIGHT = 3, - V4L2_SCENE_MODE_DAWN_DUSK = 4, - V4L2_SCENE_MODE_FALL_COLORS = 5, - V4L2_SCENE_MODE_FIREWORKS = 6, - V4L2_SCENE_MODE_LANDSCAPE = 7, - V4L2_SCENE_MODE_NIGHT = 8, - V4L2_SCENE_MODE_PARTY_INDOOR = 9, - V4L2_SCENE_MODE_PORTRAIT = 10, - V4L2_SCENE_MODE_SPORTS = 11, - V4L2_SCENE_MODE_SUNSET = 12, - V4L2_SCENE_MODE_TEXT = 13, -}; - -#define V4L2_CID_3A_LOCK (V4L2_CID_CAMERA_CLASS_BASE+27) -#define V4L2_LOCK_EXPOSURE (1 << 0) -#define V4L2_LOCK_WHITE_BALANCE (1 << 1) -#define V4L2_LOCK_FOCUS (1 << 2) - -#define V4L2_CID_AUTO_FOCUS_START (V4L2_CID_CAMERA_CLASS_BASE+28) -#define V4L2_CID_AUTO_FOCUS_STOP (V4L2_CID_CAMERA_CLASS_BASE+29) -#define V4L2_CID_AUTO_FOCUS_STATUS (V4L2_CID_CAMERA_CLASS_BASE+30) -#define V4L2_AUTO_FOCUS_STATUS_IDLE (0 << 0) -#define V4L2_AUTO_FOCUS_STATUS_BUSY (1 << 0) -#define V4L2_AUTO_FOCUS_STATUS_REACHED (1 << 1) -#define V4L2_AUTO_FOCUS_STATUS_FAILED (1 << 2) - -#define V4L2_CID_AUTO_FOCUS_RANGE (V4L2_CID_CAMERA_CLASS_BASE+31) -enum v4l2_auto_focus_range { - V4L2_AUTO_FOCUS_RANGE_AUTO = 0, - V4L2_AUTO_FOCUS_RANGE_NORMAL = 1, - V4L2_AUTO_FOCUS_RANGE_MACRO = 2, - V4L2_AUTO_FOCUS_RANGE_INFINITY = 3, -}; - -/* FM Modulator class control IDs */ -#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) -#define V4L2_CID_FM_TX_CLASS (V4L2_CTRL_CLASS_FM_TX | 1) - -#define V4L2_CID_RDS_TX_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 1) -#define V4L2_CID_RDS_TX_PI (V4L2_CID_FM_TX_CLASS_BASE + 2) -#define V4L2_CID_RDS_TX_PTY (V4L2_CID_FM_TX_CLASS_BASE + 3) -#define V4L2_CID_RDS_TX_PS_NAME (V4L2_CID_FM_TX_CLASS_BASE + 5) -#define V4L2_CID_RDS_TX_RADIO_TEXT (V4L2_CID_FM_TX_CLASS_BASE + 6) - -#define V4L2_CID_AUDIO_LIMITER_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 64) -#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 65) -#define V4L2_CID_AUDIO_LIMITER_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 66) - -#define V4L2_CID_AUDIO_COMPRESSION_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 80) -#define V4L2_CID_AUDIO_COMPRESSION_GAIN (V4L2_CID_FM_TX_CLASS_BASE + 81) -#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (V4L2_CID_FM_TX_CLASS_BASE + 82) -#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (V4L2_CID_FM_TX_CLASS_BASE + 83) -#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84) - -#define V4L2_CID_PILOT_TONE_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 96) -#define V4L2_CID_PILOT_TONE_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 97) -#define V4L2_CID_PILOT_TONE_FREQUENCY (V4L2_CID_FM_TX_CLASS_BASE + 98) - -#define V4L2_CID_TUNE_PREEMPHASIS (V4L2_CID_FM_TX_CLASS_BASE + 112) -enum v4l2_preemphasis { - V4L2_PREEMPHASIS_DISABLED = 0, - V4L2_PREEMPHASIS_50_uS = 1, - V4L2_PREEMPHASIS_75_uS = 2, -}; -#define V4L2_CID_TUNE_POWER_LEVEL (V4L2_CID_FM_TX_CLASS_BASE + 113) -#define V4L2_CID_TUNE_ANTENNA_CAPACITOR (V4L2_CID_FM_TX_CLASS_BASE + 114) - -/* Flash and privacy (indicator) light controls */ -#define V4L2_CID_FLASH_CLASS_BASE (V4L2_CTRL_CLASS_FLASH | 0x900) -#define V4L2_CID_FLASH_CLASS (V4L2_CTRL_CLASS_FLASH | 1) - -#define V4L2_CID_FLASH_LED_MODE (V4L2_CID_FLASH_CLASS_BASE + 1) -enum v4l2_flash_led_mode { - V4L2_FLASH_LED_MODE_NONE, - V4L2_FLASH_LED_MODE_FLASH, - V4L2_FLASH_LED_MODE_TORCH, -}; - -#define V4L2_CID_FLASH_STROBE_SOURCE (V4L2_CID_FLASH_CLASS_BASE + 2) -enum v4l2_flash_strobe_source { - V4L2_FLASH_STROBE_SOURCE_SOFTWARE, - V4L2_FLASH_STROBE_SOURCE_EXTERNAL, -}; - -#define V4L2_CID_FLASH_STROBE (V4L2_CID_FLASH_CLASS_BASE + 3) -#define V4L2_CID_FLASH_STROBE_STOP (V4L2_CID_FLASH_CLASS_BASE + 4) -#define V4L2_CID_FLASH_STROBE_STATUS (V4L2_CID_FLASH_CLASS_BASE + 5) - -#define V4L2_CID_FLASH_TIMEOUT (V4L2_CID_FLASH_CLASS_BASE + 6) -#define V4L2_CID_FLASH_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 7) -#define V4L2_CID_FLASH_TORCH_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 8) -#define V4L2_CID_FLASH_INDICATOR_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 9) - -#define V4L2_CID_FLASH_FAULT (V4L2_CID_FLASH_CLASS_BASE + 10) -#define V4L2_FLASH_FAULT_OVER_VOLTAGE (1 << 0) -#define V4L2_FLASH_FAULT_TIMEOUT (1 << 1) -#define V4L2_FLASH_FAULT_OVER_TEMPERATURE (1 << 2) -#define V4L2_FLASH_FAULT_SHORT_CIRCUIT (1 << 3) -#define V4L2_FLASH_FAULT_OVER_CURRENT (1 << 4) -#define V4L2_FLASH_FAULT_INDICATOR (1 << 5) - -#define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) -#define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) - -/* JPEG-class control IDs defined by V4L2 */ -#define V4L2_CID_JPEG_CLASS_BASE (V4L2_CTRL_CLASS_JPEG | 0x900) -#define V4L2_CID_JPEG_CLASS (V4L2_CTRL_CLASS_JPEG | 1) - -#define V4L2_CID_JPEG_CHROMA_SUBSAMPLING (V4L2_CID_JPEG_CLASS_BASE + 1) -enum v4l2_jpeg_chroma_subsampling { - V4L2_JPEG_CHROMA_SUBSAMPLING_444 = 0, - V4L2_JPEG_CHROMA_SUBSAMPLING_422 = 1, - V4L2_JPEG_CHROMA_SUBSAMPLING_420 = 2, - V4L2_JPEG_CHROMA_SUBSAMPLING_411 = 3, - V4L2_JPEG_CHROMA_SUBSAMPLING_410 = 4, - V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY = 5, -}; -#define V4L2_CID_JPEG_RESTART_INTERVAL (V4L2_CID_JPEG_CLASS_BASE + 2) -#define V4L2_CID_JPEG_COMPRESSION_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 3) - -#define V4L2_CID_JPEG_ACTIVE_MARKER (V4L2_CID_JPEG_CLASS_BASE + 4) -#define V4L2_JPEG_ACTIVE_MARKER_APP0 (1 << 0) -#define V4L2_JPEG_ACTIVE_MARKER_APP1 (1 << 1) -#define V4L2_JPEG_ACTIVE_MARKER_COM (1 << 16) -#define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17) -#define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18) - -/* Image source controls */ -#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900) -#define V4L2_CID_IMAGE_SOURCE_CLASS (V4L2_CTRL_CLASS_IMAGE_SOURCE | 1) - -#define V4L2_CID_VBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1) -#define V4L2_CID_HBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2) -#define V4L2_CID_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3) - -/* Image processing controls */ -#define V4L2_CID_IMAGE_PROC_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_PROC | 0x900) -#define V4L2_CID_IMAGE_PROC_CLASS (V4L2_CTRL_CLASS_IMAGE_PROC | 1) - -#define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) -#define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) - -/* - * T U N I N G - */ -struct v4l2_tuner { - __u32 index; - __u8 name[32]; - __u32 type; /* enum v4l2_tuner_type */ - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 rxsubchans; - __u32 audmode; - __s32 signal; - __s32 afc; - __u32 reserved[4]; -}; - -struct v4l2_modulator { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 rangelow; - __u32 rangehigh; - __u32 txsubchans; - __u32 reserved[4]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_TUNER_CAP_LOW 0x0001 -#define V4L2_TUNER_CAP_NORM 0x0002 -#define V4L2_TUNER_CAP_STEREO 0x0010 -#define V4L2_TUNER_CAP_LANG2 0x0020 -#define V4L2_TUNER_CAP_SAP 0x0020 -#define V4L2_TUNER_CAP_LANG1 0x0040 -#define V4L2_TUNER_CAP_RDS 0x0080 -#define V4L2_TUNER_CAP_RDS_BLOCK_IO 0x0100 -#define V4L2_TUNER_CAP_RDS_CONTROLS 0x0200 - -/* Flags for the 'rxsubchans' field */ -#define V4L2_TUNER_SUB_MONO 0x0001 -#define V4L2_TUNER_SUB_STEREO 0x0002 -#define V4L2_TUNER_SUB_LANG2 0x0004 -#define V4L2_TUNER_SUB_SAP 0x0004 -#define V4L2_TUNER_SUB_LANG1 0x0008 -#define V4L2_TUNER_SUB_RDS 0x0010 - -/* Values for the 'audmode' field */ -#define V4L2_TUNER_MODE_MONO 0x0000 -#define V4L2_TUNER_MODE_STEREO 0x0001 -#define V4L2_TUNER_MODE_LANG2 0x0002 -#define V4L2_TUNER_MODE_SAP 0x0002 -#define V4L2_TUNER_MODE_LANG1 0x0003 -#define V4L2_TUNER_MODE_LANG1_LANG2 0x0004 - -struct v4l2_frequency { - __u32 tuner; - __u32 type; /* enum v4l2_tuner_type */ - __u32 frequency; - __u32 reserved[8]; -}; - -struct v4l2_hw_freq_seek { - __u32 tuner; - __u32 type; /* enum v4l2_tuner_type */ - __u32 seek_upward; - __u32 wrap_around; - __u32 spacing; - __u32 reserved[7]; -}; - -/* - * R D S - */ - -struct v4l2_rds_data { - __u8 lsb; - __u8 msb; - __u8 block; -} __attribute__ ((packed)); - -#define V4L2_RDS_BLOCK_MSK 0x7 -#define V4L2_RDS_BLOCK_A 0 -#define V4L2_RDS_BLOCK_B 1 -#define V4L2_RDS_BLOCK_C 2 -#define V4L2_RDS_BLOCK_D 3 -#define V4L2_RDS_BLOCK_C_ALT 4 -#define V4L2_RDS_BLOCK_INVALID 7 - -#define V4L2_RDS_BLOCK_CORRECTED 0x40 -#define V4L2_RDS_BLOCK_ERROR 0x80 - -/* - * A U D I O - */ -struct v4l2_audio { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* Flags for the 'capability' field */ -#define V4L2_AUDCAP_STEREO 0x00001 -#define V4L2_AUDCAP_AVL 0x00002 - -/* Flags for the 'mode' field */ -#define V4L2_AUDMODE_AVL 0x00001 - -struct v4l2_audioout { - __u32 index; - __u8 name[32]; - __u32 capability; - __u32 mode; - __u32 reserved[2]; -}; - -/* - * M P E G S E R V I C E S - * - * NOTE: EXPERIMENTAL API - */ -#if 1 -#define V4L2_ENC_IDX_FRAME_I (0) -#define V4L2_ENC_IDX_FRAME_P (1) -#define V4L2_ENC_IDX_FRAME_B (2) -#define V4L2_ENC_IDX_FRAME_MASK (0xf) - -struct v4l2_enc_idx_entry { - __u64 offset; - __u64 pts; - __u32 length; - __u32 flags; - __u32 reserved[2]; -}; - -#define V4L2_ENC_IDX_ENTRIES (64) -struct v4l2_enc_idx { - __u32 entries; - __u32 entries_cap; - __u32 reserved[4]; - struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; -}; - - -#define V4L2_ENC_CMD_START (0) -#define V4L2_ENC_CMD_STOP (1) -#define V4L2_ENC_CMD_PAUSE (2) -#define V4L2_ENC_CMD_RESUME (3) - -/* Flags for V4L2_ENC_CMD_STOP */ -#define V4L2_ENC_CMD_STOP_AT_GOP_END (1 << 0) - -struct v4l2_encoder_cmd { - __u32 cmd; - __u32 flags; - union { - struct { - __u32 data[8]; - } raw; - }; -}; - -/* Decoder commands */ -#define V4L2_DEC_CMD_START (0) -#define V4L2_DEC_CMD_STOP (1) -#define V4L2_DEC_CMD_PAUSE (2) -#define V4L2_DEC_CMD_RESUME (3) - -/* Flags for V4L2_DEC_CMD_START */ -#define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) - -/* Flags for V4L2_DEC_CMD_PAUSE */ -#define V4L2_DEC_CMD_PAUSE_TO_BLACK (1 << 0) - -/* Flags for V4L2_DEC_CMD_STOP */ -#define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0) -#define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1) - -/* Play format requirements (returned by the driver): */ - -/* The decoder has no special format requirements */ -#define V4L2_DEC_START_FMT_NONE (0) -/* The decoder requires full GOPs */ -#define V4L2_DEC_START_FMT_GOP (1) - -/* The structure must be zeroed before use by the application - This ensures it can be extended safely in the future. */ -struct v4l2_decoder_cmd { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } start; - - struct { - __u32 data[16]; - } raw; - }; -}; -#endif - - -/* - * D A T A S E R V I C E S ( V B I ) - * - * Data services API by Michael Schimek - */ - -/* Raw VBI */ -struct v4l2_vbi_format { - __u32 sampling_rate; /* in 1 Hz */ - __u32 offset; - __u32 samples_per_line; - __u32 sample_format; /* V4L2_PIX_FMT_* */ - __s32 start[2]; - __u32 count[2]; - __u32 flags; /* V4L2_VBI_* */ - __u32 reserved[2]; /* must be zero */ -}; - -/* VBI flags */ -#define V4L2_VBI_UNSYNC (1 << 0) -#define V4L2_VBI_INTERLACED (1 << 1) - -/* Sliced VBI - * - * This implements is a proposal V4L2 API to allow SLICED VBI - * required for some hardware encoders. It should change without - * notice in the definitive implementation. - */ - -struct v4l2_sliced_vbi_format { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - __u32 io_size; - __u32 reserved[2]; /* must be zero */ -}; - -/* Teletext World System Teletext - (WST), defined on ITU-R BT.653-2 */ -#define V4L2_SLICED_TELETEXT_B (0x0001) -/* Video Program System, defined on ETS 300 231*/ -#define V4L2_SLICED_VPS (0x0400) -/* Closed Caption, defined on EIA-608 */ -#define V4L2_SLICED_CAPTION_525 (0x1000) -/* Wide Screen System, defined on ITU-R BT1119.1 */ -#define V4L2_SLICED_WSS_625 (0x4000) - -#define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) -#define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) - -struct v4l2_sliced_vbi_cap { - __u16 service_set; - /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field - service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field - (equals frame lines 313-336 for 625 line video - standards, 263-286 for 525 line standards) */ - __u16 service_lines[2][24]; - __u32 type; /* enum v4l2_buf_type */ - __u32 reserved[3]; /* must be 0 */ -}; - -struct v4l2_sliced_vbi_data { - __u32 id; - __u32 field; /* 0: first field, 1: second field */ - __u32 line; /* 1-23 */ - __u32 reserved; /* must be 0 */ - __u8 data[48]; -}; - -/* - * Sliced VBI data inserted into MPEG Streams - */ - -/* - * V4L2_MPEG_STREAM_VBI_FMT_IVTV: - * - * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an - * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI - * data - * - * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header - * definitions are not included here. See the MPEG-2 specifications for details - * on these headers. - */ - -/* Line type IDs */ -#define V4L2_MPEG_VBI_IVTV_TELETEXT_B (1) -#define V4L2_MPEG_VBI_IVTV_CAPTION_525 (4) -#define V4L2_MPEG_VBI_IVTV_WSS_625 (5) -#define V4L2_MPEG_VBI_IVTV_VPS (7) - -struct v4l2_mpeg_vbi_itv0_line { - __u8 id; /* One of V4L2_MPEG_VBI_IVTV_* above */ - __u8 data[42]; /* Sliced VBI data for the line */ -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_itv0 { - __le32 linemask[2]; /* Bitmasks of VBI service lines present */ - struct v4l2_mpeg_vbi_itv0_line line[35]; -} __attribute__ ((packed)); - -struct v4l2_mpeg_vbi_ITV0 { - struct v4l2_mpeg_vbi_itv0_line line[36]; -} __attribute__ ((packed)); - -#define V4L2_MPEG_VBI_IVTV_MAGIC0 "itv0" -#define V4L2_MPEG_VBI_IVTV_MAGIC1 "ITV0" - -struct v4l2_mpeg_vbi_fmt_ivtv { - __u8 magic[4]; - union { - struct v4l2_mpeg_vbi_itv0 itv0; - struct v4l2_mpeg_vbi_ITV0 ITV0; - }; -} __attribute__ ((packed)); - -/* - * A G G R E G A T E S T R U C T U R E S - */ - -/** - * struct v4l2_plane_pix_format - additional, per-plane format definition - * @sizeimage: maximum size in bytes required for data, for which - * this plane will be used - * @bytesperline: distance in bytes between the leftmost pixels in two - * adjacent lines - */ -struct v4l2_plane_pix_format { - __u32 sizeimage; - __u16 bytesperline; - __u16 reserved[7]; -} __attribute__ ((packed)); - -/** - * struct v4l2_pix_format_mplane - multiplanar format definition - * @width: image width in pixels - * @height: image height in pixels - * @pixelformat: little endian four character code (fourcc) - * @field: enum v4l2_field; field order (for interlaced video) - * @colorspace: enum v4l2_colorspace; supplemental to pixelformat - * @plane_fmt: per-plane information - * @num_planes: number of planes for this format - */ -struct v4l2_pix_format_mplane { - __u32 width; - __u32 height; - __u32 pixelformat; - __u32 field; - __u32 colorspace; - - struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES]; - __u8 num_planes; - __u8 reserved[11]; -} __attribute__ ((packed)); - -/** - * struct v4l2_format - stream data format - * @type: enum v4l2_buf_type; type of the data stream - * @pix: definition of an image format - * @pix_mp: definition of a multiplanar image format - * @win: definition of an overlaid image - * @vbi: raw VBI capture or output parameters - * @sliced: sliced VBI capture or output parameters - * @raw_data: placeholder for future extensions and custom formats - */ -struct v4l2_format { - __u32 type; - union { - struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ - struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */ - struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ - struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ - struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ - __u8 raw_data[200]; /* user-defined */ - } fmt; -}; - -/* Stream type-dependent parameters - */ -struct v4l2_streamparm { - __u32 type; /* enum v4l2_buf_type */ - union { - struct v4l2_captureparm capture; - struct v4l2_outputparm output; - __u8 raw_data[200]; /* user-defined */ - } parm; -}; - -/* - * E V E N T S - */ - -#define V4L2_EVENT_ALL 0 -#define V4L2_EVENT_VSYNC 1 -#define V4L2_EVENT_EOS 2 -#define V4L2_EVENT_CTRL 3 -#define V4L2_EVENT_FRAME_SYNC 4 -#define V4L2_EVENT_PRIVATE_START 0x08000000 - -/* Payload for V4L2_EVENT_VSYNC */ -struct v4l2_event_vsync { - /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */ - __u8 field; -} __attribute__ ((packed)); - -/* Payload for V4L2_EVENT_CTRL */ -#define V4L2_EVENT_CTRL_CH_VALUE (1 << 0) -#define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1) - -struct v4l2_event_ctrl { - __u32 changes; - __u32 type; - union { - __s32 value; - __s64 value64; - }; - __u32 flags; - __s32 minimum; - __s32 maximum; - __s32 step; - __s32 default_value; -}; - -struct v4l2_event_frame_sync { - __u32 frame_sequence; -}; - -struct v4l2_event { - __u32 type; - union { - struct v4l2_event_vsync vsync; - struct v4l2_event_ctrl ctrl; - struct v4l2_event_frame_sync frame_sync; - __u8 data[64]; - } u; - __u32 pending; - __u32 sequence; - struct timespec timestamp; - __u32 id; - __u32 reserved[8]; -}; - -#define V4L2_EVENT_SUB_FL_SEND_INITIAL (1 << 0) -#define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK (1 << 1) - -struct v4l2_event_subscription { - __u32 type; - __u32 id; - __u32 flags; - __u32 reserved[5]; -}; - -/* - * A D V A N C E D D E B U G G I N G - * - * NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS! - * FOR DEBUGGING, TESTING AND INTERNAL USE ONLY! - */ - -/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ - -#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ -#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ -#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ -#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ - -struct v4l2_dbg_match { - __u32 type; /* Match type */ - union { /* Match this chip, meaning determined by type */ - __u32 addr; - char name[32]; - }; -} __attribute__ ((packed)); - -struct v4l2_dbg_register { - struct v4l2_dbg_match match; - __u32 size; /* register size in bytes */ - __u64 reg; - __u64 val; -} __attribute__ ((packed)); - -/* VIDIOC_DBG_G_CHIP_IDENT */ -struct v4l2_dbg_chip_ident { - struct v4l2_dbg_match match; - __u32 ident; /* chip identifier as specified in */ - __u32 revision; /* chip revision, chip specific */ -} __attribute__ ((packed)); - -/** - * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument - * @index: on return, index of the first created buffer - * @count: entry: number of requested buffers, - * return: number of created buffers - * @memory: enum v4l2_memory; buffer memory type - * @format: frame format, for which buffers are requested - * @reserved: future extensions - */ -struct v4l2_create_buffers { - __u32 index; - __u32 count; - __u32 memory; - struct v4l2_format format; - __u32 reserved[8]; -}; - -/* - * I O C T L C O D E S F O R V I D E O D E V I C E S - * - */ -#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) -#define VIDIOC_RESERVED _IO('V', 1) -#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc) -#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) -#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) -#define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) -#define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) -#define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) -#define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) -#define VIDIOC_OVERLAY _IOW('V', 14, int) -#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) -#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) -#define VIDIOC_STREAMON _IOW('V', 18, int) -#define VIDIOC_STREAMOFF _IOW('V', 19, int) -#define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) -#define VIDIOC_S_PARM _IOWR('V', 22, struct v4l2_streamparm) -#define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id) -#define VIDIOC_S_STD _IOW('V', 24, v4l2_std_id) -#define VIDIOC_ENUMSTD _IOWR('V', 25, struct v4l2_standard) -#define VIDIOC_ENUMINPUT _IOWR('V', 26, struct v4l2_input) -#define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) -#define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) -#define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner) -#define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner) -#define VIDIOC_G_AUDIO _IOR('V', 33, struct v4l2_audio) -#define VIDIOC_S_AUDIO _IOW('V', 34, struct v4l2_audio) -#define VIDIOC_QUERYCTRL _IOWR('V', 36, struct v4l2_queryctrl) -#define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) -#define VIDIOC_G_INPUT _IOR('V', 38, int) -#define VIDIOC_S_INPUT _IOWR('V', 39, int) -#define VIDIOC_G_OUTPUT _IOR('V', 46, int) -#define VIDIOC_S_OUTPUT _IOWR('V', 47, int) -#define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) -#define VIDIOC_G_AUDOUT _IOR('V', 49, struct v4l2_audioout) -#define VIDIOC_S_AUDOUT _IOW('V', 50, struct v4l2_audioout) -#define VIDIOC_G_MODULATOR _IOWR('V', 54, struct v4l2_modulator) -#define VIDIOC_S_MODULATOR _IOW('V', 55, struct v4l2_modulator) -#define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency) -#define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency) -#define VIDIOC_CROPCAP _IOWR('V', 58, struct v4l2_cropcap) -#define VIDIOC_G_CROP _IOWR('V', 59, struct v4l2_crop) -#define VIDIOC_S_CROP _IOW('V', 60, struct v4l2_crop) -#define VIDIOC_G_JPEGCOMP _IOR('V', 61, struct v4l2_jpegcompression) -#define VIDIOC_S_JPEGCOMP _IOW('V', 62, struct v4l2_jpegcompression) -#define VIDIOC_QUERYSTD _IOR('V', 63, v4l2_std_id) -#define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format) -#define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio) -#define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout) -#define VIDIOC_G_PRIORITY _IOR('V', 67, __u32) /* enum v4l2_priority */ -#define VIDIOC_S_PRIORITY _IOW('V', 68, __u32) /* enum v4l2_priority */ -#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap) -#define VIDIOC_LOG_STATUS _IO('V', 70) -#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) -#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) -#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) -#if 1 -#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) -#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) -#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) -#define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) -#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) -#endif - -#if 1 -/* Experimental, meant for debugging, testing and internal use. - Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. - You must be root to use these ioctls. Never use these in applications! */ -#define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) -#define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) - -/* Experimental, meant for debugging, testing and internal use. - Never use this ioctl in applications! */ -#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) -#endif - -#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) - -/* These four DV Preset ioctls are deprecated in favor of the DV Timings - ioctls. */ -#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) -#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) -#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) -#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) -#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) -#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) -#define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) -#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) -#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) - -/* Experimental, the below two ioctls may change over the next couple of kernel - versions */ -#define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) -#define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) - -/* Experimental selection API */ -#define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) -#define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) - -/* Experimental, these two ioctls may change over the next couple of kernel - versions. */ -#define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) -#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) - -/* Experimental, these three ioctls may change over the next couple of kernel - versions. */ -#define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 98, struct v4l2_enum_dv_timings) -#define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) -#define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) - -/* Reminder: when adding new ioctls please add support for them to - drivers/media/video/v4l2-compat-ioctl32.c as well! */ - -#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ - -#endif /* __LINUX_VIDEODEV2_H */ diff -Nru libindi-1.0.0/libs/webcam/videodev.h libindi-1.1.0/libs/webcam/videodev.h --- libindi-1.0.0/libs/webcam/videodev.h 2015-02-15 08:52:24.000000000 +0000 +++ libindi-1.1.0/libs/webcam/videodev.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,365 +0,0 @@ -/* - Copyright 2006 Bill Dirks - Justin Schoeman - et al. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef __LINUX_VIDEODEV_H -#define __LINUX_VIDEODEV_H - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ - -struct video_capability -{ - char name[32]; - int type; - int channels; /* Num channels */ - int audios; /* Num audio devices */ - int maxwidth; /* Supported width */ - int maxheight; /* And height */ - int minwidth; /* Supported width */ - int minheight; /* And height */ -}; - - -struct video_channel -{ - int channel; - char name[32]; - int tuners; - unsigned int flags; -#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ -#define VIDEO_VC_AUDIO 2 /* Channel has audio */ - unsigned short type; -#define VIDEO_TYPE_TV 1 -#define VIDEO_TYPE_CAMERA 2 - unsigned short norm; /* Norm set by channel */ -}; - -struct video_tuner -{ - int tuner; - char name[32]; - unsigned long rangelow, rangehigh; /* Tuner range */ - unsigned int flags; -#define VIDEO_TUNER_PAL 1 -#define VIDEO_TUNER_NTSC 2 -#define VIDEO_TUNER_SECAM 4 -#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ -#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ -#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ -#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ -#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ - unsigned short mode; /* PAL/NTSC/SECAM/OTHER */ -#define VIDEO_MODE_PAL 0 -#define VIDEO_MODE_NTSC 1 -#define VIDEO_MODE_SECAM 2 -#define VIDEO_MODE_AUTO 3 - unsigned short signal; /* Signal strength 16bit scale */ -}; - -struct video_picture -{ - unsigned short brightness; - unsigned short hue; - unsigned short colour; - unsigned short contrast; - unsigned short whiteness; /* Black and white only */ - unsigned short depth; /* Capture depth */ - unsigned short palette; /* Palette in use */ -#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ -#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ -#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ -#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ -#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ -#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ -#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ -#define VIDEO_PALETTE_YUYV 8 -#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ -#define VIDEO_PALETTE_YUV420 10 -#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ -#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ -#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ -#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ -#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ -#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ -#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ -#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ -}; - -struct video_audio -{ - int audio; /* Audio channel */ - unsigned short volume; /* If settable */ - unsigned short bass, treble; - unsigned int flags; -#define VIDEO_AUDIO_MUTE 1 -#define VIDEO_AUDIO_MUTABLE 2 -#define VIDEO_AUDIO_VOLUME 4 -#define VIDEO_AUDIO_BASS 8 -#define VIDEO_AUDIO_TREBLE 16 -#define VIDEO_AUDIO_BALANCE 32 - char name[16]; -#define VIDEO_SOUND_MONO 1 -#define VIDEO_SOUND_STEREO 2 -#define VIDEO_SOUND_LANG1 4 -#define VIDEO_SOUND_LANG2 8 - unsigned short mode; - unsigned short balance; /* Stereo balance */ - unsigned short step; /* Step actual volume uses */ -}; - -struct video_clip -{ - int x,y; - int width, height; - struct video_clip *next; /* For user use/driver use only */ -}; - -struct video_window -{ - unsigned int x,y; /* Position of window */ - unsigned int width,height; /* Its size */ - unsigned int chromakey; - unsigned int flags; - struct video_clip *clips; /* Set only */ - int clipcount; -#define VIDEO_WINDOW_INTERLACE 1 -#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ -#define VIDEO_CLIP_BITMAP -1 -/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ -#define VIDEO_CLIPMAP_SIZE (128 * 625) -}; - -struct video_capture -{ - unsigned int x,y; /* Offsets into image */ - unsigned int width, height; /* Area to capture */ - unsigned short decimation; /* Decimation divider */ - unsigned short flags; /* Flags for capture */ -#define VIDEO_CAPTURE_ODD 0 /* Temporal */ -#define VIDEO_CAPTURE_EVEN 1 -}; - -struct video_buffer -{ - void *base; - int height,width; - int depth; - int bytesperline; -}; - -struct video_mmap -{ - unsigned int frame; /* Frame (0 - n) for double buffer */ - int height,width; - unsigned int format; /* should be VIDEO_PALETTE_* */ -}; - -struct video_key -{ - unsigned char key[8]; - unsigned int flags; -}; - - -#define VIDEO_MAX_FRAME 32 - -struct video_mbuf -{ - int size; /* Total memory to map */ - int frames; /* Frames */ - int offsets[VIDEO_MAX_FRAME]; -}; - - -#define VIDEO_NO_UNIT (-1) - - -struct video_unit -{ - int video; /* Video minor */ - int vbi; /* VBI minor */ - int radio; /* Radio minor */ - int audio; /* Audio minor */ - int teletext; /* Teletext minor */ -}; - -struct vbi_format { - unsigned int sampling_rate; /* in Hz */ - unsigned int samples_per_line; - unsigned int sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ - int start[2]; /* starting line for each frame */ - unsigned int count[2]; /* count of lines for each frame */ - unsigned int flags; -#define VBI_UNSYNC 1 /* can distingues between top/bottom field */ -#define VBI_INTERLACED 2 /* lines are interlaced */ -}; - -/* video_info is biased towards hardware mpeg encode/decode */ -/* but it could apply generically to any hardware compressor/decompressor */ -struct video_info -{ - unsigned int frame_count; /* frames output since decode/encode began */ - unsigned int h_size; /* current unscaled horizontal size */ - unsigned int v_size; /* current unscaled veritcal size */ - unsigned int smpte_timecode; /* current SMPTE timecode (for current GOP) */ - unsigned int picture_type; /* current picture type */ - unsigned int temporal_reference; /* current temporal reference */ - unsigned char user_data[256]; /* user data last found in compressed stream */ - /* user_data[0] contains user data flags, user_data[1] has count */ -}; - -/* generic structure for setting playback modes */ -struct video_play_mode -{ - int mode; - int p1; - int p2; -}; - -/* for loading microcode / fpga programming */ -struct video_code -{ - char loadwhat[16]; /* name or tag of file being passed */ - int datasize; - unsigned char *data; -}; - -#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ -#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ -#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ -#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ -#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ -#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ -#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ -#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ -#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ -#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ -#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ -#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ -#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ -#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ -#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ -#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ -#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ -#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ -#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ -#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ -#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ -#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ -#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ -#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ -#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ -#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ -#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ -#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ -#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ - - -#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ - -/* VIDIOCSWRITEMODE */ -#define VID_WRITE_MPEG_AUD 0 -#define VID_WRITE_MPEG_VID 1 -#define VID_WRITE_OSD 2 -#define VID_WRITE_TTX 3 -#define VID_WRITE_CC 4 -#define VID_WRITE_MJPEG 5 - -/* VIDIOCSPLAYMODE */ -#define VID_PLAY_VID_OUT_MODE 0 - /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ -#define VID_PLAY_GENLOCK 1 - /* p1: 0 = OFF, 1 = ON */ - /* p2: GENLOCK FINE DELAY value */ -#define VID_PLAY_NORMAL 2 -#define VID_PLAY_PAUSE 3 -#define VID_PLAY_SINGLE_FRAME 4 -#define VID_PLAY_FAST_FORWARD 5 -#define VID_PLAY_SLOW_MOTION 6 -#define VID_PLAY_IMMEDIATE_NORMAL 7 -#define VID_PLAY_SWITCH_CHANNELS 8 -#define VID_PLAY_FREEZE_FRAME 9 -#define VID_PLAY_STILL_MODE 10 -#define VID_PLAY_MASTER_MODE 11 - /* p1: see below */ -#define VID_PLAY_MASTER_NONE 1 -#define VID_PLAY_MASTER_VIDEO 2 -#define VID_PLAY_MASTER_AUDIO 3 -#define VID_PLAY_ACTIVE_SCANLINES 12 - /* p1 = first active; p2 = last active */ -#define VID_PLAY_RESET 13 -#define VID_PLAY_END_MARK 14 - - - -#define VID_HARDWARE_BT848 1 -#define VID_HARDWARE_QCAM_BW 2 -#define VID_HARDWARE_PMS 3 -#define VID_HARDWARE_QCAM_C 4 -#define VID_HARDWARE_PSEUDO 5 -#define VID_HARDWARE_SAA5249 6 -#define VID_HARDWARE_AZTECH 7 -#define VID_HARDWARE_SF16MI 8 -#define VID_HARDWARE_RTRACK 9 -#define VID_HARDWARE_ZOLTRIX 10 -#define VID_HARDWARE_SAA7146 11 -#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ -#define VID_HARDWARE_RTRACK2 13 -#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ -#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ -#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */ -#define VID_HARDWARE_BROADWAY 17 /* Broadway project */ -#define VID_HARDWARE_GEMTEK 18 -#define VID_HARDWARE_TYPHOON 19 -#define VID_HARDWARE_VINO 20 /* SGI Indy Vino */ -#define VID_HARDWARE_CADET 21 /* Cadet radio */ -#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ -#define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ -#define VID_HARDWARE_CPIA 24 -#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ -#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ -#define VID_HARDWARE_OV511 27 -#define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ -#define VID_HARDWARE_W9966 29 -#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ -#define VID_HARDWARE_PWC 31 /* Philips webcams */ -#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ -#define VID_HARDWARE_CPIA2 33 -#define VID_HARDWARE_VICAM 34 -#define VID_HARDWARE_SF16FMR2 35 -#define VID_HARDWARE_W9968CF 36 -#endif /* __LINUX_VIDEODEV_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff -Nru libindi-1.0.0/.project libindi-1.1.0/.project --- libindi-1.0.0/.project 1970-01-01 00:00:00.000000000 +0000 +++ libindi-1.1.0/.project 2015-09-06 13:17:35.000000000 +0000 @@ -0,0 +1,11 @@ + + + Project-Source@libindi + + + + + + + +