diff --git a/cmake_modules/FindASTROASIS.cmake b/cmake_modules/FindASTROASIS.cmake index 35f8c591d..d066727ef 100644 --- a/cmake_modules/FindASTROASIS.cmake +++ b/cmake_modules/FindASTROASIS.cmake @@ -22,12 +22,22 @@ else (ASTROASIS_INCLUDE_DIR AND ASTROASIS_LIBRARIES) ${GNUWIN32_DIR}/include ) - find_library(ASTROASIS_LIBRARIES NAMES oasisfocuser + find_library(ASTROASIS_FOCUSER_LIBRARIES NAMES oasisfocuser PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) + find_library(ASTROASIS_FILTER_WHEEL_LIBRARIES NAMES oasisfilterwheel + PATHS + ${_obLinkDir} + ${GNUWIN32_DIR}/lib + ) + + if (ASTROASIS_FOCUSER_LIBRARIES AND ASTROASIS_FILTER_WHEEL_LIBRARIES) + set(ASTROASIS_LIBRARIES ${ASTROASIS_FOCUSER_LIBRARIES} ${ASTROASIS_FILTER_WHEEL_LIBRARIES}) + endif (ASTROASIS_FOCUSER_LIBRARIES AND ASTROASIS_FILTER_WHEEL_LIBRARIES) + if(ASTROASIS_INCLUDE_DIR AND ASTROASIS_LIBRARIES) set(ASTROASIS_FOUND TRUE) else (ASTROASIS_INCLUDE_DIR AND ASTROASIS_LIBRARIES) diff --git a/debian/indi-astroasis/changelog b/debian/indi-astroasis/changelog index 6926922ac..5e4ecee4e 100644 --- a/debian/indi-astroasis/changelog +++ b/debian/indi-astroasis/changelog @@ -1,3 +1,10 @@ +indi-astroasis (1.1) jammy; urgency=medium + + * Add Oasis Filter Wheel driver. + * Update compilation and installation instructions. + + -- Frank Chen Mon, 2 Oct 2023 21:00:00 +0800 + indi-astroasis (1.0) jammy; urgency=medium * Initial release. diff --git a/debian/libastroasis/changelog b/debian/libastroasis/changelog index b9c4d854a..78ba0a734 100644 --- a/debian/libastroasis/changelog +++ b/debian/libastroasis/changelog @@ -1,3 +1,9 @@ +libastroasis (1.1.0) jammy; urgency=medium + + * Add Oasis Filter Wheel driver library files. + + -- Frank Chen Sun, 1 Oct 2023 01:00:00 +0800 + libastroasis (1.0.5) jammy; urgency=medium * Initial Release. diff --git a/indi-astroasis/CMakeLists.txt b/indi-astroasis/CMakeLists.txt index 10ee530f0..e797d6410 100644 --- a/indi-astroasis/CMakeLists.txt +++ b/indi-astroasis/CMakeLists.txt @@ -12,7 +12,7 @@ find_package(USB1 REQUIRED) find_package(Threads REQUIRED) set(ASTROASIS_VERSION_MAJOR 1) -set(ASTROASIS_VERSION_MINOR 0) +set(ASTROASIS_VERSION_MINOR 1) set(INDI_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/indi") @@ -35,11 +35,22 @@ ELSE() target_link_libraries(indi_oasis_focuser ${INDI_LIBRARIES} ${ASTROASIS_LIBRARIES} ${USB1_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) ENDIF() +########### indi_oasis_filter_wheel ########### +add_executable(indi_oasis_filter_wheel ${CMAKE_CURRENT_SOURCE_DIR}/oasis_filter_wheel.cpp) +IF (APPLE) +set(CMAKE_EXE_LINKER_FLAGS "-framework IOKit -framework CoreFoundation") +target_link_libraries(indi_oasis_filter_wheel ${INDI_LIBRARIES} ${ASTROASIS_LIBRARIES} ${LIBUSB_LIBRARIES}) +ELSE() +target_link_libraries(indi_oasis_filter_wheel ${INDI_LIBRARIES} ${ASTROASIS_LIBRARIES} ${USB1_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +ENDIF() + ##################################### if (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*") target_link_libraries(indi_oasis_focuser rt) +target_link_libraries(indi_oasis_filter_wheel rt) endif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*") install(TARGETS indi_oasis_focuser RUNTIME DESTINATION bin) +install(TARGETS indi_oasis_filter_wheel RUNTIME DESTINATION bin) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/indi_astroasis.xml DESTINATION ${INDI_DATA_DIR}) diff --git a/indi-astroasis/INSTALL b/indi-astroasis/INSTALL index 272c1a309..7cbbe7265 100644 --- a/indi-astroasis/INSTALL +++ b/indi-astroasis/INSTALL @@ -1,16 +1,22 @@ Installation instructions ========================= -Compile Instructions - - Assumption: INDI package installed (see https://indilib.org/download.html) - - Retrieve the sources for the Astroasis driver - git clone https://github.com/astroasis/indi-3rdparty.git - - cd indi-3rdparty - checkout branch "master" - - mkdir -p build/indi-astroasis - - cd build/indi-astroasis - - cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ../../indi-astroasis - - sudo make install +Compilation Instructions -And now start the INDI server and kstars. +Step 1: build and install libastroasis + 1) $ cd indi-3rdparty + 2) $ mkdir -p build/libastroasis + 3) $ cd build/libastroasis + 4) $ cmake -DCMAKE_INSTALL_PREFIX=/usr ../../libastroasis + 5) $ make + 6) $ sudo make install + +Step 2: build and install indi-astroasis + 1) $ cd indi-3rdparty + 2) $ mkdir -p build/indi-astroasis + 3) $ cd build/indi-astroasis + 4) $ cmake -DCMAKE_INSTALL_PREFIX=/usr ../../indi-astroasis + 5) $ make + 6) $ sudo make install +And now start the INDI server and kstars. diff --git a/indi-astroasis/indi_astroasis.xml.cmake b/indi-astroasis/indi_astroasis.xml.cmake index 10d0521e4..9a18dd18f 100644 --- a/indi-astroasis/indi_astroasis.xml.cmake +++ b/indi-astroasis/indi_astroasis.xml.cmake @@ -6,4 +6,10 @@ @ASTROASIS_VERSION_MAJOR@.@ASTROASIS_VERSION_MINOR@ + + + indi_oasis_filter_wheel + @ASTROASIS_VERSION_MAJOR@.@ASTROASIS_VERSION_MINOR@ + + diff --git a/indi-astroasis/oasis_filter_wheel.cpp b/indi-astroasis/oasis_filter_wheel.cpp new file mode 100644 index 000000000..5f1e6bc8e --- /dev/null +++ b/indi-astroasis/oasis_filter_wheel.cpp @@ -0,0 +1,434 @@ +/* + Astroasis Oasis Filter Wheel + Copyright (C) 2013-2019 Jasem Mutlaq (mutlaqja@ikarustech.com) + Copyright (C) 2023 Frank Chen (frank.chen@astroasis.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 "oasis_filter_wheel.h" +#include "config.h" +#include "indicom.h" +#include + +static class Loader +{ + std::deque> filterWheels; + public: + Loader() + { + filterWheels.push_back(std::unique_ptr(new OasisFilterWheel())); + } +} loader; + +OasisFilterWheel::OasisFilterWheel() +{ + setVersion(ASTROASIS_VERSION_MAJOR, ASTROASIS_VERSION_MINOR); +} + +bool OasisFilterWheel::initProperties() +{ + INDI::FilterWheel::initProperties(); + + // Mode + IUFillSwitch(&ModeS[0], "MODE_0", "Fast", ISS_OFF); + IUFillSwitch(&ModeS[1], "MODE_1", "Normal", ISS_OFF); + IUFillSwitch(&ModeS[2], "MODE_2", "Slow", ISS_OFF); + IUFillSwitchVector(&ModeSP, ModeS, 3, getDeviceName(), "MODE", "Mode", + MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Auto run on power up + IUFillSwitch(&AutoRunS[INDI_ENABLED], "INDI_ENABLED", "Enable", ISS_OFF); + IUFillSwitch(&AutoRunS[INDI_DISABLED], "INDI_DISABLED", "Disable", ISS_ON); + IUFillSwitchVector(&AutoRunSP, AutoRunS, 2, getDeviceName(), "FILTER_AUTO_RUN", "Auto run on power up", + MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); + + // Factory Reset + IUFillSwitch(&FactoryResetS[0], "FACTORY_RESET", "Reset", ISS_OFF); + IUFillSwitchVector(&FactoryResetSP, FactoryResetS, 1, getDeviceName(), "FACTORY_RESET", "Factory Reset", + MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + // Calibrate + IUFillSwitch(&CalibrateS[0], "CALIBRATE", "Calibrate", ISS_OFF); + IUFillSwitchVector(&CalibrateSP, CalibrateS, 1, getDeviceName(), "FILTER_CALIBRATION", "Calibrate", + MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); + + addAuxControls(); + setDefaultPollingPeriod(250); + return true; +} + +bool OasisFilterWheel::updateProperties() +{ + INDI::FilterWheel::updateProperties(); + + if (isConnected()) + { + OFWConfig config; + + GetFilterNames(); + + if (GetConfig(&config)) + { + AutoRunS[INDI_ENABLED].s = config.autorun ? ISS_ON : ISS_OFF; + AutoRunS[INDI_DISABLED].s = config.autorun ? ISS_OFF : ISS_ON; + + ModeS[0].s = (config.mode == 0) ? ISS_ON : ISS_OFF; + ModeS[1].s = (config.mode == 1) ? ISS_ON : ISS_OFF; + ModeS[2].s = (config.mode == 2) ? ISS_ON : ISS_OFF; + } + else + { + AutoRunSP.s = IPS_ALERT; + } + + defineProperty(&ModeSP); + defineProperty(&AutoRunSP); + defineProperty(&FactoryResetSP); + defineProperty(&CalibrateSP); + } + else + { + deleteProperty(ModeSP.name); + deleteProperty(AutoRunSP.name); + deleteProperty(FactoryResetSP.name); + deleteProperty(CalibrateSP.name); + } + + return true; +} + +const char *OasisFilterWheel::getDefaultName() +{ + return "Oasis Filter Wheel"; +} + +bool OasisFilterWheel::Connect() +{ + int number, ids[OFW_MAX_NUM]; + AOReturn ret; + + OFWScan(&number, ids); + + if (number <= 0) + { + LOG_INFO("Oasis filter wheel not found\n"); + return false; + } + + // For now we always use the first found Oasis Filter Wheel + mID = ids[0]; + + ret = OFWOpen(mID); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to open Oasis filter wheel, ret = %d\n", ret); + return false; + } + + ret = OFWGetSlotNum(mID, &number); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to get Oasis filter wheel slot number, ret = %d\n", ret); + OFWClose(mID); + return false; + } + + FilterSlotN[0].min = 1; + FilterSlotN[0].max = number; + + LOGF_INFO("Oasis filter wheel connected, %d slots\n", number); + + return true; +} + +bool OasisFilterWheel::Disconnect() +{ + OFWClose(mID); + + return true; +} + +bool OasisFilterWheel::GetFilterNames() +{ + char filterName[MAXINDINAME]; + char filterLabel[MAXINDILABEL]; + int MaxFilter = FilterSlotN[0].max; + IPState state = IPS_IDLE; + + FilterNameTP->s = IPS_BUSY; + + if (FilterNameT != nullptr) + { + for (int i = 0; i < FilterNameTP->ntp; i++) + free(FilterNameT[i].text); + delete [] FilterNameT; + } + + FilterNameT = new IText[MaxFilter]; + memset(FilterNameT, 0, sizeof(IText) * MaxFilter); + + for (int i = 0; i < MaxFilter; i++) + { + char name[MAXINDINAME]; + AOReturn ret = OFWGetSlotName(mID, i + 1, name); + + snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i + 1); + snprintf(filterLabel, MAXINDILABEL, "Filter#%d", i + 1); + IUFillText(&FilterNameT[i], filterName, filterLabel, (ret == AO_SUCCESS) ? name : filterLabel); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to get Oasis filter wheel slot name, ret = %d\n", ret); + state = IPS_ALERT; + } + } + + IUFillTextVector(FilterNameTP, FilterNameT, MaxFilter, getDeviceName(), "FILTER_NAME", "Filter", + FilterSlotNP.group, IP_RW, 0, state); + + return true; +} + +bool OasisFilterWheel::SetFilterNames() +{ + // Verify allowed filter names + std::regex rx("^[A-Za-z0-9=.#/_%[:space:]-]{1,32}$"); + + for (int i = 0; i < FilterSlotN[0].max; i++) + { + if (!std::regex_match(FilterNameT[i].text, rx)) + { + LOGF_ERROR("Filter #%d: the filter name is not valid. It should not have more than 32 chars", i + 1); + LOGF_ERROR("Filter #%d: and the valid chars are A to Z, a to z, 0 to 9 = . # / - _ percent or space", i + 1); + + return false; + } + } + + for (int i = 0; i < FilterSlotN[0].max; i++) + { + AOReturn ret = OFWSetSlotName(mID, i + 1, FilterNameT[i].text); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to set Oasis filter wheel slot name, ret = %d\n", ret); + return false; + } + } + + return true; +} + +bool OasisFilterWheel::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) +{ + if (dev != nullptr && !strcmp(dev, getDeviceName())) + { + if (!strcmp(name, ModeSP.name)) + { + OFWConfig config; + AOReturn ret; + int prev, target; + + prev = IUFindOnSwitchIndex(&ModeSP); + IUUpdateSwitch(&ModeSP, states, names, n); + target = IUFindOnSwitchIndex(&ModeSP); + + config.mask = MASK_MODE; + config.mode = target; + + ret = OFWSetConfig(mID, &config); + + if (ret == AO_SUCCESS) + { + ModeSP.s = IPS_OK; + } + else + { + LOGF_ERROR("Failed to set Oasis filter wheel mode, ret = %d\n", ret); + + IUResetSwitch(&ModeSP); + + if ((prev >= 0) && (prev < 3)) + ModeS[prev].s = ISS_ON; + + ModeSP.s = IPS_ALERT; + } + + IDSetSwitch(&ModeSP, nullptr); + + return true; + } + + if (!strcmp(name, AutoRunSP.name)) + { + OFWConfig config; + AOReturn ret; + + config.mask = MASK_AUTORUN; + config.autorun = (IUFindOnSwitchIndex(&AutoRunSP) == INDI_ENABLED) ? 0 : 1; + + ret = OFWSetConfig(mID, &config); + + if (ret == AO_SUCCESS) + { + IUUpdateSwitch(&AutoRunSP, states, names, n); + AutoRunSP.s = IPS_OK; + } + else + { + LOGF_ERROR("Failed to set Oasis filter wheel auto run, ret = %d\n", ret); + AutoRunSP.s = IPS_ALERT; + } + + IDSetSwitch(&AutoRunSP, nullptr); + + return true; + } + + if (!strcmp(name, CalibrateSP.name)) + { + AOReturn ret; + + CalibrateS[0].s = ISS_OFF; + + ret = OFWCalibrate(mID, 0); + + if (ret == AO_SUCCESS) + { + LOG_INFO("Oasis filter wheel calibrating...\n"); + CalibrateSP.s = IPS_BUSY; + SetTimer(getCurrentPollingPeriod()); + } + else + { + LOGF_ERROR("Failed to start Oasis filter wheel calibration, ret = %d\n", ret); + CalibrateSP.s = IPS_ALERT; + } + + IDSetSwitch(&CalibrateSP, nullptr); + + return true; + } + + if (!strcmp(name, FactoryResetSP.name)) + { + AOReturn ret; + + FactoryResetS[0].s = ISS_OFF; + + ret = OFWFactoryReset(mID); + + if (ret == AO_SUCCESS) + { + FactoryResetSP.s = IPS_OK; + } + else + { + LOGF_ERROR("Failed to factory reset Oasis filter wheel, ret = %d\n", ret); + FactoryResetSP.s = IPS_ALERT; + } + + IDSetSwitch(&FactoryResetSP, nullptr); + + return true; + } + } + + return INDI::FilterWheel::ISNewSwitch(dev, name, states, names, n); +} + +int OasisFilterWheel::QueryFilter() +{ + OFWStatus status; + AOReturn ret; + + ret = OFWGetStatus(mID, &status); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to get Oasis filter wheel status, ret = %d\n", ret); + return 0; + } + + CurrentFilter = (status.filterStatus == STATUS_IDLE) ? status.filterPosition : 0; + + if (status.filterStatus == STATUS_IDLE) + { + LOGF_DEBUG("CurrentFilter: %d\n", CurrentFilter); + } + else + { + LOG_INFO("Oasis filter wheel moving...\n"); + } + + return CurrentFilter; +} + +bool OasisFilterWheel::SelectFilter(int position) +{ + AOReturn ret; + + ret = OFWSetPosition(mID, position); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to set Oasis filter wheel position to %d\n", position); + return false; + } + + SetTimer(getCurrentPollingPeriod()); + + return true; +} + +void OasisFilterWheel::TimerHit() +{ + QueryFilter(); + + if (CurrentFilter != TargetFilter) + { + SetTimer(getCurrentPollingPeriod()); + } + else + { + SelectFilterDone(CurrentFilter); + + CalibrateSP.s = IPS_OK; + IDSetSwitch(&CalibrateSP, nullptr); + } +} + +bool OasisFilterWheel::saveConfigItems(FILE *fp) +{ + return INDI::FilterWheel::saveConfigItems(fp); +} + +bool OasisFilterWheel::GetConfig(OFWConfig *config) +{ + AOReturn ret = OFWGetConfig(mID, config); + + if (ret != AO_SUCCESS) + { + LOGF_ERROR("Failed to get Oasis filter wheel configuration, ret = %d\n", ret); + return false; + } + + return true; +} diff --git a/indi-astroasis/oasis_filter_wheel.h b/indi-astroasis/oasis_filter_wheel.h new file mode 100644 index 000000000..46bb986d8 --- /dev/null +++ b/indi-astroasis/oasis_filter_wheel.h @@ -0,0 +1,70 @@ +/* + Astroasis Oasis Filter Wheel + Copyright (C) 2013-2019 Jasem Mutlaq (mutlaqja@ikarustech.com) + Copyright (C) 2023 Frank Chen (frank.chen@astroasis.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 + +*/ + +#pragma once + +#include "indifilterwheel.h" +#include "OasisFilterWheel.h" + +class OasisFilterWheel : public INDI::FilterWheel +{ + public: + OasisFilterWheel(); + virtual ~OasisFilterWheel() override = default; + + const char * getDefaultName() override; + virtual bool initProperties() override; + virtual bool updateProperties() override; + virtual bool ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n) override; + + protected: + virtual bool Connect() override; + virtual bool Disconnect() override; + + virtual bool GetFilterNames() override; + virtual bool SetFilterNames() override; + virtual int QueryFilter() override; + virtual bool SelectFilter(int) override; + virtual void TimerHit() override; + virtual bool saveConfigItems(FILE *fp) override; + + private: + uint8_t mID; + + bool GetConfig(OFWConfig *config); + + // Mode + ISwitchVectorProperty ModeSP; + ISwitch ModeS[3]; + + // Auto run on power up + ISwitchVectorProperty AutoRunSP; + ISwitch AutoRunS[2]; + + // Factory Reset + ISwitchVectorProperty FactoryResetSP; + ISwitch FactoryResetS[1]; + + // Calibrate + ISwitchVectorProperty CalibrateSP; + ISwitch CalibrateS[1]; +}; diff --git a/libastroasis/CMakeLists.txt b/libastroasis/CMakeLists.txt index 811e0997c..83e468c03 100644 --- a/libastroasis/CMakeLists.txt +++ b/libastroasis/CMakeLists.txt @@ -1,34 +1,41 @@ cmake_minimum_required (VERSION 3.0) project (libastroasis) -set (OASISFOCUSER_VERSION "1.0.5") -set (OASISFOCUSER_SOVERSION "1") +set (OASIS_FOCUSER_VERSION "1.0.5") +set (OASIS_FOCUSER_SOVERSION "1") + +set (OASIS_FILTER_WHEEL_VERSION "1.0.0") +set (OASIS_FILTER_WHEEL_SOVERSION "1") list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/") list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake_modules/") include (GNUInstallDirs) include (InstallImported) -add_library (oasisfocuser SHARED IMPORTED) +add_library (oasisfocuser SHARED IMPORTED) +add_library (oasisfilterwheel SHARED IMPORTED) -set_target_properties (oasisfocuser PROPERTIES VERSION ${OASISFOCUSER_VERSION} SOVERSION ${OASISFOCUSER_SOVERSION}) +set_target_properties (oasisfocuser PROPERTIES VERSION ${OASIS_FOCUSER_VERSION} SOVERSION ${OASIS_FOCUSER_SOVERSION}) +set_target_properties (oasisfilterwheel PROPERTIES VERSION ${OASIS_FILTER_WHEEL_VERSION} SOVERSION ${OASIS_FILTER_WHEEL_SOVERSION}) if (APPLE) - set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "mac/liboasisfocuser.bin") + set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "mac/liboasisfocuser.bin") + set_property (TARGET oasisfilterwheel PROPERTY IMPORTED_LOCATION "mac/liboasisfilterwheel.bin") - FIX_MACOS_LIBRARIES("liboasisfocuser" "mac/liboasisfocuser.bin" "ASTROASIS") - - # Install library - install_imported (TARGETS oasisfocuser DESTINATION ${CMAKE_INSTALL_LIBDIR}) + FIX_MACOS_LIBRARIES("liboasisfocuser" "mac/liboasisfocuser.bin" "ASTROASIS") + FIX_MACOS_LIBRARIES("liboasisfilterwheel" "mac/liboasisfilterwheel.bin" "ASTROASIS") elseif (UNIX AND NOT WIN32) if (CMAKE_SYSTEM_PROCESSOR MATCHES "armv+") - set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "armhf/liboasisfocuser.bin") + set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "armhf/liboasisfocuser.bin") + set_property (TARGET oasisfilterwheel PROPERTY IMPORTED_LOCATION "armhf/liboasisfilterwheel.bin") elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") - set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "arm64/liboasisfocuser.bin") + set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "arm64/liboasisfocuser.bin") + set_property (TARGET oasisfilterwheel PROPERTY IMPORTED_LOCATION "arm64/liboasisfilterwheel.bin") elseif (CMAKE_SIZEOF_VOID_P MATCHES "8") - set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "x64/liboasisfocuser.bin") + set_property (TARGET oasisfocuser PROPERTY IMPORTED_LOCATION "x64/liboasisfocuser.bin") + set_property (TARGET oasisfilterwheel PROPERTY IMPORTED_LOCATION "x64/liboasisfilterwheel.bin") else () message (FATAL_ERROR "x86-32 architecture is not supported.") endif () @@ -37,10 +44,12 @@ elseif (UNIX AND NOT WIN32) set (UDEVRULES_INSTALL_DIR "/lib/udev/rules.d" CACHE STRING "Base directory for udev rules") install (FILES 99-astroasis.rules DESTINATION ${UDEVRULES_INSTALL_DIR}) - # Install library - install_imported (TARGETS oasisfocuser DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif () +# Install library +install_imported (TARGETS oasisfocuser DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install_imported (TARGETS oasisfilterwheel DESTINATION ${CMAKE_INSTALL_LIBDIR}) + # Install header files -install (FILES AOFocus.h DESTINATION include/libastroasis) +install (FILES AOFocus.h DESTINATION include/libastroasis) +install (FILES OasisFilterWheel.h DESTINATION include/libastroasis) diff --git a/libastroasis/OasisFilterWheel.h b/libastroasis/OasisFilterWheel.h new file mode 100644 index 000000000..f6159135d --- /dev/null +++ b/libastroasis/OasisFilterWheel.h @@ -0,0 +1,190 @@ +/* + * Copyright 2023 Suzhou Astroasis Vision Technology, Inc. All Rights Reserved. + * + * This is header file for Astroasis Oasis Filter Wheel . + * + * Note: + * 1. OFWScan() should be called before any other APIs (except for + * OFWGetSDKVersion()) for at least one time because those APIs require + * filter wheel ID as their first parameter. + * 2. OFWScan() can be called for multiple times at any time as long as the + * user wants to refresh filter wheels. + * 3. OFWGetSDKVersion() can be called at anytime and any place. + * 4. The buffer length for names (including product model, serial number, + * friendly name, Bluetooth name) should not be less than OFW_NAME_LEN. The + * buffer length for slot names should not be less than OFW_SLOT_NAME_LEN + * 5. The list of API functions are as follows. + * OFWScan(int *number, int *ids); + * OFWOpen(int id); + * OFWClose(int id); + * OFWGetProductModel(int id, char *model); + * OFWGetVersion(int id, OFWVersion *version); + * OFWGetSerialNumber(int id, char *sn); + * OFWGetFriendlyName(int id, char *name); + * OFWSetFriendlyName(int id, char *name); + * OFWGetBluetoothName(int id, char *name); + * OFWSetBluetoothName(int id, char *name); + * OFWGetConfig(int id, OFWConfig *config); + * OFWSetConfig(int id, OFWConfig *config); + * OFWGetStatus(int id, OFWStatus *status); + * OFWFactoryReset(int id); + * OFWGetSlotNum(int id, int* num); + * OFWGetSlotName(int id, int slot, char* name); + * OFWSetSlotName(int id, int slot, char* name); + * OFWGetFocusOffset(int id, int num, int* offset); + * OFWSetFocusOffset(int id, int num, int* offset); + * OFWGetColor(int id, int num, int* color); + * OFWSetColor(int id, int num, int* color); + * OFWSetPosition(int id, int position); + * OFWCalibrate(int id); + * OFWGetCalibrateData(int id, AOCalibrateData* calibrate); + * OFWFirmwareUpgrade(int id, unsigned char *data, int len); + * OFWGetSDKVersion(char *version); + * + * Refer to SDK demo application for the details of the API usage. + */ + +#ifndef __OASIS_FILTER_WHEEL_H__ +#define __OASIS_FILTER_WHEEL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WINDOWS +#define AOAPI __declspec(dllexport) +#else +#define AOAPI +#endif + +#define OFW_MAX_NUM 32 /* Maximum filter wheel numbers supported by this SDK */ +#define OFW_VERSION_LEN 32 /* Buffer length for version strings */ +#define OFW_NAME_LEN 32 /* Buffer length for name strings */ +#define OFW_SLOT_NAME_LEN 16 /* Buffer length for slot name strings */ + +typedef enum _AOReturn { + AO_SUCCESS = 0, /* Success */ + AO_ERROR_INVALID_ID, /* Device ID is invalid */ + AO_ERROR_INVALID_PARAMETER, /* One or more parameters are invalid */ + AO_ERROR_INVALID_STATE, /* Device is not in correct state for specific API call */ + AO_ERROR_BUFFER_TOO_SMALL, /* Size of buffer is too small */ + AO_ERROR_COMMUNICATION, /* Data communication error such as device has been removed from USB port */ + AO_ERROR_TIMEOUT, /* Timeout occured */ + AO_ERROR_BUSY, /* Device is being used by another application */ + AO_ERROR_NULL_POINTER, /* Caller passes null-pointer parameter which is not expected */ + AO_ERROR_OUT_OF_RESOURCE, /* Out of resouce such as lack of memory */ + AO_ERROR_NOT_IMPLEMENTED, /* The interface is not currently supported */ + AO_ERROR_FAULT, /* Significant fault which means the device may not work correctly and hard to recovery it */ + AO_ERROR_INVALID_SIZE, /* Size is invalid */ + AO_ERROR_INVALID_VERSION, /* Version is invalid */ + AO_ERROR_UNKNOWN = 0x40, /* Any other errors */ +} AOReturn; + +/* + * Used by OFWSetConfig() to indicate which field wants to be set + */ +#define MASK_MODE 0x00000001 +#define MASK_AUTORUN 0x00000002 +#define MASK_BLUETOOTH 0x00000004 +#define MASK_ALL 0xFFFFFFFF + +/* + * Used by OFWGetStatus() to indicate the filter status + */ +#define STATUS_IDLE 0 +#define STATUS_MOVING 1 +#define STATUS_CALIBRATING 2 +#define STATUS_BENCHMARKING 3 + +typedef struct _OFWVersion +{ + unsigned int protocal; /* Version of protocal over USB and Bluetooth communication */ + unsigned int hardware; /* Device hardware version */ + unsigned int firmware; /* Device firmware version */ + char built[24]; /* Null-terminated string which indicates firmware building time */ +} OFWVersion; + +typedef struct _OFWConfig { + unsigned int mask; /* Used by OFWSetConfig() to indicates which field wants to be set */ + int mode; /* Mode of the filter wheel operation */ + int autorun; /* Automatic switch to the target slot when power on */ + int bluetoothOn; /* 0 - Turn off Bluetooth, others - Turn on Bluetooth */ +} OFWConfig; + +typedef struct _OFWStatus { + int temperature; /* Internal (on board) temperature in 0.01 degree unit */ + int filterStatus; /* Current motor position */ + int filterPosition; /* Current motor position, zero - unknown position */ +} OFWStatus; + +typedef struct _OFWCalibrateData { + int low[4]; /* Calibration low value */ + int high[4]; /* Calibration high value */ +} OFWCalibrateData; + +/* + * API: OFWScan + * + * Description + * Scan for connected filter wheels. + * + * Parameters + * number: + * Pointer to an int value to hold the number of connected filter wheels. + * ids: + * Pointer to an int array to hold IDs of connected filter wheels. + * The length of the 'ids' array should be equal to or larger than + * OFW_MAX_NUM, and it's the caller's responsibility to allocate memory + * for "ids" before the API is called. + * The valid IDs are stored in first "number" of elements in "ids" array. + * + * Return value + * AO_SUCCESS: + * The function succeeds. This is the only value the API returns. + * + * Remarks + * This function should be called before any other APIs except for + * OFWGetSDKVersion(). + * Each filter wheel has a unique ID. If one filter wheel is removed from + * USB port and then plugged in again, it will be considered as different + * filter wheel and will be assigned with different ID during next scan. + * If one filter wheel remains connected during two or more scan operations, + * it will always have the same ID to indicate it's the same filter wheel. + * That is, the caller can call OFWScan() at any time and the IDs of + * connected filter wheels returned by previous OFWScan() will still be valid. + */ +AOAPI AOReturn OFWScan(int *number, int *ids); +AOAPI AOReturn OFWOpen(int id); +AOAPI AOReturn OFWClose(int id); +AOAPI AOReturn OFWGetProductModel(int id, char *model); +AOAPI AOReturn OFWGetVersion(int id, OFWVersion *version); +AOAPI AOReturn OFWGetSerialNumber(int id, char *sn); +AOAPI AOReturn OFWGetFriendlyName(int id, char *name); +AOAPI AOReturn OFWSetFriendlyName(int id, char *name); +AOAPI AOReturn OFWGetBluetoothName(int id, char *name); +AOAPI AOReturn OFWSetBluetoothName(int id, char *name); +AOAPI AOReturn OFWGetConfig(int id, OFWConfig *config); +AOAPI AOReturn OFWSetConfig(int id, OFWConfig *config); +AOAPI AOReturn OFWGetStatus(int id, OFWStatus *status); +AOAPI AOReturn OFWFactoryReset(int id); + +AOAPI AOReturn OFWGetSlotNum(int id, int *num); +AOAPI AOReturn OFWGetSlotName(int id, int slot, char *name); +AOAPI AOReturn OFWSetSlotName(int id, int slot, char *name); +AOAPI AOReturn OFWGetFocusOffset(int id, int num, int *offset); +AOAPI AOReturn OFWSetFocusOffset(int id, int num, int *offset); +AOAPI AOReturn OFWGetColor(int id, int num, int* color); +AOAPI AOReturn OFWSetColor(int id, int num, int* color); +AOAPI AOReturn OFWSetPosition(int id, int position); +AOAPI AOReturn OFWCalibrate(int id, int mode); +AOAPI AOReturn OFWGetCalibrateData(int id, OFWCalibrateData *calibrate); + +AOAPI AOReturn OFWUpgrade(int id); +AOAPI AOReturn OFWFirmwareUpgrade(int id, unsigned char *data, int len); +AOAPI AOReturn OFWGetSDKVersion(char *version); + +#ifdef __cplusplus +} +#endif + +#endif /* __OASIS_FILTER_WHEEL_H__ */ diff --git a/libastroasis/arm64/liboasisfilterwheel.bin b/libastroasis/arm64/liboasisfilterwheel.bin new file mode 100755 index 000000000..6cadfbf63 Binary files /dev/null and b/libastroasis/arm64/liboasisfilterwheel.bin differ diff --git a/libastroasis/armhf/liboasisfilterwheel.bin b/libastroasis/armhf/liboasisfilterwheel.bin new file mode 100755 index 000000000..d5c211997 Binary files /dev/null and b/libastroasis/armhf/liboasisfilterwheel.bin differ diff --git a/libastroasis/libastroasis.spec b/libastroasis/libastroasis.spec index 787e55cc3..e5f9a74dc 100644 --- a/libastroasis/libastroasis.spec +++ b/libastroasis/libastroasis.spec @@ -47,6 +47,8 @@ BuildRequires: pkgconfig(zlib) Provides: liboasisfocuser.so()(64bit) Provides: liboasisfocuser.so +Provides: liboasisfilterwheel.so()(64bit) +Provides: liboasisfilterwheel.so %description INDI is a distributed control protocol designed to operate diff --git a/libastroasis/x64/liboasisfilterwheel.bin b/libastroasis/x64/liboasisfilterwheel.bin new file mode 100644 index 000000000..860eb23e0 Binary files /dev/null and b/libastroasis/x64/liboasisfilterwheel.bin differ