diff --git a/CMakeLists.txt b/CMakeLists.txt index 18f7fd6..45d9930 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required(VERSION 3.24) -project(JetModule - VERSION 1.0.0 - DESCRIPTION "Library for using JetPeer alongside with openDAQ" +project(JetModule + DESCRIPTION "Library for publishing openDAQ device structure as Jet states" LANGUAGES C CXX) ##### Variables diff --git a/README.md b/README.md index 8fecc1c..6865aca 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Jet module is an integration of Jet protocol with openDAQ SDK. It publishes devi - After a device has been instantiated, create `JetServer` object: ```c++ - daq::modules::jet_module::JetServer jetServer = JetServer(opendaqInstance); + jet_module::JetServer jetServer = jet_module::JetServer(opendaqInstance); ``` - Call `JetServer::publishJetStates()` to publish device structure as Jet states: @@ -38,7 +38,4 @@ cmake --build . ### TODO - Add Support for all property types. -- ref_dev0/MethodSet/GetErrorInformation (Decide whether methods like these habe to be turned into Jet methods). -- Verify that Jet methods for FunctionProperty is created properly. -- Support parameter passing to Jet methods -- Rethink how to handle SelectionProperties +- Exception handling and error logging has to be reworked from ground-up. diff --git a/app/ref_app.cpp b/app/ref_app.cpp index efad1fe..7cce570 100644 --- a/app/ref_app.cpp +++ b/app/ref_app.cpp @@ -3,7 +3,7 @@ #include using namespace daq; -using namespace daq::modules::jet_module; +using namespace jet_module; int main() { diff --git a/include/common.h b/include/common.h index 940ef6d..73223d3 100644 --- a/include/common.h +++ b/include/common.h @@ -14,7 +14,11 @@ * limitations under the License. */ #pragma once -#include -#define BEGIN_NAMESPACE_JET_MODULE BEGIN_NAMESPACE_OPENDAQ_MODULE(jet_module) -#define END_NAMESPACE_JET_MODULE END_NAMESPACE_OPENDAQ_MODULE \ No newline at end of file +#define BEGIN_NAMESPACE_JET_MODULE \ + namespace jet_module \ + { + +#define END_NAMESPACE_JET_MODULE \ + } + diff --git a/include/component_converter.h b/include/component_converter.h index dd5b8e7..ec01f05 100644 --- a/include/component_converter.h +++ b/include/component_converter.h @@ -59,7 +59,6 @@ class ComponentConverter JetEventHandler jetEventHandler; InstancePtr opendaqInstance; - LoggerComponentPtr logger; private: }; diff --git a/include/jet_event_handler.h b/include/jet_event_handler.h index c0a4a7d..c23c9ba 100644 --- a/include/jet_event_handler.h +++ b/include/jet_event_handler.h @@ -47,8 +47,6 @@ class JetEventHandler JetPeerWrapper& jetPeerWrapper; PropertyConverter propertyConverter; - - LoggerComponentPtr logger; }; END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/jet_module_exceptions.h b/include/jet_module_exceptions.h index 9769f86..02e9ffc 100644 --- a/include/jet_module_exceptions.h +++ b/include/jet_module_exceptions.h @@ -14,18 +14,34 @@ * limitations under the License. */ #pragma once +#include "common.h" #include #include +#include + +BEGIN_NAMESPACE_JET_MODULE + +extern daq::LoggerComponentPtr jetModuleLogger; enum JetModuleException : int { JM_INCOMPATIBLE_TYPES = 0, JM_UNSUPPORTED_JSON_TYPE, JM_UNSUPPORTED_DAQ_TYPE, - JM_UNSUPPORTED_ITEM + JM_UNSUPPORTED_ITEM, + JM_FUNCTION_INCOMPATIBLE_ARGUMENT_TYPES, + JM_FUNCTION_INCORRECT_ARGUMENT_NUMBER, + JM_FUNCTION_UNSUPPORTED_ARGUMENT_TYPE, + JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT, + JM_FUNCTION_UNSUPPORTED_RETURN_TYPE, + JM_UNEXPECTED_TYPE }; bool checkTypeCompatibility(Json::ValueType jsonValueType, daq::CoreType daqValueType); void throwJetModuleException(JetModuleException jmException); void throwJetModuleException(JetModuleException jmException, std::string propertyName); -void throwJetModuleException(JetModuleException jmException, Json::ValueType jsonValueType, std::string propertyName, std::string globalId); \ No newline at end of file +void throwJetModuleException(JetModuleException jmException, Json::ValueType jsonValueType, std::string propertyName, std::string globalId); +std::string jetModuleExceptionToString(const JetModuleException& jmException); + + +END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/jet_module_impl.h b/include/jet_module_impl.h deleted file mode 100644 index 1b8fcec..0000000 --- a/include/jet_module_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022-2023 Blueberry d.o.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once -#include - -#include "common.h" - -BEGIN_NAMESPACE_JET_MODULE - -class JetModule final : public Module -{ -public: - explicit JetModule(ContextPtr context); - -private: - -}; - - -END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/jet_peer_wrapper.h b/include/jet_peer_wrapper.h index 17ddd05..28eb193 100644 --- a/include/jet_peer_wrapper.h +++ b/include/jet_peer_wrapper.h @@ -49,6 +49,7 @@ class JetPeerWrapper void publishJetState(const std::string& path, const Json::Value& jetState, JetStateCallback callback); void publishJetMethod(const std::string& path, JetMethodCallback callback); + void removeJetMethod(const std::string& path); Json::Value readJetState(const std::string& path); Json::Value readAllJetStates(); void updateJetState(const std::string& path, const Json::Value newValue); @@ -74,8 +75,6 @@ class JetPeerWrapper hbk::sys::EventLoop jetEventloop; bool jetEventloopRunning; std::thread jetEventloopThread; - - LoggerComponentPtr logger; }; END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/module_dll.h b/include/module_dll.h deleted file mode 100644 index 53bade7..0000000 --- a/include/module_dll.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2022-2023 Blueberry d.o.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once -#include - -DECLARE_MODULE_EXPORTS(JetModule) diff --git a/include/opendaq_event_handler.h b/include/opendaq_event_handler.h index 42e2fb7..fd7103f 100644 --- a/include/opendaq_event_handler.h +++ b/include/opendaq_event_handler.h @@ -38,6 +38,7 @@ class OpendaqEventHandler void updateSimpleProperty(const ComponentPtr& component, const DictPtr& eventParameters); void updateListProperty(const ComponentPtr& component, const DictPtr& eventParameters); void updateDictProperty(const ComponentPtr& component, const DictPtr& eventParameters); + void updateFunctionProperty(const ComponentPtr& component, const DictPtr& eventParameters); void updateActiveStatus(const ComponentPtr& component, const DictPtr& eventParameters); void addProperty(const ComponentPtr& component, const DictPtr& eventParameters); @@ -52,8 +53,6 @@ class OpendaqEventHandler JetPeerWrapper& jetPeerWrapper; PropertyManager propertyManager; PropertyConverter propertyConverter; - - LoggerComponentPtr logger; }; END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/property_converter.h b/include/property_converter.h index 4a14b49..96418ba 100644 --- a/include/property_converter.h +++ b/include/property_converter.h @@ -46,8 +46,6 @@ class PropertyConverter template Json::Value fillJsonDict_BasicType(const DictPtr& opendaqDict); - - LoggerComponentPtr logger; }; END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/include/property_manager.h b/include/property_manager.h index 346214e..730c38c 100644 --- a/include/property_manager.h +++ b/include/property_manager.h @@ -19,6 +19,7 @@ #include #include "property_converter.h" #include "jet_peer_wrapper.h" +#include "jet_module_exceptions.h" using namespace daq; @@ -57,13 +58,18 @@ class PropertyManager void createJetMethod(const ComponentPtr& propertyPublisher, const PropertyPtr& property); private: + BaseObjectPtr convertJsonValueToDaqValue(const Json::Value& jsonVal); + Json::Value convertDaqValueToJsonValue(const BaseObjectPtr& daqVal, const CoreType& coretype); + bool hasUnsupportedArgument(const CallableInfoPtr& callableInfo, const std::string& propertyName); + bool hasUnsupportedReturnType(const CoreType& returnType, const std::string& propertyName); + bool hasCompatibleArgumentTypes(CoreType daqType, const Json::Value& jsonVal); + PropertyConverter propertyConverter; JetPeerWrapper& jetPeerWrapper; - LoggerComponentPtr logger; }; -//! Template functions definitions have to be in the header file so that derived classes are able to use them. +//! Template function definitions have to be in the header file so that derived classes are able to use them. /* * Unlike regular functions and methods, template definitions (including template member functions of a class) must be visible * to a translation unit that uses them. This is because the compiler needs to instantiate the template with the specific type @@ -134,9 +140,9 @@ void PropertyManager::determinePropertyType(const PropertyHolder& propertyHolder default: { std::string message = "Unsupported value type of Property: " + propertyName + '\n'; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); message = "\"std::string\" will be used to store property value.\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Info); + DAQLOG_I(jetModuleLogger, message.c_str()); std::string propertyValue = propertyHolder.getPropertyValue(propertyName); parentJsonValue[propertyName] = propertyValue; } @@ -306,7 +312,7 @@ void PropertyManager::appendStructProperty(const PropertyHolderType& propertyHol default: { // std::string message = "Unsupported list item type: " + listItemType + '\n'; - // jetPeerWrapper.logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + // jetPeerWrapper.jetModuleLogger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); } break; } @@ -324,7 +330,7 @@ void PropertyManager::appendStructProperty(const PropertyHolderType& propertyHol default: { // std::string message = "Unsupported struct field type: " + structfieldType + '\n'; - // jetPeerWrapper.logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Info); + // jetPeerWrapper.jetModuleLogger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Info); } } } diff --git a/include/version.h b/include/version.h deleted file mode 100644 index 1ed905d..0000000 --- a/include/version.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2022-2023 Blueberry d.o.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#define JET_MODULE_MAJOR_VERSION 1u -#define JET_MODULE_MINOR_VERSION 0u -#define JET_MODULE_PATCH_VERSION 0u diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e24d47..3a4fb55 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,8 +4,6 @@ set(MODULE_HEADERS_DIR "${PROJECT_SOURCE_DIR}/include") # Header files set(SRC_Include common.h - module_dll.h - jet_module_impl.h jet_peer_wrapper.h jet_server.h jet_module_exceptions.h @@ -19,13 +17,10 @@ set(SRC_Include input_port_converter.h opendaq_event_handler.h jet_event_handler.h - version.h ) # Source files set(SRC_Srcs - module_dll.cpp - jet_module_impl.cpp jet_peer_wrapper.cpp jet_server.cpp jet_module_exceptions.cpp @@ -44,31 +39,17 @@ set(SRC_Srcs # Prepend path to header files list(TRANSFORM SRC_Include PREPEND "${MODULE_HEADERS_DIR}/") -source_group("module" FILES - ${MODULE_HEADERS_DIR}/module_dll.h - ${MODULE_HEADERS_DIR}/jet_module_impl.h - ${MODULE_HEADERS_DIR}/jet.h - module_dll.cpp - jet_module_impl.cpp - jet.cpp -) - # Library creation add_library(${LIB_NAME} SHARED ${SRC_Include} ${SRC_Srcs} ) -add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) target_include_directories(${LIB_NAME} PUBLIC ${MODULE_HEADERS_DIR}) target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq hbk jetpeer jetpeerasync jsoncpp_lib pugixml) -target_compile_definitions(${LIB_NAME} PUBLIC OPENDAQ_THREAD_SAFE) target_include_directories(${LIB_NAME} PUBLIC $ $ ) -set(OPENDAQ_MODULE_SUFFIX ".module${CMAKE_SHARED_LIBRARY_SUFFIX}") -opendaq_set_module_properties(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) - file(GLOB MODULE_HEADERS "${MODULE_HEADERS_DIR}/*.h") install(FILES ${MODULE_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${LIB_NAME}") \ No newline at end of file diff --git a/src/component_converter.cpp b/src/component_converter.cpp index 94d60f3..2d2756f 100644 --- a/src/component_converter.cpp +++ b/src/component_converter.cpp @@ -1,13 +1,11 @@ #include "component_converter.h" +#include "jet_module_exceptions.h" #include - BEGIN_NAMESPACE_JET_MODULE ComponentConverter::ComponentConverter(const InstancePtr& opendaqInstance) : jetPeerWrapper(JetPeerWrapper::getInstance()) { this->opendaqInstance = opendaqInstance; - // initiate openDAQ logger - logger = LoggerComponent("ObjectConverterLogger", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); } /** @@ -61,13 +59,13 @@ void ComponentConverter::createOpendaqCallback(const ComponentPtr& component) if(eventParameters.hasKey("Active")) // Active status changed opendaqEventHandler.updateActiveStatus(comp, eventParameters); else - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; case CoreEventId::PropertyAdded: opendaqEventHandler.addProperty(comp, eventParameters); break; default: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; } @@ -83,8 +81,8 @@ JetStateCallback ComponentConverter::createJetCallback() { JetStateCallback callback = [this](const Json::Value& value, std::string path) -> Json::Value { - std::string message = "Want to change state with path: " + path + " with the value " + value.toStyledString() + "\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Info); + std::string message = "Want to change state with path: \"" + path + "\" with the value:\n" + value.toStyledString(); + DAQLOG_I(jetModuleLogger, message.c_str()); // Actual work is done on a separate thread to handle simultaneous requests. Also, otherwise "jetset" tool would time out std::thread([this, value, path]() @@ -126,8 +124,8 @@ JetStateCallback ComponentConverter::createObjectPropertyJetCallback() { JetStateCallback callback = [this](const Json::Value& value, std::string path) -> Json::Value { - std::string message = "Want to change state with path: " + path + " with the value " + value.toStyledString() + "\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Info); + std::string message = "Want to change state with path: " + path + " with the value:\n" + value.toStyledString(); + DAQLOG_I(jetModuleLogger, message.c_str()); // Actual work is done on a separate thread to handle simultaneous requests. Also, otherwise "jetset" tool would time out std::thread([this, value, path]() diff --git a/src/jet_event_handler.cpp b/src/jet_event_handler.cpp index f3eef6b..56f0382 100644 --- a/src/jet_event_handler.cpp +++ b/src/jet_event_handler.cpp @@ -1,12 +1,12 @@ #include "jet_event_handler.h" +#include "jet_module_exceptions.h" #include BEGIN_NAMESPACE_JET_MODULE JetEventHandler::JetEventHandler() : jetPeerWrapper(JetPeerWrapper::getInstance()) { - // initiate openDAQ logger - logger = LoggerComponent("JetEventHandlerLogger", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); + } /** @@ -18,9 +18,17 @@ JetEventHandler::JetEventHandler() : jetPeerWrapper(JetPeerWrapper::getInstance( */ void JetEventHandler::updateProperty(const ComponentPtr& component, const std::string& propertyName, const Json::Value& newPropertyValue) { + PropertyPtr property = component.getProperty(propertyName); + bool isReadOnly = property.getReadOnly(); + if(isReadOnly) { + std::string message = "Property \"" + propertyName + "\" is read-only. Its value cannot be changed. Skipping."; + DAQLOG_W(jetModuleLogger, message.c_str()); + return; + } + CoreType propertyType = component.getProperty(propertyName).getValueType(); - std::string message = "Update of property with CoreType " + propertyType + std::string(" is not supported currently.\n"); + std::string unsupportedPropertyType = "Update of property with CoreType " + propertyType + std::string(" is currently unsupported. Skipping."); switch(propertyType) { case CoreType::ctBool: @@ -42,27 +50,40 @@ void JetEventHandler::updateProperty(const ComponentPtr& component, const std::s updateDictProperty(component, propertyName, newPropertyValue); break; case CoreType::ctRatio: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, unsupportedPropertyType.c_str()); break; case CoreType::ctComplexNumber: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, unsupportedPropertyType.c_str()); break; case CoreType::ctStruct: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + { + // Struct is an immutable object in openDAQ and it cannot be modified. + std::string message = "\"" + propertyName + "\" is StructProperty and cannot be modified."; + DAQLOG_E(jetModuleLogger, message.c_str()); + } break; case CoreType::ctObject: { - std::string message = "ObjectProperty must be represented as a separate state!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + // ObjectProperty is represented as a separate state. It has to be updated with "updateObjectProperty" function call. + // This function must not be called for updating ObjectProperty! + std::string message = "\"" + propertyName + "\" is ObjectProperty and has to be represented as a separate state."; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; case CoreType::ctProc: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + { + std::string message = "\"" + propertyName + "\" is FunctionProperty and cannot be modified."; + DAQLOG_E(jetModuleLogger, message.c_str()); + } break; case CoreType::ctFunc: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + { + std::string message = "\"" + propertyName + "\" is FunctionProperty and cannot be modified."; + DAQLOG_E(jetModuleLogger, message.c_str()); + } break; default: + DAQLOG_W(jetModuleLogger, unsupportedPropertyType.c_str()); break; } } diff --git a/src/jet_module_exceptions.cpp b/src/jet_module_exceptions.cpp index 2affd90..488524b 100644 --- a/src/jet_module_exceptions.cpp +++ b/src/jet_module_exceptions.cpp @@ -2,8 +2,12 @@ #include #include "jet_module_exceptions.h" +BEGIN_NAMESPACE_JET_MODULE + using namespace daq; +LoggerComponentPtr jetModuleLogger = LoggerComponent("JetModule", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); + bool checkTypeCompatibility(Json::ValueType jsonValueType, daq::CoreType daqValueType) { switch(jsonValueType) @@ -145,4 +149,28 @@ void throwJetModuleException(JetModuleException jmException, Json::ValueType jso case JetModuleException::JM_UNSUPPORTED_DAQ_TYPE: break; } -} \ No newline at end of file +} + +std::string jetModuleExceptionToString(const JetModuleException& jmException) +{ + std::string message = "Error: "; + switch(jmException) + { + case JetModuleException::JM_UNEXPECTED_TYPE: + return (message + "Unexpected type detected."); + case JetModuleException::JM_FUNCTION_INCOMPATIBLE_ARGUMENT_TYPES: + return (message + "Incompatible function argument types detected."); + case JetModuleException::JM_FUNCTION_INCORRECT_ARGUMENT_NUMBER: + return (message + "Incorrect number of arguments has been provided."); + case JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_TYPE: + return (message + "Function is defined with an argument type which is not supported."); + case JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT: + return (message + "Arguments to the function have been provided in unsupported format."); + case JetModuleException::JM_FUNCTION_UNSUPPORTED_RETURN_TYPE: + return (message + "Function is defined with a return type which is not supported."); + default: + return (message + "General error."); + } +} + +END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/src/jet_module_impl.cpp b/src/jet_module_impl.cpp deleted file mode 100644 index 8499080..0000000 --- a/src/jet_module_impl.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -#include "version.h" -#include "jet_module_impl.h" - - -BEGIN_NAMESPACE_JET_MODULE - -JetModule::JetModule(ContextPtr context) - : Module("Jet module", - daq::VersionInfo(JET_MODULE_MAJOR_VERSION, JET_MODULE_MINOR_VERSION,JET_MODULE_PATCH_VERSION), - std::move(context) - ) -{ -} - -END_NAMESPACE_JET_MODULE diff --git a/src/jet_peer_wrapper.cpp b/src/jet_peer_wrapper.cpp index cc3b7c9..7c0fd72 100644 --- a/src/jet_peer_wrapper.cpp +++ b/src/jet_peer_wrapper.cpp @@ -8,9 +8,6 @@ static hbk::sys::EventLoop jetStateReadEventloop; JetPeerWrapper::JetPeerWrapper() { - // initiate openDAQ logger - logger = LoggerComponent("JetPeerWrapperLogger", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); - jetEventloopRunning = false; // TODO: This probably has to be removed startJetEventloopThread(); @@ -46,6 +43,16 @@ void JetPeerWrapper::publishJetMethod(const std::string& path, JetMethodCallback jetPeer->addMethodAsync(path, hbk::jet::responseCallback_t(), callback); } +/** + * @brief Removes a Jet method from the specified path. + * + * @param path Path of the existing Jet method. + */ +void JetPeerWrapper::removeJetMethod(const std::string& path) +{ + jetPeer->removeMethodAsync(path); +} + /** * @brief Reads a Jet state with specified path into a Json object. * @@ -80,11 +87,11 @@ Json::Value JetPeerWrapper::readJetState(const std::string& path) // Making sure that size of the array of Json objects is exactly 1 if(jetState.size() == 0) { std::string message = "Could not read Jet state with path: " + path + "\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + DAQLOG_E(jetModuleLogger, message.c_str()); } else if(jetState.size() != 1) { std::string message = "There are multiple Jet states with path: " + path + "\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + DAQLOG_E(jetModuleLogger, message.c_str()); } // We get the first Json object in the array and get its value afterwards (Json object comes with path&value pair, we only need value) @@ -176,7 +183,7 @@ void JetPeerWrapper::modifyJetState(const char* valueType, const std::string& pa { std::string message = "Could not modify Jet state with path: " + path + "\n" + "invalid value for boolean expecting 'true'', or 'false'\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + DAQLOG_E(jetModuleLogger, message.c_str()); } } else if(strcmp(valueType,"int")==0) @@ -206,7 +213,7 @@ void JetPeerWrapper::modifyJetState(const char* valueType, const std::string& pa { std::string message = "Could not modify Jet state with path: " + path + "\n" + "error while parsing json!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + DAQLOG_E(jetModuleLogger, message.c_str()); } } } diff --git a/src/jet_server.cpp b/src/jet_server.cpp index eaae429..00eb703 100644 --- a/src/jet_server.cpp +++ b/src/jet_server.cpp @@ -78,7 +78,8 @@ void JetServer::parseOpendaqInstance(const FolderPtr& parentFolder) componentConverter.composeJetState(component); } else { - // throwJetModuleException(JM_UNSUPPORTED_ITEM); + std::string message = "Unhandled item \"" + item.getName() + "\" in openDAQ instance!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } if(folder.assigned()) { diff --git a/src/module_dll.cpp b/src/module_dll.cpp deleted file mode 100644 index 62d3a73..0000000 --- a/src/module_dll.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "module_dll.h" -#include -#include "jet_module_impl.h" - -using namespace daq::modules::jet_module; - -DEFINE_MODULE_EXPORTS(JetModule) diff --git a/src/opendaq_event_handler.cpp b/src/opendaq_event_handler.cpp index 10ea85c..6d06ac6 100644 --- a/src/opendaq_event_handler.cpp +++ b/src/opendaq_event_handler.cpp @@ -6,8 +6,7 @@ BEGIN_NAMESPACE_JET_MODULE OpendaqEventHandler::OpendaqEventHandler() : jetPeerWrapper(JetPeerWrapper::getInstance()) { - // initiate openDAQ logger - logger = LoggerComponent("OpendaqEventHandlerLogger", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); + } /** @@ -28,7 +27,7 @@ void OpendaqEventHandler::updateProperty(const ComponentPtr& component, const Di PropertyPtr property = component.getProperty(fullPath); CoreType propertyType = property.getValueType(); - std::string message = "Update of property with CoreType " + propertyType + std::string(" is not supported currently.\n"); + std::string message = "Update of property with CoreType " + std::to_string(static_cast(propertyType)) + " is not supported currently.\n"; switch(propertyType) { case CoreType::ctBool: @@ -50,22 +49,22 @@ void OpendaqEventHandler::updateProperty(const ComponentPtr& component, const Di updateDictProperty(component, eventParameters); break; case CoreType::ctRatio: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; case CoreType::ctComplexNumber: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; case CoreType::ctStruct: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; case CoreType::ctObject: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + DAQLOG_W(jetModuleLogger, message.c_str()); break; case CoreType::ctProc: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + updateFunctionProperty(component, eventParameters); break; case CoreType::ctFunc: - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Warn); + updateFunctionProperty(component, eventParameters); break; default: break; @@ -185,6 +184,20 @@ void OpendaqEventHandler::updateDictProperty(const ComponentPtr& component, cons jetPeerWrapper.updateJetState(jetStatePath, jetState); } +/** + * @brief Update the value of callable property. + * + * @param component A component which owns the callable property. + * @param eventParameters Dictionary filled with data describing the change. + */ +void OpendaqEventHandler::updateFunctionProperty(const ComponentPtr& component, const DictPtr& eventParameters) +{ + std::string funcName = eventParameters.get("Name"); + std::string funcPath = component.getGlobalId() + "/" + funcName; + jetPeerWrapper.removeJetMethod(funcPath); + propertyManager.createJetMethod(component, component.getProperty(funcName)); +} + /** * @brief Addresses to a "Active" status change initiated by openDAQ client/server. * @@ -216,8 +229,9 @@ void OpendaqEventHandler::addProperty(const ComponentPtr& component, const DictP // Property name in eventParameters is in "Property {}" format, so we have to extract the string between curly braces std::string propertyName = extractPropertyName(eventParameters.get("Property")); if(propertyName == "") { - std::string message = "Property has been to component \"" + component.getName() + "\" but could not extract property's name!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Property has been added to component \"" + component.getName() + "\" but could not extract property's name!\n"; + DAQLOG_E(jetModuleLogger, message.c_str()); + return; } PropertyPtr property = component.getProperty(propertyName); diff --git a/src/property_converter.cpp b/src/property_converter.cpp index 360a430..e82777e 100644 --- a/src/property_converter.cpp +++ b/src/property_converter.cpp @@ -1,12 +1,12 @@ #include "property_converter.h" +#include "jet_module_exceptions.h" #include BEGIN_NAMESPACE_JET_MODULE PropertyConverter::PropertyConverter() { - // initiate openDAQ logger - logger = LoggerComponent("PropertyConverterLogger", DefaultSinks(), LoggerThreadPool(), LogLevel::Default); + } ListPtr PropertyConverter::convertJsonArrayToOpendaqList(const Json::Value& jsonArray) @@ -23,8 +23,8 @@ ListPtr PropertyConverter::convertJsonArrayToOpendaqList(const Json { case Json::ValueType::nullValue: { - std::string message = "Null type element detected in the Json array!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Null type element detected in the Json array!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; case Json::ValueType::booleanValue: @@ -60,21 +60,21 @@ ListPtr PropertyConverter::convertJsonArrayToOpendaqList(const Json case Json::ValueType::arrayValue: { // TODO: Need to figure out whether nested list properties are supported in openDAQ - std::string message = "Nested list properties are not supported!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Nested list properties are not supported!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; case Json::ValueType::objectValue: { // TODO: Need to figure out whether object or dict properties are supported in openDAQ under a list - std::string message = "ObjectProperty nested under a list is not supported!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "ObjectProperty nested under a list is not supported!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; default: { - std::string message = "Unsupported array element type detected: " + arrayElementType + '\n'; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Unsupported array element type detected: " + arrayElementType; + DAQLOG_E(jetModuleLogger, message.c_str()); } } @@ -99,8 +99,8 @@ DictPtr PropertyConverter::convertJsonDictToOpendaqDict(co { case Json::ValueType::nullValue: { - std::string message = "Null type element detected in the dictionary!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Null type element detected in the dictionary!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; case Json::ValueType::booleanValue: @@ -146,21 +146,21 @@ DictPtr PropertyConverter::convertJsonDictToOpendaqDict(co case Json::ValueType::arrayValue: { // TODO: Need to figure out whether list properties are supported in openDAQ under a dict - std::string message = "List properties nested under dictionaries is not supported!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "List properties nested under dictionaries is not supported!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; case Json::ValueType::objectValue: { // TODO: Need to figure out whether object or dict properties are supported in openDAQ under a dict - std::string message = "ObjectProperty nested under dictionaries is not supported!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "ObjectProperty nested under dictionaries is not supported!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; default: { - std::string message = "Unsupported dictionary item type detected: " + dictItemType + '\n'; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Unsupported dictionary item type detected: " + dictItemType; + DAQLOG_E(jetModuleLogger, message.c_str()); } } @@ -203,14 +203,14 @@ PropertyObjectPtr PropertyConverter::convertJsonObjectToOpendaqObject(const Json break; case Json::ValueType::arrayValue: { - std::string message = "Lists nested under ObjectProperty is not supported!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Lists nested under ObjectProperty is not supported!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; default: { - std::string message = "Unsupported item type in an ObjectProperty detected!\n"; - logger.logMessage(SourceLocation{__FILE__, __LINE__, OPENDAQ_CURRENT_FUNCTION}, message.c_str(), LogLevel::Error); + std::string message = "Unsupported item type in an ObjectProperty detected!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } break; } @@ -253,8 +253,8 @@ Json::Value PropertyConverter::convertOpendaqListToJsonArray(const ListPtr Json::Value + if(hasUnsupportedArgument(callableInfo, propertyName)) { + DAQLOG_E(jetModuleLogger, jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_TYPE).c_str()); + return; + } + // We have to check whether IFunction has a valid return type. IProcedure does not return anything + if(funcType == ctFunc && hasUnsupportedReturnType(callableInfo.getReturnType(), propertyName)) { + DAQLOG_E(jetModuleLogger, jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_RETURN_TYPE).c_str()); + return; + } + + auto cb = [func, callableInfo, funcType, this](const Json::Value& args) -> Json::Value { - try - { - int numberOfArgs = args.size(); - const BaseObjectPtr method = propertyPublisher.getPropertyValue(methodName); - if(numberOfArgs > 0) - { - BaseObjectPtr daqArg; - if(numberOfArgs > 1) - { - daqArg = List(); - for (uint16_t i = 0; i < numberOfArgs; ++i) - { - propertyConverter.convertJsonToDaqArguments(daqArg, args, i); - } - } - else - { - propertyConverter.convertJsonToDaqArguments(daqArg, args, 0); - } - if (coreType == ctFunc) - method.asPtr()(daqArg); - else - method.asPtr()(daqArg); + size_t numberOfArgs; + auto funcArgs = callableInfo.getArguments(); + if(funcArgs == nullptr) // Function has no arguments + numberOfArgs = 0; + else + numberOfArgs = funcArgs.getCount(); - return "Method called successfully"; - } - if (coreType == ctFunc) - method.asPtr()(); + BaseObjectPtr returnValue; // For ctFunc. ctProc doesn't have a return value + + // Function with zero arguments + if(numberOfArgs == 0 && args.size() == 0) { + if(funcType == CoreType::ctProc) + func.asPtr()(); + else if(funcType == CoreType::ctFunc) + returnValue = func.asPtr()(); else - method.asPtr()(); + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); + + } + // Function with one argument + else if((args.isNumeric() || args.isBool() || args.isString()) && numberOfArgs == 1) { + if(!hasCompatibleArgumentTypes(funcArgs[0].getType(), args)) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_INCOMPATIBLE_ARGUMENT_TYPES); - return "Method called successfully"; + BaseObjectPtr daqArg = convertJsonValueToDaqValue(args); + if(daqArg == nullptr) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT); + + if(funcType == CoreType::ctProc) + func.asPtr()(daqArg); + else if(funcType == CoreType::ctFunc) + returnValue = func.asPtr()(daqArg); + else + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); + // A function can be called this way as well + // func.dispatch(daqArg); } - catch(...) - { - return "Method called with failure"; + else if(args.isArray()) { + // Function with one arguments provided as a Json list + if(numberOfArgs == 1 && args.size() == 1) { + if(!hasCompatibleArgumentTypes(funcArgs[0].getType(), args[0])) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_INCOMPATIBLE_ARGUMENT_TYPES); + + BaseObjectPtr daqArg = convertJsonValueToDaqValue(args[0]); + if(daqArg == nullptr) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT); + + if(funcType == CoreType::ctProc) + func.asPtr()(daqArg); + else if(funcType == CoreType::ctFunc) + returnValue = func.asPtr()(daqArg); + else + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); + } + // Function with multiple arguments + else if(numberOfArgs == args.size()) { + auto list = List(); + int i = 0; + for(const auto& arg : args) { + if(!hasCompatibleArgumentTypes(funcArgs[i].getType(), arg)) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_INCOMPATIBLE_ARGUMENT_TYPES); + + BaseObjectPtr daqArg = convertJsonValueToDaqValue(arg); + if(daqArg == nullptr) + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT); + + list.pushBack(daqArg); + i++; + } + if(funcType == CoreType::ctProc) + func.asPtr()(list); + else if(funcType == CoreType::ctFunc) + returnValue = func.asPtr()(list); + else + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); + } + // Number of arguments for the function don't match to arguments provided from Jet + else { + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_INCORRECT_ARGUMENT_NUMBER); + } + } + else { + return jetModuleExceptionToString(JetModuleException::JM_FUNCTION_UNSUPPORTED_ARGUMENT_FORMAT); } - + + if(funcType == CoreType::ctProc) + return "Procedure called successfully!"; + else if(funcType == CoreType::ctFunc) { + Json::Value returnValJson = convertDaqValueToJsonValue(returnValue, callableInfo.getReturnType()); + if(returnValJson.type() != Json::ValueType::nullValue) + return returnValJson; + else + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); + } + else + return jetModuleExceptionToString(JetModuleException::JM_UNEXPECTED_TYPE); }; jetPeerWrapper.publishJetMethod(path, cb); } +/** + * @brief Convert Json value to openDAQ value represented BaseObject pointer. This function support conversion of + * only simple types. + * + * @param jsonVal value in Json. + * @return openDAQ value represented as BaseObjectPtr. nullptr is returned in case of unsupported Json types. + */ +BaseObjectPtr PropertyManager::convertJsonValueToDaqValue(const Json::Value& jsonVal) +{ + if(jsonVal.isBool()) + return jsonVal.asBool(); + else if(jsonVal.isInt()) + return jsonVal.asInt(); + else if(jsonVal.isInt64()) + return jsonVal.asInt64(); + else if(jsonVal.isUInt()) + return jsonVal.asUInt(); + else if(jsonVal.isUInt64()) + return jsonVal.asUInt64(); + else if(jsonVal.isDouble()) + return jsonVal.asDouble(); + else if(jsonVal.isString()) + return jsonVal.asString(); + else + return nullptr; +} + +/** + * @brief Converts openDAQ value to Json value. Supports conversion of simple openDAQ types. + * + * @param daqVal OpenDAQ value. + * @param coretype Type of the openDAQ value. + * @return Value in Json. In case of unsupported types Json value initialized with nullValue is returned. + */ +Json::Value PropertyManager::convertDaqValueToJsonValue(const BaseObjectPtr& daqVal, const CoreType& coretype) +{ + switch(coretype) + { + case CoreType::ctBool: + return static_cast(daqVal.asPtr()); + case CoreType::ctInt: + return static_cast(daqVal.asPtr()); + case CoreType::ctFloat: + return static_cast(daqVal.asPtr()); + case CoreType::ctString: + return static_cast(daqVal.asPtr()); + default: + return Json::Value(Json::nullValue); + } +} + +/** + * @brief Checks whether a function or a procedure has arguments with unsupported types. + * + * @param callableInfo An object containing information on a function/procedure's arguments' types. + * @param propertyName Name of the callable property. + * @return true if the function/procedure has unsupported arguments. + * @return false if the function does not have unsupported arguments. + */ +bool PropertyManager::hasUnsupportedArgument(const CallableInfoPtr& callableInfo, const std::string& propertyName) +{ + auto funcArgs = callableInfo.getArguments(); + if(funcArgs == nullptr) // function has no arguments + return false; // false means that everything is ok. true - function has an unsupported argument + else { + for(const auto& arg : funcArgs) { + CoreType argType = arg.getType(); + if(!(argType == ctBool || argType == ctInt || argType == ctFloat || argType == ctString)) { // These are the supported types of arguments for a function + std::string message = "Unable to add FunctionProperty \"" + propertyName + "\" because of unsupported argument. Supported function arguments are: ctBool, ctInt, ctFloat, ctString."; + DAQLOG_E(jetModuleLogger, message.c_str()); + return true; + } + } + return false; + } +} + +/** + * @brief Checks whether a function returns unsupported variable type. + * + * @param returnType Type of the return value. + * @param propertyName Name of the callable property. + * @return true if the function's return type is unsupported. + * @return false if the function's return type is supported. + */ +bool PropertyManager::hasUnsupportedReturnType(const CoreType& returnType, const std::string& propertyName) +{ + if(!(returnType == ctBool || returnType == ctInt || returnType == ctFloat || returnType == ctString)) { // These are the supported return typess for a function + std::string message = "Unable to add FunctionProperty \"" + propertyName + "\" because of unsupported return type. Supported function return types are: ctBool, ctInt, ctFloat, ctString."; + DAQLOG_E(jetModuleLogger, message.c_str()); + return true; + } + else + return false; +} + +/** + * @brief Checks whether a function's/procedure's arguments have been provided with correct types from Jet. + * + * @param daqType Type of the function's/procedure's argument in openDAQ. + * @param jsonVal Type of the function's/procedure's argument provided from Jet. + * @return true if the argument types provided from Jet are compatible with function's/procedure's definition. + * @return false if the argument types provided from Jet are incompatible with function's/procedure's definition. + */ +bool PropertyManager::hasCompatibleArgumentTypes(CoreType daqType, const Json::Value& jsonVal) +{ + switch(daqType) + { + case CoreType::ctBool: + if(jsonVal.isBool()) return true; + break; + case CoreType::ctInt: + if(jsonVal.isInt() || jsonVal.isInt64() || jsonVal.isUInt() || jsonVal.isUInt64()) return true; + break; + case CoreType::ctFloat: + if(jsonVal.isDouble()) return true; + break; + case CoreType::ctString: + if(jsonVal.isString()) return true; + break; + default: + // For unsupported daq types 'false' is returned + return false; + break; + } + + return false; +} + END_NAMESPACE_JET_MODULE \ No newline at end of file diff --git a/tests/jet_server_test.cpp b/tests/jet_server_test.cpp index 4ebec02..c38923e 100644 --- a/tests/jet_server_test.cpp +++ b/tests/jet_server_test.cpp @@ -1,5 +1,7 @@ #include #include "jet_server_test.h" +#include +#include // Checks whether all of the required Jet states are present TEST_F(JetServerTest, CheckStatePresence) @@ -204,3 +206,122 @@ TEST_F(JetServerTest, TestDictProperty) valueInOpendaq = rootDevice.getPropertyValue(propertyName); EXPECT_EQ(valueInJet, valueInOpendaq); } + +TEST_F(JetServerTest, TestFunctionPropertyProcedure) +{ + hbk::jet::Peer callingPeer(hbk::jet::JET_UNIX_DOMAIN_SOCKET_NAME, 0, "callingPeer"); + double timeout = 50; // 50ms + + int testVar = 0; + + + // Procedure with no argument + std::string propName = "TestProcNoArg"; + const auto procPropertyNoArg = FunctionProperty(propName, ProcedureInfo()); + rootDevice.addProperty(procPropertyNoArg); + rootDevice.setPropertyValue(propName, Procedure([&testVar] () { testVar = 10; })); + + std::string path = rootDevicePath + "/" + propName; + Json::Value result = callingPeer.callMethod(path, Json::Value(), timeout); + ASSERT_EQ(testVar, 10); + + // Procedure with single argument + propName = "TestProcSingleArg"; + const auto procPropertySingleArg = FunctionProperty(propName, ProcedureInfo(List(ArgumentInfo("arg", CoreType::ctInt)))); + rootDevice.addProperty(procPropertySingleArg); + rootDevice.setPropertyValue(propName, Procedure([&testVar] (int arg) { testVar = arg; })); + + path = rootDevicePath + "/" + propName; + result = callingPeer.callMethod(path, 20, timeout); + ASSERT_EQ(testVar, 20); + + + // Procedure with single argument provided as a list + propName = "TestProcSingleArgAsList"; + const auto procPropertySingleArgAsList = FunctionProperty(propName, ProcedureInfo(List(ArgumentInfo("arg", CoreType::ctInt)))); + rootDevice.addProperty(procPropertySingleArgAsList); + rootDevice.setPropertyValue(propName, Procedure([&testVar] (int arg) { testVar = arg; })); + + path = rootDevicePath + "/" + propName; + Json::Value jsonArray; + jsonArray.append(30); + result = callingPeer.callMethod(path, jsonArray, timeout); + ASSERT_EQ(testVar, 30); + + + // Procedure with multiple arguments of different types + propName = "TestProcMultipleArg"; + const auto procPropertyMultipleArg = FunctionProperty(propName, ProcedureInfo(List(ArgumentInfo("arg1", CoreType::ctInt), + ArgumentInfo("arg2", CoreType::ctFloat), + ArgumentInfo("arg3", CoreType::ctBool), + ArgumentInfo("arg4", CoreType::ctString)))); + rootDevice.addProperty(procPropertyMultipleArg); + rootDevice.setPropertyValue(propName, Procedure([&testVar] (int arg1, double arg2, bool arg3, std::string arg4) { testVar = arg1; })); + + path = rootDevicePath + "/" + propName; + jsonArray.clear(); + jsonArray.append(40); + jsonArray.append(420.69); + jsonArray.append(true); + jsonArray.append("Georgia"); + result = callingPeer.callMethod(path, jsonArray, timeout); + ASSERT_EQ(testVar, 40); +} + +TEST_F(JetServerTest, TestFunctionPropertyFunction) +{ + hbk::jet::Peer callingPeer(hbk::jet::JET_UNIX_DOMAIN_SOCKET_NAME, 0, "callingPeer"); + double timeout = 50; // 50ms + + + // Function with no argument + std::string propName = "TestFuncNoArg"; + const auto procPropertyNoArg = FunctionProperty(propName, FunctionInfo(CoreType::ctInt)); + rootDevice.addProperty(procPropertyNoArg); + rootDevice.setPropertyValue(propName, Function([] () { return 42; })); + + std::string path = rootDevicePath + "/" + propName; + Json::Value result = callingPeer.callMethod(path, Json::Value(), timeout); + ASSERT_EQ(result.asInt(), 42); + + + // Function with single argument + propName = "TestFuncSingleArg"; + const auto procPropertySingleArg = FunctionProperty(propName, FunctionInfo(CoreType::ctInt, List(ArgumentInfo("arg", CoreType::ctInt)))); + rootDevice.addProperty(procPropertySingleArg); + rootDevice.setPropertyValue(propName, Function([] (int arg) { return arg; })); + + path = rootDevicePath + "/" + propName; + result = callingPeer.callMethod(path, 69, timeout); + ASSERT_EQ(result.asInt(), 69); + + + // Function with single argument provided as a list + propName = "TestFuncSingleArgAsList"; + const auto procPropertySingleArgAsList = FunctionProperty(propName, FunctionInfo(CoreType::ctInt, List(ArgumentInfo("arg", CoreType::ctInt)))); + rootDevice.addProperty(procPropertySingleArgAsList); + rootDevice.setPropertyValue(propName, Function([] (int arg) { return arg; })); + + path = rootDevicePath + "/" + propName; + Json::Value jsonArray; + jsonArray.append(420); + result = callingPeer.callMethod(path, jsonArray, timeout); + ASSERT_EQ(result.asInt(), 420); + + + // Function with multiple arguments + propName = "TestFuncMultipleArg"; + const auto procPropertyMultipleArg = FunctionProperty(propName, FunctionInfo(CoreType::ctFloat, List(ArgumentInfo("arg1", CoreType::ctFloat), + ArgumentInfo("arg2", CoreType::ctFloat), + ArgumentInfo("arg3", CoreType::ctFloat)))); + rootDevice.addProperty(procPropertyMultipleArg); + rootDevice.setPropertyValue(propName, Function([] (double arg1, double arg2, double arg3) { return (arg1+arg2+arg3)/3; })); + + path = rootDevicePath + "/" + propName; + jsonArray.clear(); + jsonArray.append(10); + jsonArray.append(20); + jsonArray.append(30); + result = callingPeer.callMethod(path, jsonArray, timeout); + ASSERT_EQ(result.asInt(), 20); +} \ No newline at end of file diff --git a/tests/jet_server_test.h b/tests/jet_server_test.h index 1f71fff..c2af139 100644 --- a/tests/jet_server_test.h +++ b/tests/jet_server_test.h @@ -29,7 +29,7 @@ #define JET_GET_VALUE_TIMEOUT (1) // 1 second using namespace daq; -using namespace daq::modules::jet_module; +using namespace jet_module; using namespace hbk::jet; /** @@ -215,12 +215,22 @@ void JetServerTest::parseOpendaqInstance(const FolderPtr& parentFolder, std::vec globalIdVector.push_back(component.getGlobalId()); } else { - // throwJetModuleException(JM_UNSUPPORTED_ITEM); + std::string message = "Unhandled item \"" + item.getName() + "\" in openDAQ instance!"; + DAQLOG_E(jetModuleLogger, message.c_str()); } if(folder.assigned()) { parseOpendaqInstance(folder, globalIdVector); } + else { + // As ObjecProperty is represented as a separate state, we have to parse each component to find such properties. + auto properties = item.getAllProperties(); + for(const auto& property : properties) { + if(property.getValueType() == CoreType::ctObject) { + globalIdVector.push_back(item.getGlobalId() + "/" + property.getName()); + } + } + } } } diff --git a/tests/property_converter_test.h b/tests/property_converter_test.h index 38aa28c..6482cd6 100644 --- a/tests/property_converter_test.h +++ b/tests/property_converter_test.h @@ -19,7 +19,7 @@ #include "property_converter.h" using namespace daq; -using namespace daq::modules::jet_module; +using namespace jet_module; // using namespace hbk::jet; class PropertyConverterTest : public ::testing::Test {