diff --git a/C/Applications/Examples/loadMeasurement/CMakeLists.txt b/C/Applications/Examples/loadMeasurement/CMakeLists.txt index 46329b8..6ba7f0a 100644 --- a/C/Applications/Examples/loadMeasurement/CMakeLists.txt +++ b/C/Applications/Examples/loadMeasurement/CMakeLists.txt @@ -4,4 +4,4 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../../SDK/cmake/") find_package(Cuvis REQUIRED) add_executable(main main.c) -target_link_libraries(main PRIVATE cuvis::cuvis) \ No newline at end of file +target_link_libraries(main PRIVATE cuvis::c) \ No newline at end of file diff --git a/C/SDK/README.md b/C/SDK/README.md index bc5a152..00a56cc 100644 --- a/C/SDK/README.md +++ b/C/SDK/README.md @@ -19,5 +19,5 @@ If cuvis is installed to default locations, they are found automatically. Else, Finally, link against *cuvis::cuvis*. In the following example, the tarket *main* is linked against cuvis: ``` add_executable(main main.c) -target_link_libraries(main PRIVATE cuvis::cuvis) +target_link_libraries(main PRIVATE cuvis::c) ``` \ No newline at end of file diff --git a/C/SDK/cmake/FindCuvis.cmake b/C/SDK/cmake/FindCuvis.cmake index 43bc1a9..178f5d1 100644 --- a/C/SDK/cmake/FindCuvis.cmake +++ b/C/SDK/cmake/FindCuvis.cmake @@ -17,11 +17,12 @@ find_package_handle_standard_args(Cuvis DEFAULT_MSG mark_as_advanced(CUVIS_LIBRARY CUVIS_INCLUDE_DIR) -if(Cuvis_FOUND AND NOT TARGET cuvis::cuvis) - add_library(cuvis::cuvis STATIC IMPORTED) +if(Cuvis_FOUND AND NOT TARGET cuvis::c) + add_library(cuvis::c STATIC IMPORTED) set_target_properties( - cuvis::cuvis + cuvis::c PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CUVIS_INCLUDE_DIR}" IMPORTED_LOCATION ${CUVIS_LIBRARY}) + endif() \ No newline at end of file diff --git a/Cpp/Applications/Examples/loadMeasurement/CMakeLists.txt b/Cpp/Applications/Examples/loadMeasurement/CMakeLists.txt new file mode 100644 index 0000000..5ccd5af --- /dev/null +++ b/Cpp/Applications/Examples/loadMeasurement/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.20.0) +project(Example) +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/../../../SDK/cmake/") +find_package(CuvisCpp REQUIRED) +add_executable(main main.cpp) +target_link_libraries(main PRIVATE cuvis::cpp) \ No newline at end of file diff --git a/Cpp/Applications/Examples/loadMeasurement/main.cpp b/Cpp/Applications/Examples/loadMeasurement/main.cpp new file mode 100644 index 0000000..9eb09e4 --- /dev/null +++ b/Cpp/Applications/Examples/loadMeasurement/main.cpp @@ -0,0 +1,102 @@ +#include "cuvis.hpp" + +#include +#include +//#include +int main(int argc, char* argv[]) +{ + + + if (argc != 3) + { + std::cout << "To few Arguments! Please provide:" << std::endl; + std::cout << "user settings directory" << std::endl; + std::cout << "measurement file (.cu3)" << std::endl; + + return -1; + } + char* const userSettingsDir = argv[1]; + char* const measurementLoc = argv[2]; + + + + + std::cout << "Example 01 load measurement cpp " << std::endl; + std::cout <<"User Settings Dir: " << userSettingsDir << std::endl; + std::cout << "measurement file(.cu3): " <name << " " + << "t=" << mesu.get_meta()->integration_time << " ms " + << "mode=" << mesu.get_meta()->processing_mode << " " + << std::endl; + if (mesu.get_meta()->measurement_flags.size() > 0) + { + std::cout << " Flags" << std::endl; + for (auto const& flags : mesu.get_meta()->measurement_flags) + { + std::cout << " - " << flags.first << " (" << flags.second << ")" << std::endl; + } + } + + + assert( + mesu.get_meta()->processing_mode == Cube_Raw && + "This example requires raw mode"); + + + auto const& cube_it = mesu.get_imdata()->find(CUVIS_MESU_CUBE_KEY); + assert( + cube_it != mesu.get_imdata()->end() && + "Cube not found"); + + auto cube = std::get>(cube_it->second); + + //uncomment to show a single channel with openCV + /* + cv::Mat img( + cv::Size(cube._width, cube._height), + CV_16UC(cube._channels), + const_cast(reinterpret_cast(cube._data)), + cv::Mat::AUTO_STEP); + + cv::Mat singleChannel; + cv::extractChannel( + img, singleChannel, 25); // extract channel 25 as an example + singleChannel.convertTo(singleChannel, CV_8U, 1 / 16.0); + cv::imshow("channel 25", singleChannel); + cv::waitKey(0); + */ + + + std::size_t x = 120; + std::size_t y = 200; + + assert(x < cube._width && "x index exceeds cube width"); + assert(y < cube._height && "x index exceeds cube width"); + + std::cout << "lambda [nm]; raw counts [au] " << std::endl; + + for (std::size_t chn = 0; chn < cube._channels; chn++) + { + // memory layout: + //unsigned index = (y * cube.width + x) * cube.channels + chn; + //uint16_t value = cube16bit[index]; + + + auto const value = cube.get(x, y, chn); + unsigned lambda = cube._wavelength[chn]; + + std::cout << lambda << "; " << value << std::endl; + } + std::cout << "finished. " << std::endl; + + +} diff --git a/Cpp/SDK/README.md b/Cpp/SDK/README.md new file mode 100644 index 0000000..c0eaac4 --- /dev/null +++ b/Cpp/SDK/README.md @@ -0,0 +1,25 @@ +# CUVIS CPP SDK + +## Importing Cuvis CPP SDK via CMake + +In order to import cuvis to your CMake project, Cuvis must be installed (todo: add link to compatible version). + +First, you need to add the directory containing *FindCuvisCpp.cmake* to *CMAKE_MODULE_PATH*, e.g.: +``` +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") +``` + +Then you need to run the *find_package* function: +``` +find_package(CuvisCpp REQUIRED) +``` + +If cuvis is installed to default locations, they are found automatically. Else, locate the cuvis.lib and the directory containing cuvis.h. + +Finally, link against *cuvis::cuvis*. In the following example, the tarket *main* is linked against cuvis: +``` +add_executable(main main.cpp) +target_link_libraries(main PRIVATE cuvis::cpp) +``` + +Please note, that linking against cuvis::cpp will enable c++17 on the target. \ No newline at end of file diff --git a/Cpp/SDK/auxiliary/.gitkeep b/Cpp/SDK/auxiliary/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Cpp/SDK/cmake/FindCuvisCpp.cmake b/Cpp/SDK/cmake/FindCuvisCpp.cmake new file mode 100644 index 0000000..cfc8dfc --- /dev/null +++ b/Cpp/SDK/cmake/FindCuvisCpp.cmake @@ -0,0 +1,32 @@ +include(GNUInstallDirs) + +find_library( + CUVIS_LIBRARY + NAMES "cuvis" + HINTS "/lib/cuvis" "$ENV{PROGRAMFILES}/Cuvis/bin") + +find_path(CUVIS_INCLUDE_DIR + NAMES cuvis.h + HINTS "/usr/include/" "$ENV{PROGRAMFILES}/Cuvis/sdk/cuvis_c") + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(CuvisCpp DEFAULT_MSG + CUVIS_LIBRARY + CUVIS_INCLUDE_DIR) + +mark_as_advanced(CUVIS_LIBRARY CUVIS_INCLUDE_DIR) + +if(CuvisCpp_FOUND AND NOT TARGET cuvis::cpp) + + add_library(cuvis::cpp STATIC IMPORTED) + + #simmilar to the c library, we use the cuvis.dll, howver we add + #the cpp interface file as well as force the utilizing target to switch to c++17 + set_target_properties( + cuvis::cpp + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${CUVIS_INCLUDE_DIR};${CMAKE_CURRENT_LIST_DIR}/../interface" + IMPORTED_LOCATION ${CUVIS_LIBRARY}) + target_compile_features(cuvis::cpp INTERFACE cxx_std_17) +endif() \ No newline at end of file diff --git a/Cpp/SDK/interface/cuvis.hpp b/Cpp/SDK/interface/cuvis.hpp new file mode 100644 index 0000000..9b8c597 --- /dev/null +++ b/Cpp/SDK/interface/cuvis.hpp @@ -0,0 +1,2107 @@ +#pragma once + +#include "cuvis.h" +#pragma warning(disable : 26812) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cuvis +{ + //pre-declarations + class Calibration; + class Measurement; + class SessionFile; + class ProcessingContext; + class AcquisitionContext; + class Exporter; + class Async; + class AsyncMesu; + class General; + class Worker; + + struct ProcessingArgs; + + struct SaveArgs; + struct TiffArgs; + struct EnviArgs; + struct ViewArgs; + + struct SessionInfo; + + using operation_mode_t = cuvis_operation_mode_t; + using reference_type_t = cuvis_reference_type_t; + using processing_mode_t = cuvis_processing_mode_t; + using pan_sharpening_interpolation_type_t = + cuvis_pan_sharpening_interpolation_type_t; + using pan_sharpening_algorithm_t = cuvis_pan_sharpening_algorithm_t; + using tiff_compression_mode_t = cuvis_tiff_compression_mode_t; + using tiff_format_t = cuvis_tiff_format_t; + using session_info_t = cuvis_session_info_t; + using mesu_metadata_t = cuvis_mesu_metadata_t; + using sensor_info_t = cuvis_sensor_info_t; + using timestamp_t = std::chrono::time_point; + using hardware_state_t = cuvis_hardware_state_t; + using capabilities_t = cuvis_capabilities_t; + + using cpp_event_callback_t = std::function; + + void chk(CUVIS_STATUS status); + + template + struct common_image_t + { + std::size_t _width; + std::size_t _height; + std::size_t _channels; + data_t const* _data; + + data_t const& + get(std::size_t x, std::size_t y, std::size_t z = std::size_t(0)) const; + }; + + + template + struct image_t : common_image_t + { + friend class Measurement; + friend class Viewer; + + public: + uint32_t const* _wavelength; + + private: + std::shared_ptr _ref; + }; + + + + template + struct view_t : common_image_t + { + friend class Viewer; + + public: + cuvis_view_category_t _category; + bool _show; + std::string _id; + + private: + std::shared_ptr _ref; + }; + + + struct GeneralExportArgs + { + GeneralExportArgs(); + operator cuvis_export_general_settings_t() const; + + std::filesystem::path export_dir; + std::string channel_selection; + double spectra_multiplier; + double pan_scale; + pan_sharpening_interpolation_type_t pan_interpolation_type; + pan_sharpening_algorithm_t pan_algorithm; + bool add_pan; + bool add_fullscale_pan; + bool permissive; + }; + + struct SaveArgs : public GeneralExportArgs + { + SaveArgs(); + operator cuvis_save_args_t() const; + + bool allow_fragmentation; + bool allow_overwrite; + bool allow_drop; + bool allow_session_file; + bool allow_info_file; + operation_mode_t operation_mode; + double fps; + size_t soft_limit; + size_t hard_limit; + std::chrono::milliseconds max_buftime; + }; + + struct TiffArgs : public GeneralExportArgs + { + TiffArgs(); + operator cuvis_export_tiff_settings_t() const; + + tiff_compression_mode_t compression_mode; + tiff_format_t format; + }; + + struct EnviArgs : public GeneralExportArgs + { + EnviArgs() = default; + }; + + struct ViewArgs : public GeneralExportArgs + { + ViewArgs(); + operator cuvis_viewer_settings_t() const; + operator cuvis_export_view_settings_t() const; + + std::string userplugin; + bool complete; + }; + + struct ProcessingArgs + { + ProcessingArgs(); + operator cuvis_proc_args_t() const; + + processing_mode_t processing_mode; + bool allow_recalib; + }; + + struct WorkerArgs + { + WorkerArgs(); + operator cuvis_worker_settings_t() const; + + + unsigned worker_count; + std::chrono::milliseconds poll_interval; + bool keep_out_of_sequence; + int worker_queue_size; + }; + + struct SessionInfo + { + SessionInfo(); + SessionInfo(session_info_t const& sess); + + operator session_info_t() const; + + std::string name; + unsigned session_no; + unsigned sequence_no; + }; + + struct MeasurementMetaData + { + MeasurementMetaData(mesu_metadata_t const& meta); + + std::string name; + std::string path; + std::string comment; + timestamp_t capture_time; + timestamp_t factory_calibration; + std::string product_name; + std::string serial_number; + std::string assembly; + double integration_time; + unsigned averages; + SessionInfo session_info; + processing_mode_t processing_mode; + std::map measurement_flags; + }; + + struct SensorInfoData + { + SensorInfoData(sensor_info_t const& info); + /** number of averages used*/ + uint32_t averages; + /** the sensors's temperature while readout (0 if not applicable) */ + int32_t temperature; + /** gain value while recording */ + double gain; + /** the timestamp (UTC) of the image readout (senor's hardware clock )*/ + timestamp_t readout_time; + }; + + + class cuvis_sdk_exception : public std::exception + { + public: + cuvis_sdk_exception(std::string const& msg, std::wstring const& wmsg); + + char const* what(void) const noexcept; + + std::wstring what_wstr(void) const noexcept; + + protected: + std::string const _msg; + std::wstring const _wmsg; + }; + + + class General + { + public: + static void set_log_level(CUVIS_INT lvl); + static void set_exception_locale(std::string const& locale = ""); + static void register_log_callback( + std::function callback, + CUVIS_INT min_lvl); + static void reset_log_callback(); + static void register_log_callback_localized( + std::function callback, + CUVIS_INT min_lvl, + std::string const& loc_id); + static void reset_log_callback_localized(); + static std::string version(); + static void init(std::string const& settings_path); + + static CUVIS_INT register_event_callback( + cpp_event_callback_t callback, CUVIS_INT i_type); + static void unregister_event_callback(CUVIS_INT i_handler_id); + }; + + class Measurement + { + public: + friend class ProcessingContext; + friend class Exporter; + friend class AsyncMesu; + friend class Viewer; + friend class SessionFile; + friend class AcquisitionContext; + friend class Worker; + + public: + using image_variant_t = std::variant< + image_t, + image_t, + image_t, + image_t>; + + + using gps_data_t = std::map; + using string_data_t = std::map; + using image_data_t = std::map; + using sensor_info_data_t = std::map; + + public: + //shallow copy (move assignment) + Measurement& operator=(Measurement const& measurement) = default; + + //move constructor + Measurement(Measurement&& measurement) = default; + + //deep copy + Measurement(Measurement const& source); + + Measurement(std::filesystem::path const& path); + + std::vector get_capabilities() const; + + MeasurementMetaData const* get_meta() const; + + sensor_info_data_t const* get_sensor_info() const; + + gps_data_t const* get_gps() const { return _gps_data.get(); } + + image_data_t const* get_imdata() const { return _image_data.get(); } + + string_data_t const* get_strdata() const { return _string_data.get(); } + + image_t const* get_thumbnail() const; + + std::string get_calib_id() const; + + void save(SaveArgs const& args); + + void set_name(std::string const& name); + + void set_comment(std::string const& comment); + + + void refresh(); + + private: + Measurement(CUVIS_MESU handle); + + + + private: + std::shared_ptr _mesu; + + private: + std::shared_ptr _meta; + std::shared_ptr _sensor_info; + std::shared_ptr _gps_data; + std::shared_ptr _string_data; + std::shared_ptr _image_data; + std::shared_ptr> _preview_image; + }; + + class Calibration + { + friend class ProcessingContext; + friend class AcquisitionContext; + + public: + Calibration(std::filesystem::path const& path); + + std::vector + get_capabilities(CUVIS_OPERATION_MODE mode) const; + + std::string get_id() const; + + private: + std::shared_ptr _calib; + }; + + class SessionFile + { + friend class ProcessingContext; + friend class AcquisitionContext; + + public: + SessionFile(std::filesystem::path const& path); + std::optional get_mesu(CUVIS_INT frameNo) const; + std::optional get_mesu_non_dropped(CUVIS_INT frameNo) const; + + + CUVIS_INT get_size() const; + CUVIS_INT get_size_non_dropped() const; + double get_fps() const; + CUVIS_OPERATION_MODE get_operation_mode() const; + + private: + std::shared_ptr _session; + }; + + class ProcessingContext + { + friend class Worker; + + public: + //Builders + ProcessingContext(Calibration const& calib); + ProcessingContext(Measurement const& mesu); + ProcessingContext(SessionFile const& session); + //Apply + Measurement& apply(Measurement& mesu) const; + bool calc_distance(double distMM); + + public: + //setters + void set_reference(Measurement const& mesu, reference_type_t type); + void clear_reference(reference_type_t type); + void set_processingArgs(ProcessingArgs const& procArgs); + + //getters + std::optional get_reference(reference_type_t type) const; + ProcessingArgs const& get_processingArgs() const; + + //checkers + bool is_capable( + Measurement const& mesu, ProcessingArgs const& procArgs) const; + bool has_reference(reference_type_t type) const; + + std::string get_calib_id() const; + + private: + std::shared_ptr _procCont; + ProcessingArgs _procArgs; + }; + + enum class async_result_t + { + done, + timeout, + overwritten, + deferred + }; + + class Async + { + friend class AcquisitionContext; + + public: + async_result_t + get(std::chrono::milliseconds waittime = std::chrono::milliseconds(0)); + + private: + std::shared_ptr _async; + }; + + class AsyncMesu + { + friend class AcquisitionContext; + + public: + std::pair> + get(std::chrono::milliseconds waittime = std::chrono::milliseconds(0)); + + + private: + std::shared_ptr _async; + }; // namespace cuvis + + + + class AcquisitionContext + { + friend class Worker; + + public: + struct component_state_info_t + { + std::string display_name; + bool is_online; + }; + + public: + using mesu_callback_t = std::function; + using component_state_t = std::pair; + using state_callback_t = std::function)>; + + + public: + AcquisitionContext(Calibration const& calib); + ~AcquisitionContext(); + + public: + AsyncMesu capture(); + void capture_queue(); + hardware_state_t get_state() const; + std::optional get_next_measurement( + std::chrono::milliseconds timeout_ms = + std::chrono::milliseconds(0)) const; + SessionInfo get_session_info() const; + CUVIS_INT get_component_count() const; + CUVIS_COMPONENT_INFO get_component_info(CUVIS_INT id) const; + + void set_session_info(SessionInfo session); + void set_queue_size(CUVIS_INT size); + + bool has_next_measurement() const; + + void register_state_change_callback( + state_callback_t callback, bool output_initial_state = true); + void reset_state_change_callback(); + + +#define ACQ_STUB_0a(funname, sdkname, type_ifcae, type_wrapped) \ + type_wrapped get_##funname() const \ + { \ + type_ifcae res; \ + chk(sdkname##_get(*_acqCont, &res)); \ + return static_cast(res); \ + } +#define ACQ_STUB_0b(funname, sdkname, type_ifcae, type_wrapped) \ + Async set_##funname(type_wrapped value) const \ + { \ + CUVIS_ASYNC_CALL_RESULT async_handle; \ + chk(sdkname##_set_async( \ + *_acqCont, &async_handle, static_cast(value))); \ + Async async; \ + async._async = std::shared_ptr( \ + new CUVIS_ASYNC_CALL_RESULT{async_handle}, \ + [](CUVIS_ASYNC_CALL_RESULT* handle) { \ + cuvis_async_capture_free(handle); \ + delete handle; \ + }); \ + return async; \ + } + + ACQ_STUB_0a(fps, cuvis_acq_cont_fps, double, double); + ACQ_STUB_0a( + integration_time, cuvis_acq_cont_integration_time, double, double); + ACQ_STUB_0a(auto_exp, cuvis_acq_cont_auto_exp, CUVIS_INT, bool); + ACQ_STUB_0a(preview_mode, cuvis_acq_cont_preview_mode, CUVIS_INT, bool); + ACQ_STUB_0a( + operation_mode, + cuvis_acq_cont_operation_mode, + cuvis_operation_mode_t, + operation_mode_t); + ACQ_STUB_0a(average, cuvis_acq_cont_average, CUVIS_INT, int); + + ACQ_STUB_0a(bandwidth, cuvis_acq_cont_bandwidth, CUVIS_INT, int); + + ACQ_STUB_0a(queue_size, cuvis_acq_cont_queue_size, CUVIS_INT, int); + + ACQ_STUB_0a(queue_used, cuvis_acq_cont_queue_used, CUVIS_INT, int); + + ACQ_STUB_0b(fps, cuvis_acq_cont_fps, double, double); + ACQ_STUB_0b( + integration_time, cuvis_acq_cont_integration_time, double, double); + ACQ_STUB_0b(auto_exp, cuvis_acq_cont_auto_exp, CUVIS_INT, bool); + ACQ_STUB_0b(preview_mode, cuvis_acq_cont_preview_mode, CUVIS_INT, bool); + ACQ_STUB_0b( + operation_mode, + cuvis_acq_cont_operation_mode, + cuvis_operation_mode_t, + operation_mode_t); + ACQ_STUB_0b(average, cuvis_acq_cont_average, CUVIS_INT, int); + + ACQ_STUB_0b(continuous, cuvis_acq_cont_continuous, CUVIS_INT, int); + + //ACQ_STUB_0b(queue_size, cuvis_acq_cont_queue_size, CUVIS_INT, int); + +#undef ACQ_STUB_0a +#undef ACQ_STUB_0b + +#define ACQ_STUB_1a(funname, sdkname, type_ifcae, type_wrapped) \ + type_wrapped get_##funname(size_t id) const \ + { \ + type_ifcae res; \ + chk(sdkname##_get(*_acqCont, id, &res)); \ + return static_cast(res); \ + } + + ACQ_STUB_1a(component_online, cuvis_comp_online, CUVIS_INT, int); + ACQ_STUB_1a(component_gain, cuvis_comp_gain, double, double); + ACQ_STUB_1a( + component_integration_time_factor, + cuvis_comp_integration_time_factor, + double, + double); + ACQ_STUB_1a(bandwidth, cuvis_comp_bandwidth, CUVIS_INT, int); + + ACQ_STUB_1a( + driver_queue_size, cuvis_comp_driver_queue_size, CUVIS_INT, size_t); + ACQ_STUB_1a( + driver_queue_used, cuvis_comp_driver_queue_used, CUVIS_INT, size_t); + ACQ_STUB_1a( + hardware_queue_size, cuvis_comp_hardware_queue_size, CUVIS_INT, size_t); + ACQ_STUB_1a( + hardware_queue_used, cuvis_comp_hardware_queue_used, CUVIS_INT, size_t); + + ACQ_STUB_1a(temperature, cuvis_comp_temperature, CUVIS_INT, int); + +#undef ACQ_STUB_1a + +#define ACQ_STUB_1b(funname, sdkname, type_ifcae, type_wrapped) \ + Async set_##funname(size_t id, type_wrapped value) const \ + { \ + CUVIS_ASYNC_CALL_RESULT async_handle; \ + chk(sdkname##_set_async( \ + *_acqCont, id, &async_handle, static_cast(value))); \ + Async async; \ + async._async = std::shared_ptr( \ + new CUVIS_ASYNC_CALL_RESULT{async_handle}, \ + [](CUVIS_ASYNC_CALL_RESULT* handle) { \ + cuvis_async_capture_free(handle); \ + delete handle; \ + }); \ + return async; \ + } + + ACQ_STUB_1b(component_gain, cuvis_comp_gain, double, double); + ACQ_STUB_1b( + component_integration_time_factor, + cuvis_comp_integration_time_factor, + double, + double); + +#undef ACQ_STUB_1b + CUVIS_ACQ_CONT get_handle() const; + + private: + std::shared_ptr _acqCont; + std::atomic_bool _state_poll_thread_run; + + std::thread _state_poll_thread; + }; + + class Viewer + { + friend class Worker; + + public: + using viewer_settings_t = cuvis_viewer_settings_t; + using view_variant_t = std::variant, view_t>; + using view_data_t = std::map; + + + public: + Viewer(ViewArgs const& args); + view_data_t apply(Measurement const& mesu); + + private: + std::shared_ptr _viewer; + static view_data_t create_view_data(CUVIS_VIEW); + }; + + class Exporter + { + friend class Worker; + + public: + using general_export_settings_t = cuvis_export_general_settings_t; + + Measurement const& apply(Measurement const& mesu) const; + + size_t get_queue_used() const; + + protected: + Exporter() = default; + void setHandle(CUVIS_EXPORTER exporter); + + private: + std::shared_ptr _exporter; + }; + + class CubeExporter : public Exporter + { + public: + using format_settings_t = cuvis_save_args_t; + + public: + CubeExporter(SaveArgs const& args); + }; + + class TiffExporter : public Exporter + { + public: + using format_settings_t = cuvis_export_tiff_settings_t; + + public: + TiffExporter(TiffArgs const& args); + }; + + class EnviExporter : public Exporter + { + public: + EnviExporter(EnviArgs const& args); + }; + + class ViewExporter : public Exporter + { + public: + using format_settings_t = cuvis_export_view_settings_t; + + public: + ViewExporter(ViewArgs const& args); + }; + + class Worker + { + public: + struct worker_return_t + { + std::optional mesu; + std::optional view; + std::exception_ptr exception; + }; + + using worker_callback_t = std::function; + + + public: + Worker(WorkerArgs const& args); + + void set_acq_cont(AcquisitionContext const* acqCont); + void set_proc_cont(ProcessingContext const* procCont); + void set_exporter(Exporter const* exporter); + void set_viewer(Viewer const* viewer); + + + bool has_next_result() const; + worker_return_t get_next_result() const; + + void register_worker_callback( + worker_callback_t callback, unsigned concurrency = 1); + + void reset_worker_callback(); + + + size_t get_queue_size() const; + size_t get_queue_used() const; + void set_queue_size(size_t size); + + private: + std::shared_ptr _worker; + + + std::atomic_bool _worker_poll_thread_run; + + std::thread _worker_poll_thread; + }; + + + // implementation part + + + inline void chk(CUVIS_STATUS status) + { + if (status != status_ok) + { + throw cuvis_sdk_exception( + cuvis_get_last_error_msg(), cuvis_get_last_error_msg_localized()); + } + } + + inline Measurement::Measurement(Measurement const& source) + : _gps_data(std::make_shared()), + _string_data(std::make_shared()), + _image_data(std::make_shared()), + _sensor_info(std::make_shared()) + { + CUVIS_MESU copy_handle; + chk(cuvis_measurement_deep_copy(*source._mesu, ©_handle)); + + _mesu = std::shared_ptr( + new CUVIS_MESU{copy_handle}, [](CUVIS_MESU* handle) { + cuvis_measurement_free(handle); + delete handle; + }); + refresh(); + } + + + inline Measurement::Measurement(std::filesystem::path const& path) + : _gps_data(std::make_shared()), + _string_data(std::make_shared()), + _image_data(std::make_shared()), + _sensor_info(std::make_shared()) + { + CUVIS_MESU mesu; + chk(cuvis_measurement_load(path.string().c_str(), &mesu)); + + _mesu = std::shared_ptr( + new CUVIS_MESU{mesu}, [](CUVIS_MESU* handle) { + cuvis_measurement_free(handle); + delete handle; + }); + + refresh(); + } + inline Measurement::Measurement(CUVIS_MESU handle) + : _gps_data(std::make_shared()), + _string_data(std::make_shared()), + _image_data(std::make_shared()), + _sensor_info(std::make_shared()), + _mesu(std::shared_ptr( + new CUVIS_MESU{handle}, [](CUVIS_MESU* handle) { + cuvis_measurement_free(handle); + delete handle; + })) + { + refresh(); + } + + inline void Measurement::save(SaveArgs const& args) + { + chk(cuvis_measurement_save(*_mesu, args.export_dir.string().c_str(), args)); + refresh(); + } + + + + inline void Measurement::set_name(std::string const& name) + { + chk(cuvis_measurement_set_name(*_mesu, name.c_str())); + refresh(); + } + + inline void Measurement::set_comment(std::string const& comment) + { + chk(cuvis_measurement_set_comment(*_mesu, comment.c_str())); + refresh(); + } + + inline void Measurement::refresh() + { + mesu_metadata_t meta; + chk(cuvis_measurement_get_metadata(*_mesu, &meta)); + _meta = std::make_shared(meta); + + auto get_flag = [&](CUVIS_FLAGS flag, std::string const& key) -> void { + if (meta.measurement_flags & flag) + { + CUVIS_CHAR value[CUVIS_MAXBUF]; + chk(cuvis_measurement_get_data_string(*_mesu, key.c_str(), value)); + _meta->measurement_flags.emplace(key, value); + } + }; + + get_flag( + CUVIS_MESU_FLAG_OVERILLUMINATED, CUVIS_MESU_FLAG_OVERILLUMINATED_KEY); + get_flag( + CUVIS_MESU_FLAG_POOR_REFERENCE, CUVIS_MESU_FLAG_POOR_REFERENCE_KEY); + get_flag( + CUVIS_MESU_FLAG_POOR_WHITE_BALANCING, + CUVIS_MESU_FLAG_POOR_WHITE_BALANCING_KEY); + get_flag(CUVIS_MESU_FLAG_DARK_INTTIME, CUVIS_MESU_FLAG_DARK_INTTIME_KEY); + get_flag(CUVIS_MESU_FLAG_DARK_TEMP, CUVIS_MESU_FLAG_DARK_TEMP_KEY); + get_flag(CUVIS_MESU_FLAG_WHITE_INTTIME, CUVIS_MESU_FLAG_WHITE_INTTIME_KEY); + get_flag(CUVIS_MESU_FLAG_WHITE_TEMP, CUVIS_MESU_FLAG_WHITE_TEMP_KEY); + get_flag( + CUVIS_MESU_FLAG_WHITEDARK_INTTIME, + CUVIS_MESU_FLAG_WHITEDARK_INTTIME_KEY); + get_flag( + CUVIS_MESU_FLAG_WHITEDARK_TEMP, CUVIS_MESU_FLAG_WHITEDARK_TEMP_KEY); + + CUVIS_INT numel; + chk(cuvis_measurement_get_data_count(*_mesu, &numel)); + + _gps_data->clear(); + _string_data->clear(); + _image_data->clear(); + _preview_image.reset(); + _sensor_info->clear(); + + for (decltype(numel) k = decltype(numel){0}; k < numel; k++) + { + CUVIS_CHAR key[CUVIS_MAXBUF]; + cuvis_data_type_t type; + chk(cuvis_measurement_get_data_info(*_mesu, key, &type, k)); + + switch (type) + { + case cuvis_data_type_t::data_type_gps: { + cuvis_gps_t gps; + chk(cuvis_measurement_get_data_gps(*_mesu, key, &gps)); + _gps_data->emplace(std::string(key), gps); + } + break; + case cuvis_data_type_t::data_type_sensor_info: { + sensor_info_t info; + chk(cuvis_measurement_get_data_sensor_info(*_mesu, key, &info)); + _sensor_info->emplace(std::string(key), SensorInfoData(info)); + } + break; + case cuvis_data_type_t::data_type_image: { + cuvis_imbuffer_t im; + chk(cuvis_measurement_get_data_image(*_mesu, key, &im)); + switch (im.format) + { + case cuvis_imbuffer_format_t::imbuffer_format_uint8: { + image_t image({}); + image._width = im.width; + image._height = im.height; + image._channels = im.channels; + image._data = reinterpret_cast(im.raw); + image._wavelength = im.wavelength; + image._ref = _mesu; + + _image_data->emplace(std::string(key), image); + if (std::string(key) == CUVIS_MESU_PREVIEW_KEY) + { + _preview_image = std::make_shared>(image); + } + else if ( + std::string(key) == CUVIS_MESU_PAN_KEY && !_preview_image) + { + _preview_image = std::make_shared>(image); + } + } + break; + case cuvis_imbuffer_format_t::imbuffer_format_uint16: { + image_t image({}); + image._width = im.width; + image._height = im.height; + image._channels = im.channels; + image._data = reinterpret_cast(im.raw); + image._wavelength = im.wavelength; + image._ref = _mesu; + + _image_data->emplace(std::string(key), image); + } + break; + case cuvis_imbuffer_format_t::imbuffer_format_uint32: { + image_t image({}); + image._width = im.width; + image._height = im.height; + image._channels = im.channels; + image._data = reinterpret_cast(im.raw); + image._wavelength = im.wavelength; + image._ref = _mesu; + + _image_data->emplace(std::string(key), image); + } + break; + case cuvis_imbuffer_format_t::imbuffer_format_float: { + image_t image({}); + image._width = im.width; + image._height = im.height; + image._channels = im.channels; + image._data = reinterpret_cast(im.raw); + image._wavelength = im.wavelength; + image._ref = _mesu; + + _image_data->emplace(std::string(key), image); + } + break; + default: //unknown or unsupported + throw std::runtime_error( + "unsupported measurement data bit depth"); + break; + } + } + break; + case cuvis_data_type_t::data_type_string: { + CUVIS_CHAR value[CUVIS_MAXBUF]; + chk(cuvis_measurement_get_data_string(*_mesu, key, value)); + _string_data->emplace(std::string(key), std::string(value)); + } + break; + default: // unknown or unsupported + break; + } + } + } + + inline std::vector Measurement::get_capabilities() const + { + int32_t bitmap; + chk(cuvis_measurement_get_capabilities(*_mesu, &bitmap)); + std::vector capabilities; + for (int32_t i = 1; i <= 33554432; i = i * 2) + { + if ((bitmap & i) != 0) + { + capabilities.push_back(static_cast(i)); + } + } + return capabilities; + } + + inline std::string Measurement::get_calib_id() const + { + CUVIS_CHAR id[CUVIS_MAXBUF]; + chk(cuvis_measurement_get_calib_id(*_mesu, id)); + std::string res(id); + return res; + } + + inline std::string Calibration::get_id() const + { + CUVIS_CHAR id[CUVIS_MAXBUF]; + chk(cuvis_calib_get_id(*_calib, id)); + std::string res(id); + return res; + } + + inline std::string ProcessingContext::get_calib_id() const + { + CUVIS_CHAR id[CUVIS_MAXBUF]; + chk(cuvis_proc_cont_get_calib_id(*_procCont, id)); + std::string res(id); + return res; + } + + inline std::vector + Calibration::get_capabilities(CUVIS_OPERATION_MODE mode) const + { + int32_t bitmap; + chk(cuvis_calib_get_capabilities(*_calib, mode, &bitmap)); + std::vector capabilities; + for (int32_t i = 1; i <= 33554432; i = i * 2) + { + if ((bitmap & i) != 0) + { + capabilities.push_back(static_cast(i)); + } + } + return capabilities; + } + + inline image_t const* Measurement::get_thumbnail() const + { + return _preview_image.get(); + } + + inline MeasurementMetaData const* Measurement::get_meta() const + { + return _meta.get(); + } + + inline cuvis::Measurement::sensor_info_data_t const* + Measurement::get_sensor_info() const + { + return _sensor_info.get(); + } + + inline Calibration::Calibration(std::filesystem::path const& path) + { + CUVIS_CALIB calib; + chk(cuvis_calib_create_from_path(path.string().c_str(), &calib)); + + _calib = std::shared_ptr( + new CUVIS_CALIB{calib}, [](CUVIS_CALIB* handle) { + cuvis_calib_free(handle); + delete handle; + }); + } + + inline ProcessingContext::ProcessingContext(Calibration const& calib) + { + CUVIS_PROC_CONT procCont; + chk(cuvis_proc_cont_create_from_calib(*calib._calib, &procCont)); + _procCont = std::shared_ptr( + new CUVIS_PROC_CONT{procCont}, [](CUVIS_PROC_CONT* handle) { + cuvis_proc_cont_free(handle); + delete handle; + }); + } + + inline ProcessingContext::ProcessingContext(Measurement const& mesu) + { + CUVIS_PROC_CONT procCont; + chk(cuvis_proc_cont_create_from_mesu(*mesu._mesu, &procCont)); + _procCont = std::shared_ptr( + new CUVIS_PROC_CONT{procCont}, [](CUVIS_PROC_CONT* handle) { + cuvis_proc_cont_free(handle); + delete handle; + }); + } + + inline ProcessingContext::ProcessingContext(SessionFile const& session) + { + CUVIS_PROC_CONT procCont; + chk(cuvis_proc_cont_create_from_session_file(*session._session, &procCont)); + _procCont = std::shared_ptr( + new CUVIS_PROC_CONT{procCont}, [](CUVIS_PROC_CONT* handle) { + cuvis_proc_cont_free(handle); + delete handle; + }); + } + + inline Measurement& ProcessingContext::apply(Measurement& mesu) const + { + chk(cuvis_proc_cont_apply(*_procCont, *mesu._mesu)); + mesu.refresh(); + return mesu; + } + + inline void ProcessingContext::set_reference( + Measurement const& mesu, reference_type_t type) + { + chk(cuvis_proc_cont_set_reference(*_procCont, *mesu._mesu, type)); + return; + } + inline void ProcessingContext::clear_reference(reference_type_t type) + { + chk(cuvis_proc_cont_clear_reference(*_procCont, type)); + return; + } + + inline std::optional + ProcessingContext::get_reference(reference_type_t type) const + { + bool hasRef = has_reference(type); + if (!hasRef) + { + return {}; + } + + CUVIS_MESU handle; + chk(cuvis_proc_cont_get_reference(*_procCont, &handle, type)); + + Measurement mesu(handle); + + return {mesu}; + } + + inline bool ProcessingContext::calc_distance(double distMM) + { + chk(cuvis_proc_cont_calc_distance(*_procCont, distMM)); + return true; + } + + inline bool ProcessingContext::is_capable( + Measurement const& mesu, ProcessingArgs const& procArgs) const + { + CUVIS_INT isCap; + + cuvis_proc_args_t args; + args.allow_recalib = procArgs.allow_recalib; + args.processing_mode = procArgs.processing_mode; + chk(cuvis_proc_cont_is_capable(*_procCont, *mesu._mesu, args, &isCap)); + + return {1 == isCap}; + } + + inline bool ProcessingContext::has_reference(reference_type_t type) const + { + CUVIS_INT hasRef; + chk(cuvis_proc_cont_has_reference(*_procCont, type, &hasRef)); + + return {1 == hasRef}; + } + + inline void + ProcessingContext::set_processingArgs(ProcessingArgs const& procArgs) + { + _procArgs = procArgs; + chk(cuvis_proc_cont_set_args(*_procCont, _procArgs)); + } + + inline ProcessingArgs const& ProcessingContext::get_processingArgs() const + { + return _procArgs; + } + + inline Worker::Worker(WorkerArgs const& args) : _worker_poll_thread_run(false) + + { + CUVIS_WORKER worker; + chk(cuvis_worker_create(&worker, args.operator cuvis_worker_settings_t())); + _worker = std::shared_ptr( + new CUVIS_WORKER{worker}, [](CUVIS_WORKER* handle) { + cuvis_worker_free(handle); + delete handle; + }); + } + + inline void Worker::set_acq_cont(AcquisitionContext const* acqCont) + { + if (nullptr != acqCont) + { + chk(cuvis_worker_set_acq_cont(*_worker, *acqCont->_acqCont)); + } + else + { + chk(cuvis_worker_set_acq_cont(*_worker, CUVIS_HANDLE_NULL)); + } + } + + + + inline void Worker::set_proc_cont(ProcessingContext const* procCont) + { + if (nullptr != procCont) + { + chk(cuvis_worker_set_proc_cont(*_worker, *procCont->_procCont)); + } + else + { + chk(cuvis_worker_set_proc_cont(*_worker, CUVIS_HANDLE_NULL)); + } + } + + inline void Worker::set_exporter(Exporter const* exporter) + { + if (nullptr != exporter) + { + chk(cuvis_worker_set_exporter(*_worker, *exporter->_exporter)); + } + else + { + chk(cuvis_worker_set_exporter(*_worker, CUVIS_HANDLE_NULL)); + } + } + inline void Worker::set_viewer(Viewer const* viewer) + { + if (nullptr != viewer) + { + chk(cuvis_worker_set_viewer(*_worker, *viewer->_viewer)); + } + else + { + chk(cuvis_worker_set_viewer(*_worker, CUVIS_HANDLE_NULL)); + } + } + + inline bool Worker::has_next_result() const + { + CUVIS_INT hasNext; + chk(cuvis_worker_has_next_result(*_worker, &hasNext)); + return hasNext != 0; + } + + inline void Worker::set_queue_size(size_t size) + { + chk(cuvis_worker_set_queue_limit(*_worker, size)); + return; + } + inline size_t Worker::get_queue_size() const + { + CUVIS_INT size; + chk(cuvis_worker_get_queue_limit(*_worker, &size)); + return size; + } + inline size_t Worker::get_queue_used() const + { + CUVIS_INT size; + chk(cuvis_worker_get_queue_used(*_worker, &size)); + return size; + } + inline Worker::worker_return_t Worker::get_next_result() const + { + try + { + CUVIS_VIEW current_view; + CUVIS_MESU current_mesu; + chk(cuvis_worker_get_next_result(*_worker, ¤t_mesu, ¤t_view)); + + std::optional mesu; + std::optional view; + if (current_mesu != CUVIS_HANDLE_NULL) + { + mesu = std::move(Measurement(current_mesu)); + /* + auto tmp = Measurement(current_mesu); + mesu = tmp;*/ + } + if (current_view != CUVIS_HANDLE_NULL) + { + view = Viewer::create_view_data(current_view); + } + return {std::move(mesu), view, nullptr}; + } + catch (cuvis::cuvis_sdk_exception const& ex) + { + return {{}, {}, std::make_exception_ptr(ex)}; + } + } + + inline void Worker::register_worker_callback( + worker_callback_t callback, unsigned concurrency) + { + reset_worker_callback(); + + static const std::chrono::milliseconds poll_time = + std::chrono::milliseconds(1); + + + _worker_poll_thread_run = true; + + _worker_poll_thread = std::thread([this, callback, concurrency] { + std::deque> async_tasks; + while (_worker_poll_thread_run.load()) + { + if (has_next_result()) + { + auto ret = get_next_result(); + + async_tasks.push_back( + std::async(std::launch::async, callback, std::move(ret))); + + if (async_tasks.size() >= concurrency) + { + auto& res = async_tasks.front(); + while (true) + { + if (res.wait_for(poll_time) == std::future_status::ready) + { + break; + } + + if (!_worker_poll_thread_run.load()) + + { + return; + } + } + try + { + res.get(); + } + catch (...) + {} + + async_tasks.pop_front(); + } + } + + else + { + std::this_thread::sleep_for(poll_time); + } + } + }); + } + + inline void Worker::reset_worker_callback() + { + _worker_poll_thread_run = false; + if (_worker_poll_thread.joinable()) + { + _worker_poll_thread.join(); + } + } + + inline Viewer::Viewer(ViewArgs const& args) + { + CUVIS_VIEWER viewer; + chk(cuvis_viewer_create(&viewer, args)); + _viewer = std::shared_ptr( + new CUVIS_VIEWER{viewer}, [](CUVIS_VIEWER* handle) { + cuvis_viewer_free(handle); + delete handle; + }); + } + + inline Viewer::view_data_t Viewer::apply(Measurement const& mesu) + { + CUVIS_VIEW current_view; + chk(cuvis_viewer_apply(*_viewer, *mesu._mesu, ¤t_view)); + + + return create_view_data(current_view); + } + inline Viewer::view_data_t Viewer::create_view_data(CUVIS_VIEW current_view) + { + Viewer::view_data_t view_array; + + auto current_view_handle = std::shared_ptr( + new CUVIS_VIEW{current_view}, [](CUVIS_VIEW* handle) { + cuvis_view_free(handle); + delete handle; + }); + + + CUVIS_INT numel; + chk(cuvis_view_get_data_count(current_view, &numel)); + + for (decltype(numel) k = decltype(numel){0}; k < numel; k++) + { + cuvis_view_data_t view_data; + chk(cuvis_view_get_data(current_view, k, &view_data)); + + + cuvis_imbuffer_t const& im = view_data.data; + + + + switch (im.format) + { + case cuvis_imbuffer_format_t::imbuffer_format_uint8: { + view_t view({}); + view._width = im.width; + view._height = im.height; + view._channels = im.channels; + view._data = reinterpret_cast(im.raw); + view._show = (view_data.show != 0); + view._category = view_data.category; + view._ref = current_view_handle; + + view_array.emplace(std::string(view_data.id), view); + + break; + } + case cuvis_imbuffer_format_t::imbuffer_format_float: { + view_t view({}); + view._width = im.width; + view._height = im.height; + view._channels = im.channels; + view._data = reinterpret_cast(im.raw); + view._show = (view_data.show != 0); + view._category = view_data.category; + view._ref = current_view_handle; + + view_array.emplace(std::string(view_data.id), view); + + break; + } + + break; + default: //unknown or unsupported + throw std::runtime_error("unsupported view bit depth"); + break; + } + } + + return view_array; + } + inline AcquisitionContext::~AcquisitionContext() + { + reset_state_change_callback(); + } + + inline CUVIS_ACQ_CONT AcquisitionContext::get_handle() const + { + return *_acqCont; + } + + inline AcquisitionContext::AcquisitionContext(Calibration const& calib) + : _state_poll_thread_run(false) + { + CUVIS_ACQ_CONT acqCont; + chk(cuvis_acq_cont_create_from_calib(*calib._calib, &acqCont)); + _acqCont = std::shared_ptr( + new CUVIS_ACQ_CONT{acqCont}, [](CUVIS_ACQ_CONT* handle) { + cuvis_acq_cont_free(handle); + delete handle; + }); + } + + + inline void AcquisitionContext::register_state_change_callback( + state_callback_t callback, bool output_initial_state) + { + reset_state_change_callback(); + + _state_poll_thread_run = true; + + _state_poll_thread = std::thread([this, callback, output_initial_state] { + hardware_state_t last_state = hardware_state_offline; + std::map last_component_states; + for (int k = 0; k < get_component_count(); k++) + { + auto info = get_component_info(k); + last_component_states.emplace( + k, component_state_info_t{std::string(info.displayname), false}); + } + + bool first_pending = output_initial_state; + + while (_state_poll_thread_run.load()) + { + bool state_changed = first_pending; + first_pending = false; + + decltype(last_state) current_state = get_state(); + if (last_state != current_state) + { + state_changed = true; + last_state = current_state; + } + for (int k = 0; k < get_component_count(); k++) + { + auto comp_state = get_component_online(k) != 0; + auto last_comp_state = last_component_states[k].is_online; + + if (comp_state != last_comp_state) + { + state_changed = true; + last_component_states[k].is_online = comp_state; + } + } + if (state_changed) + callback(last_state, last_component_states); + else + { + static const std::chrono::milliseconds poll_time = + std::chrono::milliseconds(500); + std::this_thread::sleep_for(poll_time); + } + } + }); + } + + inline void AcquisitionContext::reset_state_change_callback() + { + _state_poll_thread_run = false; + + if (_state_poll_thread.joinable()) + { + _state_poll_thread.join(); + } + } + + + inline Measurement const& Exporter::apply(Measurement const& mesu) const + { + chk(cuvis_exporter_apply(*_exporter, *mesu._mesu)); + return mesu; + } + + inline size_t Exporter::get_queue_used() const + { + CUVIS_INT size; + chk(cuvis_exporter_get_queue_used(*_exporter, &size)); + return size; + } + + inline void Exporter::setHandle(CUVIS_EXPORTER exporter) + { + _exporter = std::shared_ptr( + new CUVIS_EXPORTER{exporter}, [](CUVIS_EXPORTER* handle) { + cuvis_exporter_free(handle); + delete handle; + }); + } + + inline CubeExporter::CubeExporter(SaveArgs const& args) + { + CUVIS_EXPORTER exporter; + chk(cuvis_exporter_create_cube(&exporter, args, args)); + setHandle(exporter); + } + + inline TiffExporter::TiffExporter(TiffArgs const& args) + { + CUVIS_EXPORTER exporter; + chk(cuvis_exporter_create_tiff(&exporter, args, args)); + setHandle(exporter); + } + + inline EnviExporter::EnviExporter(EnviArgs const& args) + { + CUVIS_EXPORTER exporter; + chk(cuvis_exporter_create_envi(&exporter, args)); + setHandle(exporter); + } + + inline ViewExporter::ViewExporter(ViewArgs const& args) + { + CUVIS_EXPORTER exporter; + chk(cuvis_exporter_create_view(&exporter, args, args)); + setHandle(exporter); + } + + inline async_result_t Async::get(std::chrono::milliseconds waittime) + { + auto result = + cuvis_async_call_get(_async.get(), CUVIS_INT(waittime.count())); + switch (result) + { + case cuvis_status_t::status_ok: return async_result_t::done; + case cuvis_status_t::status_deferred: return async_result_t::deferred; + case cuvis_status_t::status_overwritten: + return async_result_t::overwritten; + case cuvis_status_t::status_timeout: return async_result_t::timeout; + default: + throw cuvis_sdk_exception( + cuvis_get_last_error_msg(), cuvis_get_last_error_msg_localized()); + } + } + + inline std::pair> + AsyncMesu::get(std::chrono::milliseconds waittime) + { + CUVIS_MESU mesu; + auto result = cuvis_async_capture_get( + _async.get(), CUVIS_INT(waittime.count()), &mesu); + switch (result) + { + case cuvis_status_t::status_ok: + return {async_result_t::done, Measurement(mesu)}; + case cuvis_status_t::status_deferred: + return {async_result_t::deferred, {}}; + case cuvis_status_t::status_overwritten: + return {async_result_t::overwritten, {}}; + case cuvis_status_t::status_timeout: return {async_result_t::timeout, {}}; + default: + throw cuvis_sdk_exception( + cuvis_get_last_error_msg(), cuvis_get_last_error_msg_localized()); + } + } + + inline void AcquisitionContext::capture_queue() + { + chk(cuvis_acq_cont_capture_async(*_acqCont, nullptr)); + } + + inline AsyncMesu AcquisitionContext::capture() + { + CUVIS_ASYNC_CAPTURE_RESULT asyncRes; + chk(cuvis_acq_cont_capture_async(*_acqCont, &asyncRes)); + AsyncMesu am; + am._async = std::shared_ptr( + new CUVIS_ASYNC_CAPTURE_RESULT{asyncRes}, + [](CUVIS_ASYNC_CAPTURE_RESULT* handle) { + cuvis_async_capture_free(handle); + delete handle; + }); + return am; + } + + inline hardware_state_t AcquisitionContext::get_state() const + { + CUVIS_HARDWARE_STATE state; + chk(cuvis_acq_cont_get_state(*_acqCont, &state)); + return state; + } + + inline std::optional AcquisitionContext::get_next_measurement( + std::chrono::milliseconds timeout_ms) const + { + CUVIS_MESU mesu; + auto ret = cuvis_acq_cont_get_next_measurement( + *_acqCont, &mesu, CUVIS_INT(timeout_ms.count())); + if (status_ok == ret) + { + return Measurement(mesu); + } + else if (status_no_measurement == ret) + { + return {}; + } + + throw cuvis_sdk_exception( + cuvis_get_last_error_msg(), cuvis_get_last_error_msg_localized()); + } + + inline bool AcquisitionContext::has_next_measurement() const + { + CUVIS_INT has_next; + chk(cuvis_acq_cont_has_next_measurement(*_acqCont, &has_next)); + return 1 == has_next; + } + + + inline SessionInfo AcquisitionContext::get_session_info() const + { + CUVIS_SESSION_INFO session; + chk(cuvis_acq_cont_get_session_info(*_acqCont, &session)); + return {session}; + } + inline CUVIS_INT AcquisitionContext::get_component_count() const + { + CUVIS_INT count; + chk(cuvis_acq_cont_get_component_count(*_acqCont, &count)); + return count; + } + inline CUVIS_COMPONENT_INFO + AcquisitionContext::get_component_info(CUVIS_INT id) const + { + CUVIS_COMPONENT_INFO info; + chk(cuvis_acq_cont_get_component_info(*_acqCont, id, &info)); + return info; + } + inline void AcquisitionContext::set_session_info(SessionInfo session) + { + auto const csess = session.operator cuvis::session_info_t(); + chk(cuvis_acq_cont_set_session_info(*_acqCont, &csess)); + return; + } + + inline void AcquisitionContext::set_queue_size(CUVIS_INT size) + { + chk(cuvis_acq_cont_queue_size_set(*_acqCont, size)); + return; + } + + inline void General::set_log_level(CUVIS_INT lvl) + { + chk(cuvis_set_log_level(lvl)); + return; + } + + inline void General::set_exception_locale(std::string const& locale) + { + chk(cuvis_set_last_error_locale(locale.c_str())); + return; + } + + namespace event_impl + { + class event_handler_register + { + private: + event_handler_register() = default; + + public: + static event_handler_register& get_handler_register() + { + static event_handler_register reg; + return reg; + } + + public: + event_handler_register(event_handler_register const&) = delete; + event_handler_register(event_handler_register&&) = delete; + event_handler_register& operator=(event_handler_register&&) = delete; + event_handler_register& operator=(event_handler_register const&) = delete; + + private: + std::mutex mtx_; + std::map handler_register_; + + static void handler_function(CUVIS_INT handler_id, CUVIS_INT event_id) + { + /* handler function gets called from another thread than register/unregister */ + event_handler_register& reg = get_handler_register(); + std::lock_guard lock(reg.mtx_); + const auto itr = reg.handler_register_.find(handler_id); + if (itr != reg.handler_register_.end()) + { + reg.handler_register_[handler_id](event_id); + } + } + + public: + /* register event callback is not threadsafe */ + CUVIS_INT register_event_callback( + cpp_event_callback_t callback, CUVIS_INT i_type) + { + int handler_id = -1; + chk(cuvis_register_external_event_callback( + handler_function, i_type, &handler_id)); + if (handler_id >= 0) + { + std::lock_guard lock(mtx_); + handler_register_[handler_id] = callback; + } + return handler_id; + } + /* unregister event callback is not threadsafe */ + void unregister_event_callback(CUVIS_INT i_handler_id) + { + chk(cuvis_unregister_event_callback(i_handler_id)); + /* we want the lock only after the sdk call to prevent a dead-lock from happening */ + /* e.g. unregister gets lock, but event-queue handle has internal lock, and also wants this lock */ + /* therefore deadlock */ + std::lock_guard lock(mtx_); + handler_register_.erase(i_handler_id); + } + }; + } // namespace event_impl + inline CUVIS_INT General::register_event_callback( + cpp_event_callback_t callback, CUVIS_INT i_type) + { + return event_impl::event_handler_register::get_handler_register() + .register_event_callback(callback, i_type); + } + inline void General::unregister_event_callback(CUVIS_INT i_handler_id) + { + event_impl::event_handler_register::get_handler_register() + .unregister_event_callback(i_handler_id); + } + + namespace log_impl + { + inline std::mutex log_callback_fun_mutex; + inline std::function log_callback_fun; + inline void SDK_CCALL custom_log(char const* msg, CUVIS_LOGLEVEL lvl) + { + log_callback_fun(msg, lvl); + } + inline std::mutex log_callback_localized_fun_mutex; + inline std::function + log_callback_localized_fun; + inline void SDK_CCALL + custom_log_localized(wchar_t const* msg, CUVIS_LOGLEVEL lvl) + { + log_callback_localized_fun(msg, lvl); + } + } // namespace log_impl + + + + inline void General::register_log_callback( + std::function callback, + CUVIS_INT min_lvl) + { + const std::lock_guard lock(log_impl::log_callback_fun_mutex); + log_impl::log_callback_fun = callback; + chk(cuvis_register_log_callback( + (log_callback)log_impl::custom_log, min_lvl)); + + return; + } + + inline void General::reset_log_callback() + { + const std::lock_guard lock(log_impl::log_callback_fun_mutex); + chk(cuvis_reset_log_callback()); + log_impl::log_callback_fun = + std::function(); + return; + } + + inline void General::register_log_callback_localized( + std::function callback, + CUVIS_INT min_lvl, + std::string const& loc_id = "") + { + const std::lock_guard lock( + log_impl::log_callback_localized_fun_mutex); + log_impl::log_callback_localized_fun = callback; + chk(cuvis_register_log_callback_localized( + (log_callback_localized)log_impl::custom_log_localized, + min_lvl, + loc_id.c_str())); + return; + } + + inline void General::reset_log_callback_localized() + { + const std::lock_guard lock( + log_impl::log_callback_localized_fun_mutex); + chk(cuvis_reset_log_callback_localized()); + log_impl::log_callback_localized_fun = + std::function(); + return; + } + + inline std::string General::version() + { + CUVIS_CHAR version[CUVIS_MAXBUF]; + chk(cuvis_version(version)); + return std::string(version); + } + + inline void General::init(std::string const& settings_path) + { + chk(cuvis_init(settings_path.c_str())); + return; + } + + inline SessionFile::SessionFile(std::filesystem::path const& path) + { + CUVIS_SESSION_FILE session; + chk(cuvis_session_file_load(path.string().c_str(), &session)); + _session = std::shared_ptr( + new CUVIS_SESSION_FILE{session}, [](CUVIS_SESSION_FILE* handle) { + cuvis_session_file_free(handle); + delete handle; + }); + } + + inline std::optional + SessionFile::get_mesu(CUVIS_INT frameNo) const + { + CUVIS_MESU mesu; + const auto ret = cuvis_session_file_get_mesu(*_session, frameNo, &mesu); + + if (CUVIS_HANDLE_NULL == mesu) + { + return {}; + } + + return Measurement(mesu); + } + + inline std::optional + SessionFile::get_mesu_non_dropped(CUVIS_INT frameNo) const + { + CUVIS_MESU mesu; + const auto ret = + cuvis_session_file_get_mesu_non_dropped(*_session, frameNo, &mesu); + + if (CUVIS_HANDLE_NULL == mesu) + { + return {}; + } + + return Measurement(mesu); + } + + inline CUVIS_INT SessionFile::get_size() const + { + CUVIS_INT size; + chk(cuvis_session_file_get_size(*_session, &size)); + return size; + } + + inline CUVIS_INT SessionFile::get_size_non_dropped() const + { + CUVIS_INT size; + chk(cuvis_session_file_get_size_non_dropped(*_session, &size)); + return size; + } + + inline double SessionFile::get_fps() const + { + double fps; + chk(cuvis_session_file_get_fps(*_session, &fps)); + return fps; + } + + inline CUVIS_OPERATION_MODE SessionFile::get_operation_mode() const + { + CUVIS_OPERATION_MODE op_mode; + chk(cuvis_session_file_get_operation_mode(*_session, &op_mode)); + return op_mode; + } + + template + inline data_t const& common_image_t::get( + std::size_t x, std::size_t y, std::size_t z) const + { + assert(x < _width); + assert(y < _height); + assert(z < _channels); + return _data[((y)*_width + (x)) * _channels + (z)]; + } + + + + inline GeneralExportArgs::GeneralExportArgs() + : export_dir("."), + channel_selection("all"), + spectra_multiplier(1.0), + pan_scale(0.0), + pan_interpolation_type(pan_sharpening_interpolation_type_Linear), + pan_algorithm(pan_sharpening_algorithm_CubertMacroPixel), + add_pan(false), + add_fullscale_pan(false), + permissive(false) + {} + + inline GeneralExportArgs::operator cuvis_export_general_settings_t() const + { + cuvis_export_general_settings_t ges({}); + std::strncpy(ges.export_dir, export_dir.string().c_str(), CUVIS_MAXBUF); + std::strncpy( + ges.channel_selection, channel_selection.c_str(), CUVIS_MAXBUF); + ges.spectra_multiplier = spectra_multiplier; + ges.pan_scale = pan_scale; + ges.pan_interpolation_type = pan_interpolation_type; + ges.pan_algorithm = pan_algorithm; + ges.add_pan = static_cast(add_pan); + ges.add_fullscale_pan = static_cast(add_fullscale_pan); + ges.permissive = static_cast(permissive); + + return ges; + } + + inline SaveArgs::SaveArgs() + : allow_fragmentation(false), + allow_overwrite(false), + allow_drop(false), + allow_session_file(true), + operation_mode(operation_mode_t::OperationMode_Software), + fps(0.0), + allow_info_file(true), + soft_limit(20), + hard_limit(100), + max_buftime(10000) + {} + + inline SaveArgs::operator cuvis_save_args_t() const + { + cuvis_save_args_t save_args; + save_args.allow_fragmentation = static_cast(allow_fragmentation); + save_args.allow_overwrite = static_cast(allow_overwrite); + save_args.allow_drop = static_cast(allow_drop); + save_args.allow_session_file = static_cast(allow_session_file); + save_args.allow_info_file = static_cast(allow_info_file); + save_args.operation_mode = operation_mode; + save_args.fps = fps; + save_args.soft_limit = soft_limit; + save_args.hard_limit = hard_limit; + save_args.max_buftime = max_buftime.count(); + return save_args; + } + + inline ProcessingArgs::ProcessingArgs() + : processing_mode(processing_mode_t::Cube_Raw), allow_recalib(false) + {} + inline ProcessingArgs::operator cuvis_proc_args_t() const + { + cuvis_proc_args_t proc_args({}); + proc_args.processing_mode = processing_mode; + proc_args.allow_recalib = allow_recalib; + return proc_args; + } + + inline ViewArgs::ViewArgs() : userplugin(), complete(false) {} + + inline ViewArgs::operator cuvis_viewer_settings_t() const + { + cuvis_viewer_settings_t args; + args.userplugin = userplugin.c_str(); + args.pan_scale = pan_scale; + args.pan_interpolation_type = pan_interpolation_type; + args.pan_algorithm = pan_algorithm; + args.complete = complete; + + return args; + } + inline ViewArgs::operator cuvis_export_view_settings_t() const + { + cuvis_export_view_settings_t args; + args.userplugin = userplugin.c_str(); + + return args; + } + + inline TiffArgs::TiffArgs() + : compression_mode(tiff_compression_mode_None), + format(tiff_format_MultiChannel) + {} + + inline TiffArgs::operator cuvis_export_tiff_settings_t() const + { + cuvis_export_tiff_settings_t args; + args.compression_mode = compression_mode; + args.format = format; + + return args; + } + + inline WorkerArgs::WorkerArgs() + + : worker_count(std::thread::hardware_concurrency()), + + poll_interval(std::chrono::milliseconds(5)), + keep_out_of_sequence(false), + worker_queue_size(100) + {} + + inline WorkerArgs::operator cuvis_worker_settings_t() const + { + cuvis_worker_settings_t args; + + args.worker_count = worker_count; + args.poll_interval = (std::int32_t)(poll_interval.count()); + args.keep_out_of_sequence = (int)keep_out_of_sequence; + args.worker_queue_size = worker_queue_size; + + return args; + } + + inline SessionInfo::SessionInfo() + : name("auto"), session_no(0), sequence_no(0) + {} + + inline SessionInfo::SessionInfo(session_info_t const& sess) + : name(sess.name), + session_no(sess.session_no), + sequence_no(sess.sequence_no) + {} + + inline SessionInfo::operator cuvis::session_info_t() const + { + session_info_t sess; + std::strncpy(sess.name, name.c_str(), CUVIS_MAXBUF); + sess.session_no = static_cast(session_no); + sess.sequence_no = static_cast(sequence_no); + return sess; + } + + inline MeasurementMetaData::MeasurementMetaData(mesu_metadata_t const& meta) + { + name = std::string(meta.name); + path = std::string(meta.path); + comment = std::string(meta.comment); + capture_time = std::chrono::time_point( + std::chrono::milliseconds(meta.capture_time)); + factory_calibration = std::chrono::time_point( + std::chrono::milliseconds(meta.factory_calibration)); + product_name = std::string(meta.product_name); + serial_number = std::string(meta.serial_number); + assembly = std::string(meta.assembly); + integration_time = meta.integration_time; + averages = static_cast(meta.averages); + session_info = SessionInfo(); + session_info.name = meta.session_info_name; + session_info.sequence_no = meta.session_info_sequence_no; + session_info.session_no = meta.session_info_session_no; + processing_mode = meta.processing_mode; + } + + inline SensorInfoData::SensorInfoData(sensor_info_t const& info) + { + averages = info.averages; + temperature = info.temperature; + gain = info.gain; + readout_time = std::chrono::time_point( + std::chrono::milliseconds(info.readout_time)); + } + + + inline cuvis_sdk_exception::cuvis_sdk_exception( + std::string const& msg, std::wstring const& wmsg) + : _msg(msg), _wmsg(wmsg) + {} + + inline char const* cuvis_sdk_exception::what(void) const noexcept + { + return _msg.c_str(); + } + + inline std::wstring cuvis_sdk_exception::what_wstr(void) const noexcept + { + return _wmsg; + } +} // namespace cuvis