.
This commit is contained in:
@@ -9,4 +9,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include "celix/framework.h"
|
#include "celix/framework.h"
|
||||||
#include "celix/linked_list_iterator.h"
|
#include "celix/linked_list_iterator.h"
|
||||||
|
#include "celix/bundle_activator.h"
|
||||||
|
#include "celix/bundle_context.h"
|
||||||
|
#include "celix/service_listener.h"
|
||||||
|
#include "celix/service_reference.h"
|
||||||
|
#include "celix/constants.h"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ namespace core {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum class CoreServiceEventType : int {
|
||||||
|
STARTUP_FINISHED = 1,
|
||||||
|
SHUTDOWN = 2
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for events emitted by the CoreService.
|
* Base class for events emitted by the CoreService.
|
||||||
*/
|
*/
|
||||||
@@ -29,12 +34,10 @@ class CoreServiceEvent {
|
|||||||
public:
|
public:
|
||||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||||
|
|
||||||
enum class EventType : int { STARTUP_FINISHED = 1, SHUTDOWN = 2 };
|
CoreServiceEventType eventType;
|
||||||
|
|
||||||
const EventType eventType;
|
|
||||||
const timestamp_t timestamp;
|
const timestamp_t timestamp;
|
||||||
|
|
||||||
CoreServiceEvent(EventType type, const timestamp_t timestamp = std::chrono::system_clock::now())
|
CoreServiceEvent(CoreServiceEventType type, const timestamp_t timestamp = std::chrono::system_clock::now())
|
||||||
: eventType(type), timestamp(timestamp) {}
|
: eventType(type), timestamp(timestamp) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ public:
|
|||||||
class StartupFinishedEvent
|
class StartupFinishedEvent
|
||||||
: public CoreServiceEvent {
|
: public CoreServiceEvent {
|
||||||
public:
|
public:
|
||||||
StartupFinishedEvent() : CoreServiceEvent(EventType::STARTUP_FINISHED) {}
|
StartupFinishedEvent() : CoreServiceEvent(CoreServiceEventType::STARTUP_FINISHED) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +64,7 @@ public:
|
|||||||
class ShutdownEvent
|
class ShutdownEvent
|
||||||
: public CoreServiceEvent {
|
: public CoreServiceEvent {
|
||||||
public:
|
public:
|
||||||
ShutdownEvent() : CoreServiceEvent(EventType::SHUTDOWN) {}
|
ShutdownEvent() : CoreServiceEvent(CoreServiceEventType::SHUTDOWN) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ template<> const int implementation::ServiceInfo<CoreServiceImpl>::minor = 0;
|
|||||||
|
|
||||||
|
|
||||||
CoreServiceImpl::CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle)
|
CoreServiceImpl::CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle)
|
||||||
: publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {}
|
: publicNodeHandle(publicNodeHandle), privateNodeHandle(privateNodeHandle) {
|
||||||
|
schemaLoader.reset(new utils::SchemaLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,43 +33,20 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle);
|
CoreServiceImpl(ros::NodeHandle& publicNodeHandle, ros::NodeHandle& privateNodeHandle);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
/* Public Service Implementations */
|
||||||
////////////// Public Service Implementations //////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a reference to a node handle with public namespace.
|
|
||||||
*
|
|
||||||
* \return public node handle
|
|
||||||
*/
|
|
||||||
virtual ros::NodeHandle& getPublicNodeHandle() override {
|
virtual ros::NodeHandle& getPublicNodeHandle() override {
|
||||||
return publicNodeHandle;
|
return publicNodeHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a reference to a node handle with private namespace.
|
|
||||||
*
|
|
||||||
* \return private node handle
|
|
||||||
*/
|
|
||||||
virtual ros::NodeHandle& getPrivateNodeHandle() override {
|
virtual ros::NodeHandle& getPrivateNodeHandle() override {
|
||||||
return privateNodeHandle;
|
return privateNodeHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Request an application shutdown
|
|
||||||
*/
|
|
||||||
virtual void requestShutdown() override;
|
virtual void requestShutdown() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a reference to the schema loader.
|
|
||||||
*
|
|
||||||
* \return schema loader.
|
|
||||||
*/
|
|
||||||
virtual utils::SchemaLoader& getSchemaLoader() override {
|
virtual utils::SchemaLoader& getSchemaLoader() override {
|
||||||
return *schemaLoader;
|
return *schemaLoader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Boost
|
// Boost
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
// ROS
|
// ROS
|
||||||
#include "ros/ros.h"
|
#include <ros/ros.h>
|
||||||
// APR
|
// APR
|
||||||
#include <apr_general.h>
|
#include <apr_general.h>
|
||||||
#include <apr_strings.h>
|
#include <apr_strings.h>
|
||||||
|
|||||||
+121
-25
@@ -1,5 +1,6 @@
|
|||||||
#ifndef _HOS_DEVICEREPOSITORY_SERVICE_H_
|
|
||||||
#define _HOS_DEVICEREPOSITORY_SERVICE_H_
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/Interface.h>
|
#include <hos/cosgi/service/Interface.h>
|
||||||
@@ -26,6 +27,22 @@ using namespace libvariant;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device event type.
|
||||||
|
*
|
||||||
|
* DeviceRepositoryService emits DEVICE_ADDED, DEVICE_REMOVED.
|
||||||
|
* Device emits STATUS_UPDATE_RECEIVED, COMMAND_RECEIVED, STATE_CHANGED, DEVICE_REMOVED.
|
||||||
|
**/
|
||||||
|
enum class DeviceEventType : int {
|
||||||
|
DEVICE_ADDED = 1,
|
||||||
|
DEVICE_REMOVED = 2,
|
||||||
|
STATUS_UPDATE_RECEIVED = 3,
|
||||||
|
COMMAND_RECEIVED = 4,
|
||||||
|
STATE_CHANGED = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for device events.
|
* Base class for device events.
|
||||||
*/
|
*/
|
||||||
@@ -33,20 +50,15 @@ class DeviceEvent {
|
|||||||
public:
|
public:
|
||||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||||
|
|
||||||
enum class EventType : int {
|
DeviceEventType eventType;
|
||||||
DEVICE_ADDED = 1,
|
|
||||||
DEVICE_REMOVED = 2,
|
|
||||||
STATUS_UPDATE_RECEIVED = 3,
|
|
||||||
COMMAND_RECEIVED = 4,
|
|
||||||
STATE_CHANGED = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
Device* const device;
|
Device* const device;
|
||||||
const timestamp_t timestamp;
|
|
||||||
const EventType eventType;
|
|
||||||
|
|
||||||
DeviceEvent(Device* device, const EventType& type, const timestamp_t& timestamp)
|
const timestamp_t timestamp;
|
||||||
: device(device), timestamp(timestamp), eventType(type) {}
|
|
||||||
|
DeviceEvent(Device* device, const DeviceEventType& type, const timestamp_t& timestamp)
|
||||||
|
: eventType(type), device(device), timestamp(timestamp) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -58,7 +70,7 @@ class DeviceAddedEvent
|
|||||||
: public DeviceEvent {
|
: public DeviceEvent {
|
||||||
public:
|
public:
|
||||||
DeviceAddedEvent(Device* device, const timestamp_t& timestamp)
|
DeviceAddedEvent(Device* device, const timestamp_t& timestamp)
|
||||||
: DeviceEvent(device, DeviceEvent::EventType::DEVICE_ADDED, timestamp) {}
|
: DeviceEvent(device,DeviceEventType::DEVICE_ADDED, timestamp) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -70,7 +82,7 @@ class DeviceRemovedEvent
|
|||||||
: public DeviceEvent {
|
: public DeviceEvent {
|
||||||
public:
|
public:
|
||||||
DeviceRemovedEvent(Device* device, const timestamp_t& timestamp)
|
DeviceRemovedEvent(Device* device, const timestamp_t& timestamp)
|
||||||
: DeviceEvent(device, DeviceEvent::EventType::DEVICE_REMOVED, timestamp) {}
|
: DeviceEvent(device, DeviceEventType::DEVICE_REMOVED, timestamp) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -84,7 +96,7 @@ public:
|
|||||||
const Variant statusMsg;
|
const Variant statusMsg;
|
||||||
|
|
||||||
DeviceStatusMsgEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
DeviceStatusMsgEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
||||||
: DeviceEvent(device, DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, timestamp), statusMsg(statusMsg) {}
|
: DeviceEvent(device, DeviceEventType::STATUS_UPDATE_RECEIVED, timestamp), statusMsg(statusMsg) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -98,7 +110,7 @@ public:
|
|||||||
const Variant cmdMsg;
|
const Variant cmdMsg;
|
||||||
|
|
||||||
DeviceCmdMsgEvent(Device* device, const Variant& cmdMsg, const timestamp_t& timestamp)
|
DeviceCmdMsgEvent(Device* device, const Variant& cmdMsg, const timestamp_t& timestamp)
|
||||||
: DeviceEvent(device, DeviceEvent::EventType::COMMAND_RECEIVED, timestamp), cmdMsg(cmdMsg) {}
|
: DeviceEvent(device, DeviceEventType::COMMAND_RECEIVED, timestamp), cmdMsg(cmdMsg) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -112,33 +124,89 @@ public:
|
|||||||
const Variant statusMsg;
|
const Variant statusMsg;
|
||||||
|
|
||||||
DeviceStateChangeEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
DeviceStateChangeEvent(Device* device, const Variant& statusMsg, const timestamp_t& timestamp)
|
||||||
: DeviceEvent(device, DeviceEvent::EventType::STATE_CHANGED, timestamp), statusMsg(statusMsg) {}
|
: DeviceEvent(device, DeviceEventType::STATE_CHANGED, timestamp), statusMsg(statusMsg) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public COSGI interface of an device object.
|
* Public COSGI interface of an device object.
|
||||||
|
*
|
||||||
|
* It offers following functionality:
|
||||||
|
* - Get device informations.
|
||||||
|
* - Events indicating device state changes.
|
||||||
|
* - Send commands to the device.
|
||||||
*/
|
*/
|
||||||
class Device
|
class Device
|
||||||
: public virtual interface::ObservableObject<DeviceEvent::EventType, DeviceEvent> {
|
: public virtual interface::ObservableObject<DeviceEventType, DeviceEvent> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device identifier.
|
||||||
|
*
|
||||||
|
* \return unique device identifier.
|
||||||
|
*/
|
||||||
virtual const std::string& getDeviceID() noexcept = 0;
|
virtual const std::string& getDeviceID() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device type.
|
||||||
|
*
|
||||||
|
* \return device type.
|
||||||
|
*/
|
||||||
virtual const std::string& getDeviceType() noexcept = 0;
|
virtual const std::string& getDeviceType() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ROS topic the device uses for commands.
|
||||||
|
*
|
||||||
|
* \return command topic.
|
||||||
|
*/
|
||||||
virtual const std::string& getCmdTopic() noexcept = 0;
|
virtual const std::string& getCmdTopic() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ROS topic the device uses for status updates.
|
||||||
|
*
|
||||||
|
* \return status updates topic.
|
||||||
|
*/
|
||||||
virtual const std::string& getStatusTopic() noexcept = 0;
|
virtual const std::string& getStatusTopic() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current state of the device.
|
||||||
|
*
|
||||||
|
* \return current state.
|
||||||
|
*/
|
||||||
virtual const Variant& getCurrentState() noexcept = 0;
|
virtual const Variant& getCurrentState() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timestamp of the current state.
|
||||||
|
*
|
||||||
|
* \return timestamp.
|
||||||
|
*/
|
||||||
virtual const timestamp_t& getCurrentStateTimestamp() noexcept = 0;
|
virtual const timestamp_t& getCurrentStateTimestamp() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last state of the device.
|
||||||
|
*
|
||||||
|
* \return last state.
|
||||||
|
*/
|
||||||
virtual const Variant& getLastState() noexcept = 0;
|
virtual const Variant& getLastState() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timestamp of the last state.
|
||||||
|
*
|
||||||
|
* \return timestamp.
|
||||||
|
*/
|
||||||
virtual const timestamp_t& getLastStateTimestamp() noexcept = 0;
|
virtual const timestamp_t& getLastStateTimestamp() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a command to the device.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param[in] cmd command.
|
||||||
|
*/
|
||||||
virtual void sendCommand(const Variant& cmd) = 0;
|
virtual void sendCommand(const Variant& cmd) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -146,18 +214,49 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public COSGI interface of the device repository service
|
* Public COSGI interface of the device repository service.
|
||||||
**/
|
*
|
||||||
|
* It offers following functionality:
|
||||||
|
* - Retrieve devices.
|
||||||
|
* - Events indicating new/removed devices.
|
||||||
|
*/
|
||||||
class DeviceRepositoryService
|
class DeviceRepositoryService
|
||||||
: public virtual interface::ObservableService<DeviceEvent::EventType, DeviceEvent> {
|
: public virtual interface::ObservableService<DeviceEventType, DeviceEvent> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service name.
|
||||||
|
*/
|
||||||
static constexpr const char* SERVICE_NAME = "hos_devicerepository_service";
|
static constexpr const char* SERVICE_NAME = "hos_devicerepository_service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the device with the given identifier.
|
||||||
|
*
|
||||||
|
* \param[in] device_id device identifier.
|
||||||
|
* \return device pointer, or expired pointer when no device was found.
|
||||||
|
*/
|
||||||
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept = 0;
|
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all known devices.
|
||||||
|
*
|
||||||
|
* \return vector of device pointers.
|
||||||
|
*/
|
||||||
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept = 0;
|
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of known devices.
|
||||||
|
*
|
||||||
|
* \return device count.
|
||||||
|
*/
|
||||||
virtual size_t deviceCount() noexcept = 0;
|
virtual size_t deviceCount() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the device ids of known devices.
|
||||||
|
*
|
||||||
|
* \return vector of device pointers.
|
||||||
|
*/
|
||||||
virtual std::vector<std::string> getDeviceIDs() noexcept = 0;
|
virtual std::vector<std::string> getDeviceIDs() noexcept = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -169,6 +268,3 @@ public:
|
|||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
} // namespace hos
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _HOS_DEVICEREPOSITORY_SERVICE_H_ */
|
|
||||||
|
|||||||
@@ -1,41 +1,42 @@
|
|||||||
|
|
||||||
|
// std
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
// ROS
|
||||||
|
#include <ros/ros.h>
|
||||||
|
// APR
|
||||||
#include <apr_general.h>
|
#include <apr_general.h>
|
||||||
|
// Celix
|
||||||
#include "ros/ros.h"
|
#include <hos/cosgi/celix.h>
|
||||||
|
// CoreService
|
||||||
extern "C" {
|
|
||||||
#include "celix/bundle_activator.h"
|
|
||||||
#include "celix/bundle_context.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace hos::cosgi;
|
using namespace hos::cosgi;
|
||||||
using namespace hos::cosgi::service::devicerepository;
|
using namespace hos::cosgi::service::devicerepository;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct UserData {
|
struct UserData {
|
||||||
apr_pool_t* memoryPool = nullptr;
|
apr_pool_t* memoryPool = nullptr;
|
||||||
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
||||||
service_registration_pt serviceReg = nullptr;
|
service_registration_pt serviceReg = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
||||||
celix_status_t status = CELIX_START_ERROR;
|
celix_status_t status = CELIX_START_ERROR;
|
||||||
apr_pool_t* memoryPool = nullptr;
|
apr_pool_t* memoryPool = nullptr;
|
||||||
|
|
||||||
// Create APR memory pool
|
// Create APR memory pool
|
||||||
apr_status_t astatus = apr_pool_create(&memoryPool, NULL);
|
apr_status_t astatus = apr_pool_create(&memoryPool, NULL);
|
||||||
if (astatus != APR_SUCCESS) {
|
if (astatus != APR_SUCCESS) {
|
||||||
ROS_ERROR("DeviceRepositoryService: Could not create APR memory pool (%i).", astatus);
|
ROS_ERROR("DeviceRepositoryService: Could not create APR memory pool (%i).", astatus);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Create user data
|
// Create user data
|
||||||
UserData* myUserData = (UserData*)apr_palloc(memoryPool, sizeof(UserData));
|
UserData* myUserData = (UserData*)apr_palloc(memoryPool, sizeof(UserData));
|
||||||
if (myUserData != nullptr) {
|
if (myUserData != nullptr) {
|
||||||
@@ -47,20 +48,24 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
|
|||||||
ROS_ERROR("DeviceRepositoryService: Could not create user data struct");
|
ROS_ERROR("DeviceRepositoryService: Could not create user data struct");
|
||||||
apr_pool_destroy(memoryPool);
|
apr_pool_destroy(memoryPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_SUCCESS;
|
celix_status_t status = CELIX_SUCCESS;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
UserData* myUserData = (UserData*)userData;
|
UserData* myUserData = (UserData*)userData;
|
||||||
// Create hos-devicerepository-service
|
|
||||||
|
// Create device repository service
|
||||||
if (myUserData->serviceReg != nullptr) {
|
if (myUserData->serviceReg != nullptr) {
|
||||||
serviceRegistration_unregister(myUserData->serviceReg);
|
serviceRegistration_unregister(myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
myUserData->serviceImpl.reset(new DeviceRepositoryServiceImpl());
|
myUserData->serviceImpl.reset(new DeviceRepositoryServiceImpl());
|
||||||
// Get HOS Core Service
|
|
||||||
|
// Get core service
|
||||||
service_reference_pt ref = nullptr;
|
service_reference_pt ref = nullptr;
|
||||||
bundleContext_getServiceReference(context, (char*)service::core::CoreService::SERVICE_NAME, &ref);
|
bundleContext_getServiceReference(context, (char*)service::core::CoreService::SERVICE_NAME, &ref);
|
||||||
service::core::CoreService* coreService = nullptr;
|
service::core::CoreService* coreService = nullptr;
|
||||||
@@ -70,10 +75,12 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
} else {
|
} else {
|
||||||
myUserData->serviceImpl->setCoreService(coreService);
|
myUserData->serviceImpl->setCoreService(coreService);
|
||||||
}
|
}
|
||||||
// Register hos-devicerepository-service
|
|
||||||
|
// Register device repository service
|
||||||
if (myUserData->serviceImpl->isInitialized()) {
|
if (myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(context, (char*)DeviceRepositoryService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
bundleContext_registerService(context, (char*)DeviceRepositoryService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ROS_INFO("DeviceRepositoryService: Bundle successfully started");
|
ROS_INFO("DeviceRepositoryService: Bundle successfully started");
|
||||||
} else {
|
} else {
|
||||||
ROS_ERROR("DeviceRepositoryService: Could not start bundle, user data struct is null");
|
ROS_ERROR("DeviceRepositoryService: Could not start bundle, user data struct is null");
|
||||||
@@ -81,6 +88,7 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
@@ -100,6 +108,7 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
@@ -116,3 +125,4 @@ celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt contex
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+139
-95
@@ -1,12 +1,5 @@
|
|||||||
/*
|
|
||||||
* hos_itemrepository_service_impl.cpp
|
|
||||||
*
|
|
||||||
* Created on: 05.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "DeviceRepositoryServiceImpl.h"
|
#include "DeviceRepositoryServiceImpl.h"
|
||||||
|
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
@@ -15,51 +8,65 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace devicerepository {
|
namespace devicerepository {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Service information
|
||||||
template<> const char* implementation::ServiceInfo<DeviceRepositoryServiceImpl>::name = service::devicerepository::DeviceRepositoryService::SERVICE_NAME;
|
template<> const char* implementation::ServiceInfo<DeviceRepositoryServiceImpl>::name = service::devicerepository::DeviceRepositoryService::SERVICE_NAME;
|
||||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::major = 1;
|
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::major = 1;
|
||||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::minor = 0;
|
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::minor = 0;
|
||||||
|
|
||||||
|
|
||||||
bool DeviceImpl::handleStatusMsg(const Variant& msg, const timestamp_t& stamp) {
|
|
||||||
|
bool DeviceImpl::handleStatusMsg(const Variant& msg, const timestamp_t& stamp) noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||||
Variant tmp = currentState.Copy();
|
|
||||||
tmp.Merge(msg);
|
|
||||||
bool stateChanged = false;
|
bool stateChanged = false;
|
||||||
if (tmp != currentState) { // state has changed
|
Variant newstate = currentState.Copy();
|
||||||
lastState = currentState.Copy();
|
newstate.Merge(msg);
|
||||||
lastStamp = currentStamp;
|
|
||||||
currentState = std::move(tmp);
|
if (newstate != currentState) {
|
||||||
|
lastState = std::move(currentState);
|
||||||
|
lastStamp = std::move(currentStamp);
|
||||||
|
currentState = std::move(newstate);
|
||||||
currentStamp = stamp;
|
currentStamp = stamp;
|
||||||
stateChanged = true;
|
stateChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceStatusMsgEvent event(this, msg, stamp);
|
DeviceStatusMsgEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
notifyObservers(DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||||
|
|
||||||
if (stateChanged){
|
if (stateChanged){
|
||||||
DeviceStateChangeEvent event(this, msg, stamp);
|
DeviceStateChangeEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEvent::EventType::STATE_CHANGED, &event);
|
notifyObservers(DeviceEventType::STATE_CHANGED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateChanged;
|
return stateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp) {
|
|
||||||
|
void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp) noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||||
DeviceCmdMsgEvent event(this, msg, stamp);
|
DeviceCmdMsgEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEvent::EventType::COMMAND_RECEIVED, &event);
|
notifyObservers(DeviceEventType::COMMAND_RECEIVED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceImpl::sendCommand(const Variant& cmd) {
|
void DeviceImpl::sendCommand(const Variant& cmd) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||||
parent->sendDeviceCommand(this, cmd);
|
parent->sendDeviceCommand(this, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* coreService) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* coreService) noexcept {
|
||||||
if (coreService && !this->coreService) {
|
if (coreService && !this->coreService) {
|
||||||
this->coreService = coreService;
|
this->coreService = coreService;
|
||||||
this->nodehandle = &coreService->getPrivateNodeHandle();
|
this->nodehandle = &coreService->getPrivateNodeHandle();
|
||||||
@@ -70,11 +77,15 @@ void DeviceRepositoryServiceImpl::setCoreService(service::core::CoreService* cor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::init() {
|
|
||||||
|
void DeviceRepositoryServiceImpl::init() noexcept {
|
||||||
|
// Get public parameters
|
||||||
nodehandle->getParam("device_repository_prefix", deviceRepositoryPrefix);
|
nodehandle->getParam("device_repository_prefix", deviceRepositoryPrefix);
|
||||||
nodehandle->getParam("hos_status_topic", hosStatusTopic);
|
nodehandle->getParam("hos_status_topic", hosStatusTopic);
|
||||||
XmlRpc::XmlRpcValue rawValue;
|
XmlRpc::XmlRpcValue rawValue;
|
||||||
nodehandle->getParam(deviceRepositoryPrefix, rawValue);
|
nodehandle->getParam(deviceRepositoryPrefix, rawValue);
|
||||||
|
|
||||||
|
// create devices
|
||||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||||
for (auto dev : rawValue) {
|
for (auto dev : rawValue) {
|
||||||
std::string devname = dev.first;
|
std::string devname = dev.first;
|
||||||
@@ -87,11 +98,13 @@ void DeviceRepositoryServiceImpl::init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hosStatusSub = nodehandle->subscribe(hosStatusTopic, 1000, &DeviceRepositoryServiceImpl::hosStatusMsgCallback, this);
|
hosStatusSub = nodehandle->subscribe(hosStatusTopic, 1000, &DeviceRepositoryServiceImpl::hosStatusMsgCallback, this);
|
||||||
initialized = true;
|
initialized = true;
|
||||||
ROS_INFO_STREAM("DeviceRepositoryService: Initialized and Ready.");
|
ROS_INFO_STREAM("DeviceRepositoryService: Initialized and Ready.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::addDevice(const std::string& name) {
|
void DeviceRepositoryServiceImpl::addDevice(const std::string& name) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << deviceRepositoryPrefix << "/" << name;
|
ss << deviceRepositoryPrefix << "/" << name;
|
||||||
@@ -100,28 +113,37 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name) {
|
|||||||
addDevice(name, rawValue);
|
addDevice(name, rawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue) {
|
void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::string type, statusTopic, cmdTopic;
|
std::string type, statusTopic, cmdTopic;
|
||||||
|
|
||||||
|
// device type
|
||||||
XmlRpc::XmlRpcValue& typeRaw = rawValue["type"];
|
XmlRpc::XmlRpcValue& typeRaw = rawValue["type"];
|
||||||
if (typeRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
if (typeRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||||
throw std::runtime_error("type is not a string.");
|
throw std::runtime_error("type is not a string.");
|
||||||
}
|
}
|
||||||
type = static_cast<std::string>(typeRaw);
|
type = static_cast<std::string>(typeRaw);
|
||||||
|
|
||||||
|
// device status topic
|
||||||
XmlRpc::XmlRpcValue& statusTopicRaw = rawValue["status_topic"];
|
XmlRpc::XmlRpcValue& statusTopicRaw = rawValue["status_topic"];
|
||||||
if (statusTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
if (statusTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||||
throw std::runtime_error("statusTopic is not a string.");
|
throw std::runtime_error("statusTopic is not a string.");
|
||||||
}
|
}
|
||||||
statusTopic = static_cast<std::string>(statusTopicRaw);
|
statusTopic = static_cast<std::string>(statusTopicRaw);
|
||||||
|
|
||||||
|
// device command topic
|
||||||
XmlRpc::XmlRpcValue& cmdTopicRaw = rawValue["cmd_topic"];
|
XmlRpc::XmlRpcValue& cmdTopicRaw = rawValue["cmd_topic"];
|
||||||
if (cmdTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
if (cmdTopicRaw.getType() != XmlRpc::XmlRpcValue::TypeString) {
|
||||||
throw std::runtime_error("cmdTopic is not a string.");
|
throw std::runtime_error("cmdTopic is not a string.");
|
||||||
}
|
}
|
||||||
cmdTopic = static_cast<std::string>(cmdTopicRaw);
|
cmdTopic = static_cast<std::string>(cmdTopicRaw);
|
||||||
|
|
||||||
|
// create device
|
||||||
std::shared_ptr<DeviceImpl> dev = std::make_shared<DeviceImpl>(this, name, type, statusTopic, cmdTopic);
|
std::shared_ptr<DeviceImpl> dev = std::make_shared<DeviceImpl>(this, name, type, statusTopic, cmdTopic);
|
||||||
devices.insert({name, dev});
|
devices.insert({name, dev});
|
||||||
|
|
||||||
// status topic
|
// status topic subscriber
|
||||||
auto& entry = subscripedTopics[dev->getStatusTopic()];
|
auto& entry = subscripedTopics[dev->getStatusTopic()];
|
||||||
if (entry.first <= 0) {
|
if (entry.first <= 0) {
|
||||||
entry.second = nodehandle->subscribe(dev->getStatusTopic(), 1000, &DeviceRepositoryServiceImpl::statusMsgCallback, this);
|
entry.second = nodehandle->subscribe(dev->getStatusTopic(), 1000, &DeviceRepositoryServiceImpl::statusMsgCallback, this);
|
||||||
@@ -130,7 +152,7 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
|||||||
subscripedTopics[dev->getStatusTopic()] = entry;
|
subscripedTopics[dev->getStatusTopic()] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmd topic
|
// cmd topic subscriber
|
||||||
auto& entry2 = subscripedTopics[dev->getCmdTopic()];
|
auto& entry2 = subscripedTopics[dev->getCmdTopic()];
|
||||||
if (entry2.first <= 0) {
|
if (entry2.first <= 0) {
|
||||||
entry2.second = nodehandle->subscribe(dev->getCmdTopic(), 1000, &DeviceRepositoryServiceImpl::cmdMsgCallback, this);
|
entry2.second = nodehandle->subscribe(dev->getCmdTopic(), 1000, &DeviceRepositoryServiceImpl::cmdMsgCallback, this);
|
||||||
@@ -139,7 +161,7 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
|||||||
subscripedTopics[dev->getCmdTopic()] = entry2;
|
subscripedTopics[dev->getCmdTopic()] = entry2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmd publisher
|
// cmd topic publisher
|
||||||
auto& entry3 = publishedTopics[dev->getCmdTopic()];
|
auto& entry3 = publishedTopics[dev->getCmdTopic()];
|
||||||
if (entry3.first <= 0) {
|
if (entry3.first <= 0) {
|
||||||
entry3.second = nodehandle->advertise<hos_core_msgs::DeviceCommand>(dev->getCmdTopic(), 1000);
|
entry3.second = nodehandle->advertise<hos_core_msgs::DeviceCommand>(dev->getCmdTopic(), 1000);
|
||||||
@@ -148,13 +170,9 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
|||||||
publishedTopics[dev->getCmdTopic()] = entry3;
|
publishedTopics[dev->getCmdTopic()] = entry3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
entry2.first= entry2.first + 1;
|
|
||||||
subscripedTopics[dev->getCmdTopic()] = entry2;
|
|
||||||
|
|
||||||
// send device added event
|
// send device added event
|
||||||
DeviceAddedEvent event(dev.get(), std::chrono::system_clock::now());
|
DeviceAddedEvent event(dev.get(), std::chrono::system_clock::now());
|
||||||
notifyObservers(DeviceEvent::EventType::DEVICE_ADDED, &event);
|
notifyObservers(DeviceEventType::DEVICE_ADDED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -163,8 +181,8 @@ void DeviceRepositoryServiceImpl::removeDevice(const std::string& name) {
|
|||||||
auto dev = devices.find(name);
|
auto dev = devices.find(name);
|
||||||
if (dev != devices.end()) {
|
if (dev != devices.end()) {
|
||||||
DeviceRemovedEvent event(dev->second.get(), std::chrono::system_clock::now());
|
DeviceRemovedEvent event(dev->second.get(), std::chrono::system_clock::now());
|
||||||
notifyObservers(DeviceEvent::EventType::DEVICE_REMOVED, &event);
|
notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
dev->second->notifyObservers(DeviceEvent::EventType::DEVICE_REMOVED, &event);
|
dev->second->notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
devices.erase(name);
|
devices.erase(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,6 +196,7 @@ std::weak_ptr<Device> DeviceRepositoryServiceImpl::getDevice(const std::string&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::weak_ptr<Device>> DeviceRepositoryServiceImpl::getDevices() noexcept {
|
std::vector<std::weak_ptr<Device>> DeviceRepositoryServiceImpl::getDevices() noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::vector<std::weak_ptr<Device>> retval;
|
std::vector<std::weak_ptr<Device>> retval;
|
||||||
@@ -188,11 +207,6 @@ std::vector<std::weak_ptr<Device>> DeviceRepositoryServiceImpl::getDevices() noe
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t DeviceRepositoryServiceImpl::deviceCount() noexcept {
|
|
||||||
return devices.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> DeviceRepositoryServiceImpl::getDeviceIDs() noexcept {
|
std::vector<std::string> DeviceRepositoryServiceImpl::getDeviceIDs() noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::vector<std::string> retval;
|
std::vector<std::string> retval;
|
||||||
@@ -203,90 +217,117 @@ std::vector<std::string> DeviceRepositoryServiceImpl::getDeviceIDs() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) {
|
void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::cout << "HOSDeviceRepositoryServiceImpl::statusMsgCallback" << std::endl;
|
|
||||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://").append(msg->device_type).append("/status"));
|
try {
|
||||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
// Verify message using appropriate json schema.
|
||||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
auto schemaUrl = (boost::format("hos:schema://%1%/status") % msg->device_type).str();
|
||||||
if (!sr.Error()) {
|
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||||
auto dev = devices.find(msg->device_id);
|
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||||
if (dev != devices.end()) {
|
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||||
auto stamp = std::chrono::system_clock::now();
|
if (!sr.Error()) {
|
||||||
bool stateChanged = dev->second->handleStatusMsg(m, stamp);
|
|
||||||
DeviceStatusMsgEvent event(dev->second.get(), m, stamp);
|
// Get recipient and pass on message
|
||||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
auto dev = devices.find(msg->device_id);
|
||||||
if (stateChanged) {
|
if (dev != devices.end()) {
|
||||||
DeviceStateChangeEvent event(dev->second.get(), m, stamp);
|
auto stamp = std::chrono::system_clock::now();
|
||||||
notifyObservers(DeviceEvent::EventType::STATE_CHANGED, &event);
|
dev->second->handleStatusMsg(m, stamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ROS_ERROR_STREAM("Could not validate status message: " << sr.PrettyPrintMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} catch (std::exception& e) {
|
||||||
ROS_ERROR_STREAM("Could not validate status message: " << sr.PrettyPrintMessage());
|
ROS_ERROR_STREAM("Exception while handling device status message: " << e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) {
|
|
||||||
|
void DeviceRepositoryServiceImpl::cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::cout << "HOSDeviceRepositoryServiceImpl::cmdMsgCallback" << std::endl;
|
|
||||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://").append(msg->device_type).append("/command"));
|
try {
|
||||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
// Verify message using appropriate json schema.
|
||||||
auto test = msg->stamp;
|
auto schemaUrl = (boost::format("hos:schema://%1%/command") % msg->device_type).str();
|
||||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||||
if (!sr.Error()) {
|
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||||
auto dev = devices.find(msg->device_id);
|
auto test = msg->stamp;
|
||||||
if (dev != devices.end()) {
|
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||||
auto stamp = std::chrono::system_clock::now();
|
if (!sr.Error()) {
|
||||||
dev->second->handleCommandMsg(m, stamp);
|
|
||||||
DeviceCmdMsgEvent event(dev->second.get(), m, stamp);
|
// Get recipient and pass on message
|
||||||
notifyObservers(DeviceEvent::EventType::STATUS_UPDATE_RECEIVED, &event);
|
auto dev = devices.find(msg->device_id);
|
||||||
|
if (dev != devices.end()) {
|
||||||
|
auto stamp = std::chrono::system_clock::now();
|
||||||
|
dev->second->handleCommandMsg(m, stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ROS_ERROR_STREAM("Could not validate command message: " << sr.PrettyPrintMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} catch (std::exception& e) {
|
||||||
ROS_ERROR_STREAM("Could not validate command message: " << sr.PrettyPrintMessage());
|
ROS_ERROR_STREAM("Exception while handling device command message: " << e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) {
|
|
||||||
|
void DeviceRepositoryServiceImpl::hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) noexcept {
|
||||||
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::cout << "HOSDeviceRepositoryServiceImpl::hosStatusMsgCallback" << std::endl;
|
|
||||||
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://core/msgs/hosstatusupdate"));
|
try {
|
||||||
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
// Verify message using appropriate json schema.
|
||||||
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
Variant s = coreService->getSchemaLoader().GetSchema(std::string("hos:schema://core/msgs/hosstatusupdate"));
|
||||||
if (!sr.Error()) {
|
Variant m = Deserialize(msg->msg_body, SERIALIZE_JSON);
|
||||||
if (m.Contains("devices")) {
|
SchemaResult sr = SchemaValidate(s, m, &coreService->getSchemaLoader());
|
||||||
auto d = m["devices"];
|
if (!sr.Error()) {
|
||||||
if (d.Contains("added") && d["added"].IsList()) {
|
|
||||||
for (auto dev : d["added"].AsList()) {
|
// we are only interested in the device part.
|
||||||
if (dev.IsString()) {
|
if (m.Contains("devices")) {
|
||||||
std::string devname = dev.AsString();
|
auto d = m["devices"];
|
||||||
if (devices.find(devname) == devices.end()) {
|
// devices added
|
||||||
addDevice(devname);
|
if (d.Contains("added") && d["added"].IsList()) {
|
||||||
|
for (auto dev : d["added"].AsList()) {
|
||||||
|
if (dev.IsString()) {
|
||||||
|
std::string devname = dev.AsString();
|
||||||
|
if (devices.find(devname) == devices.end()) {
|
||||||
|
addDevice(devname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// devices removed
|
||||||
if (d.Contains("removed") && d["removed"].IsList()) {
|
if (d.Contains("removed") && d["removed"].IsList()) {
|
||||||
for (auto dev : d["removed"].AsList()) {
|
for (auto dev : d["removed"].AsList()) {
|
||||||
if (dev.IsString()) {
|
if (dev.IsString()) {
|
||||||
std::string devname = dev.AsString();
|
std::string devname = dev.AsString();
|
||||||
if (devices.find(devname) != devices.end()) {
|
if (devices.find(devname) != devices.end()) {
|
||||||
removeDevice(devname);
|
removeDevice(devname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ROS_ERROR_STREAM("Could not validate hos status message: " << sr.PrettyPrintMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} catch (std::exception& e) {
|
||||||
ROS_ERROR_STREAM("Could not validate hos status message: " << sr.PrettyPrintMessage());
|
ROS_ERROR_STREAM("Exception while handling hos status message: " << e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepositoryServiceImpl::sendDeviceCommand(Device* device, const Variant& cmd) {
|
void DeviceRepositoryServiceImpl::sendDeviceCommand(DeviceImpl* device, const Variant& cmd) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
|
|
||||||
|
// Verify message using appropriate json schema.
|
||||||
auto schemaUrl = (boost::format("hos:schema://%1%/command") % device->getDeviceType()).str();
|
auto schemaUrl = (boost::format("hos:schema://%1%/command") % device->getDeviceType()).str();
|
||||||
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
Variant s = coreService->getSchemaLoader().GetSchema(schemaUrl);
|
||||||
SchemaResult sr = SchemaValidate(s, cmd, &coreService->getSchemaLoader());
|
SchemaResult sr = SchemaValidate(s, cmd, &coreService->getSchemaLoader());
|
||||||
if (!sr.Error()) {
|
if (!sr.Error()) {
|
||||||
|
|
||||||
|
// Retrieve appropriate publisher and send message
|
||||||
auto entry = publishedTopics[device->getCmdTopic()];
|
auto entry = publishedTopics[device->getCmdTopic()];
|
||||||
if (entry.first > 0) {
|
if (entry.first > 0) {
|
||||||
hos_core_msgs::DeviceCommand command;
|
hos_core_msgs::DeviceCommand command;
|
||||||
@@ -296,11 +337,14 @@ void DeviceRepositoryServiceImpl::sendDeviceCommand(Device* device, const Varian
|
|||||||
command.msg_body = Serialize(cmd, SERIALIZE_JSON);
|
command.msg_body = Serialize(cmd, SERIALIZE_JSON);
|
||||||
command.stamp = ros::Time::now();
|
command.stamp = ros::Time::now();
|
||||||
entry.second.publish(command);
|
entry.second.publish(command);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ROS_ERROR_STREAM("Could not find device command publisher for topic " << device->getCmdTopic());
|
auto msg = (boost::format("Could not find device command publisher for topic %1%") % device->getCmdTopic()).str();
|
||||||
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ROS_ERROR_STREAM("Could not validate device command: " << sr.PrettyPrintMessage());
|
auto msg = (boost::format("Could not validate device command: %1%") % sr.PrettyPrintMessage()).str();
|
||||||
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-48
@@ -1,27 +1,25 @@
|
|||||||
/*
|
|
||||||
* hos_itemrepository_service_impl.h
|
|
||||||
*
|
|
||||||
* Created on: 05.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_
|
#pragma once
|
||||||
#define SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_
|
|
||||||
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
// hos includes
|
||||||
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
|
#include <hos_core_msgs/DeviceCommand.h>
|
||||||
|
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||||
|
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||||
#include <hos/utils/SchemaLoader.h>
|
#include <hos/utils/SchemaLoader.h>
|
||||||
|
// libvariant includes
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
// ROS includes
|
||||||
|
#include <ros/ros.h>
|
||||||
|
// std includes
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <hos_core_msgs/DeviceCommand.h>
|
|
||||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
|
||||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
|
||||||
#include <hos/cosgi/service/Implementation.h>
|
|
||||||
#include <ros/ros.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace libvariant;
|
using namespace libvariant;
|
||||||
@@ -29,10 +27,15 @@ using namespace libvariant;
|
|||||||
|
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
/**
|
||||||
|
* Specialization of std::hash for DeviceEventType.
|
||||||
|
*
|
||||||
|
* Required by std::map.
|
||||||
|
*/
|
||||||
template <>
|
template <>
|
||||||
class hash <hos::cosgi::service::devicerepository::DeviceEvent::EventType>{
|
class hash <hos::cosgi::service::devicerepository::DeviceEventType>{
|
||||||
public :
|
public :
|
||||||
size_t operator()(const hos::cosgi::service::devicerepository::DeviceEvent::EventType& x) const {
|
size_t operator()(const hos::cosgi::service::devicerepository::DeviceEventType& x) const {
|
||||||
return static_cast<size_t>(x);
|
return static_cast<size_t>(x);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -52,22 +55,26 @@ class DeviceRepositoryServiceImpl;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device implementation
|
* Implementation of Device.
|
||||||
**/
|
**/
|
||||||
class DeviceImpl
|
class DeviceImpl
|
||||||
: public virtual Device,
|
: public virtual Device,
|
||||||
public virtual implementation::ObservableObject<DeviceEvent::EventType, DeviceEvent> {
|
public virtual implementation::ObservableObject<DeviceEventType, DeviceEvent> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
DeviceRepositoryServiceImpl* parent;
|
DeviceRepositoryServiceImpl* parent;
|
||||||
std::recursive_mutex objMutex;
|
std::recursive_mutex objMutex;
|
||||||
|
|
||||||
std::string deviceID;
|
std::string deviceID;
|
||||||
std::string deviceType;
|
std::string deviceType;
|
||||||
|
|
||||||
std::string statusTopic;
|
std::string statusTopic;
|
||||||
std::string cmdTopic;
|
std::string cmdTopic;
|
||||||
|
|
||||||
Variant currentState;
|
Variant currentState;
|
||||||
timestamp_t currentStamp;
|
timestamp_t currentStamp;
|
||||||
|
|
||||||
Variant lastState;
|
Variant lastState;
|
||||||
timestamp_t lastStamp;
|
timestamp_t lastStamp;
|
||||||
|
|
||||||
@@ -77,26 +84,46 @@ public:
|
|||||||
const std::string& deviceType,
|
const std::string& deviceType,
|
||||||
const std::string& statusTopic,
|
const std::string& statusTopic,
|
||||||
const std::string& cmdTopic )
|
const std::string& cmdTopic )
|
||||||
: parent(parent), deviceID(deviceID), deviceType(deviceType), statusTopic(statusTopic), cmdTopic(cmdTopic) {}
|
: parent(parent), deviceID(deviceID), deviceType(deviceType),
|
||||||
|
statusTopic(statusTopic), cmdTopic(cmdTopic) {}
|
||||||
|
|
||||||
|
|
||||||
/* Public Service Implementations */
|
/* Public Service Implementations */
|
||||||
|
|
||||||
virtual const std::string& getDeviceID() noexcept override { return deviceID; }
|
virtual const std::string& getDeviceID() noexcept override {
|
||||||
virtual const std::string& getDeviceType() noexcept override { return deviceType; }
|
return deviceID;
|
||||||
virtual const std::string& getCmdTopic() noexcept override { return cmdTopic; }
|
}
|
||||||
virtual const std::string& getStatusTopic() noexcept override { return statusTopic; }
|
virtual const std::string& getDeviceType() noexcept override {
|
||||||
|
return deviceType;
|
||||||
|
}
|
||||||
|
virtual const std::string& getCmdTopic() noexcept override {
|
||||||
|
return cmdTopic;
|
||||||
|
}
|
||||||
|
virtual const std::string& getStatusTopic() noexcept override {
|
||||||
|
return statusTopic;
|
||||||
|
}
|
||||||
|
|
||||||
virtual const Variant& getCurrentState() noexcept override { return currentState; }
|
virtual const Variant& getCurrentState() noexcept override {
|
||||||
virtual const timestamp_t& getCurrentStateTimestamp() noexcept override { return currentStamp; }
|
return currentState;
|
||||||
virtual const Variant& getLastState() noexcept override { return lastState; }
|
}
|
||||||
virtual const timestamp_t& getLastStateTimestamp() noexcept override { return lastStamp; }
|
virtual const timestamp_t& getCurrentStateTimestamp() noexcept override {
|
||||||
|
return currentStamp;
|
||||||
|
}
|
||||||
|
virtual const Variant& getLastState() noexcept override {
|
||||||
|
return lastState;
|
||||||
|
}
|
||||||
|
virtual const timestamp_t& getLastStateTimestamp() noexcept override {
|
||||||
|
return lastStamp;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void sendCommand(const Variant& cmd) override;
|
virtual void sendCommand(const Variant& cmd) override;
|
||||||
|
|
||||||
/* Internal Stuff */
|
|
||||||
|
|
||||||
bool handleStatusMsg(const Variant& msg, const timestamp_t& stamp);
|
/* Internal */
|
||||||
void handleCommandMsg(const Variant& msg, const timestamp_t& stamp);
|
|
||||||
|
bool handleStatusMsg(const Variant& msg, const timestamp_t& stamp) noexcept;
|
||||||
|
|
||||||
|
void handleCommandMsg(const Variant& msg, const timestamp_t& stamp) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -107,9 +134,12 @@ public:
|
|||||||
**/
|
**/
|
||||||
class DeviceRepositoryServiceImpl
|
class DeviceRepositoryServiceImpl
|
||||||
: public virtual DeviceRepositoryService,
|
: public virtual DeviceRepositoryService,
|
||||||
public virtual implementation::ObservableService<DeviceRepositoryServiceImpl, DeviceEvent::EventType, DeviceEvent> {
|
public virtual implementation::ObservableService<DeviceRepositoryServiceImpl, DeviceEventType, DeviceEvent> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef std::map<std::string, std::shared_ptr<DeviceImpl>> devicesMap_t;
|
||||||
|
typedef std::map<std::string, std::pair<int, ros::Subscriber>> subscripedTopicMap_t;
|
||||||
|
typedef std::map<std::string, std::pair<int, ros::Publisher>> publishedTopicMap_t;
|
||||||
|
|
||||||
std::recursive_mutex serviceMutex;
|
std::recursive_mutex serviceMutex;
|
||||||
|
|
||||||
@@ -119,52 +149,68 @@ private:
|
|||||||
std::string deviceRepositoryPrefix = "/hos/devices/repository";
|
std::string deviceRepositoryPrefix = "/hos/devices/repository";
|
||||||
std::string hosStatusTopic = "/hos/status/updates";
|
std::string hosStatusTopic = "/hos/status/updates";
|
||||||
|
|
||||||
typedef std::map<std::string, std::shared_ptr<DeviceImpl>> devicesMap_t;
|
|
||||||
devicesMap_t devices;
|
devicesMap_t devices;
|
||||||
typedef std::map<std::string, std::pair<int, ros::Subscriber>> subscripedTopicMap_t;
|
|
||||||
typedef std::map<std::string, std::pair<int, ros::Publisher>> publishedTopicMap_t;
|
|
||||||
subscripedTopicMap_t subscripedTopics;
|
subscripedTopicMap_t subscripedTopics;
|
||||||
publishedTopicMap_t publishedTopics;
|
publishedTopicMap_t publishedTopics;
|
||||||
long msgSeqNumber = 0;
|
|
||||||
ros::Subscriber hosStatusSub;
|
ros::Subscriber hosStatusSub;
|
||||||
|
long msgSeqNumber = 0;
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
void init();
|
void init() noexcept;
|
||||||
|
|
||||||
void addDevice(const std::string& name);
|
void addDevice(const std::string& name);
|
||||||
|
|
||||||
void addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue);
|
void addDevice(const std::string& name, XmlRpc::XmlRpcValue& rawValue);
|
||||||
|
|
||||||
void removeDevice(const std::string& name);
|
void removeDevice(const std::string& name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
void setCoreService(service::core::CoreService* coreService);
|
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/* Public Service Implementations */
|
/* Public Service Implementations */
|
||||||
|
|
||||||
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept override;
|
virtual std::weak_ptr<Device> getDevice(const std::string& device_id) noexcept override;
|
||||||
|
|
||||||
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept override;
|
virtual std::vector<std::weak_ptr<Device>> getDevices() noexcept override;
|
||||||
virtual size_t deviceCount() noexcept override;
|
|
||||||
|
virtual size_t deviceCount() noexcept override {
|
||||||
|
return devices.size();
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::vector<std::string> getDeviceIDs() noexcept override;
|
virtual std::vector<std::string> getDeviceIDs() noexcept override;
|
||||||
|
|
||||||
|
|
||||||
/* Message Callbacks */
|
/* Message Callbacks */
|
||||||
|
|
||||||
void statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg);
|
/** ROS subscriber callback for device status messages. */
|
||||||
void cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg);
|
void statusMsgCallback(const hos_core_msgs::DeviceStatusUpdate::ConstPtr& msg) noexcept;
|
||||||
void hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg);
|
|
||||||
|
|
||||||
/* Internal Stuff */
|
/** ROS subscriber callback for device command messages. */
|
||||||
|
void cmdMsgCallback(const hos_core_msgs::DeviceCommand::ConstPtr& msg) noexcept;
|
||||||
|
|
||||||
|
/** ROS subscriber callback for hos status messages. */
|
||||||
|
void hosStatusMsgCallback(const hos_core_msgs::HosStatusUpdate::ConstPtr& msg) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
|
||||||
|
bool isInitialized() noexcept {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendDeviceCommand(DeviceImpl* device, const Variant& cmd);
|
||||||
|
|
||||||
bool isInitialized() noexcept { return initialized; }
|
|
||||||
void sendDeviceCommand(Device* device, const Variant& cmd);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace devicerepository
|
} // namespace devicerepository
|
||||||
} // namespace service
|
} // namespace service
|
||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
} // namespace hos
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_DEVICEREPOSITORY_DEVICEREPOSITORY_SERVICEIMPL_H_ */
|
|
||||||
|
|||||||
@@ -120,11 +120,14 @@ set(BUNDLE_NAME "hos_ruleengine")
|
|||||||
|
|
||||||
bundle(hos_cosgi_ruleengine
|
bundle(hos_cosgi_ruleengine
|
||||||
SOURCES
|
SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/ruleengine_serviceimpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/RuleEngineServiceImpl
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RulePackage
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RulePackageImpl
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/Rule
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RuleImpl
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RuleConditionImpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalOrCondition
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalAndCondition
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/DeviceMsgCondition
|
||||||
)
|
)
|
||||||
target_link_libraries(hos_cosgi_ruleengine
|
target_link_libraries(hos_cosgi_ruleengine
|
||||||
${catkin_LIBRARIES}
|
${catkin_LIBRARIES}
|
||||||
|
|||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Interface.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
namespace libvariant { class Variant; }
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
namespace rules {
|
||||||
|
class RulePackage;
|
||||||
|
class Rule;
|
||||||
|
namespace conditions { class RuleCondition; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public abstract COSGI interface of a rule condition factory.
|
||||||
|
*/
|
||||||
|
class RuleConditionFactory
|
||||||
|
: public virtual interface::Object {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a condition from the given json config.
|
||||||
|
*
|
||||||
|
* \param[in] parent parent rule
|
||||||
|
* \param[in] json config
|
||||||
|
* \return new rule condition
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<rules::conditions::RuleCondition> createCondition(rules::Rule* parent, const libvariant::Variant& raw) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of the rule engine service.
|
||||||
|
*/
|
||||||
|
class RuleEngineService
|
||||||
|
: public virtual interface::Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service name.
|
||||||
|
*/
|
||||||
|
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rulepackage with the given name.
|
||||||
|
*
|
||||||
|
* \param[in] name name
|
||||||
|
* \return weak reference to rule package (an expired reference is returned if the wanted rule package does not exists).
|
||||||
|
*/
|
||||||
|
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vector containing all known rulepackages.
|
||||||
|
*
|
||||||
|
* \return vector of weak references.
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of known rule packages.
|
||||||
|
*
|
||||||
|
* \return rule package count.
|
||||||
|
*/
|
||||||
|
virtual size_t getRulePackageCount() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a rule condition factory under the given type identifier.
|
||||||
|
*
|
||||||
|
* \param[in] type condition type identifier.
|
||||||
|
* \param[in] factory rule condition factory.
|
||||||
|
*/
|
||||||
|
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ruleengine
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
-94
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Rule.h
|
|
||||||
*
|
|
||||||
* Created on: 29.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
|
||||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
#include "RuleCondition.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace devicerepository {
|
|
||||||
class Device;
|
|
||||||
class DeviceEvent;
|
|
||||||
class DeviceRepositoryService;
|
|
||||||
}
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
class RulePackage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace scripting {
|
|
||||||
class ScriptingService;
|
|
||||||
class GlobalScriptContext;
|
|
||||||
class Script;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace utils {
|
|
||||||
class SchemaLoader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
class Rule {
|
|
||||||
private:
|
|
||||||
std::shared_ptr<scripting::Script> script;
|
|
||||||
std::shared_ptr<scripting::Script> exitScript;
|
|
||||||
std::shared_ptr<RuleCondition> condition;
|
|
||||||
bool enabled = false;
|
|
||||||
bool currentState = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RulePackage* const parent;
|
|
||||||
const std::string name;
|
|
||||||
|
|
||||||
Rule(RulePackage* parent, const std::string name);
|
|
||||||
static std::shared_ptr<Rule> createRule(RulePackage* parent, const std::string name, Variant raw);
|
|
||||||
|
|
||||||
bool getCurrentState() { return currentState; }
|
|
||||||
bool evaluate();
|
|
||||||
void execute(Variant lContext = Variant());
|
|
||||||
void executeExitScript(Variant lContext = Variant());
|
|
||||||
|
|
||||||
bool isEnabled() { return enabled; }
|
|
||||||
void enable();
|
|
||||||
void disable();
|
|
||||||
|
|
||||||
void conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext = Variant());
|
|
||||||
|
|
||||||
std::shared_ptr<RuleCondition> createRuleCondition(Variant raw);
|
|
||||||
|
|
||||||
utils::SchemaLoader* getHOSSchemaLoader();
|
|
||||||
devicerepository::DeviceRepositoryService* getDeviceRepository();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
|
||||||
} /* namespace service */
|
|
||||||
} /* namespace cosgi */
|
|
||||||
} /* namespace hos */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_ */
|
|
||||||
-105
@@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
* RuleCondition.h
|
|
||||||
*
|
|
||||||
* Created on: 29.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
|
||||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
class Rule;
|
|
||||||
class RuleCompositeCondition;
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
|
|
||||||
class RuleCondition {
|
|
||||||
public:
|
|
||||||
enum class Category : int { Event, State, Mixed };
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool currentState = false;
|
|
||||||
Category category;
|
|
||||||
RuleCompositeCondition* compositeParent = nullptr;
|
|
||||||
bool enabled = false;
|
|
||||||
|
|
||||||
void notifyStateChangeToParent(bool newState, Category category, Variant lcontext = Variant());
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rule* const parent;
|
|
||||||
const std::string type;
|
|
||||||
|
|
||||||
RuleCondition(Rule* parent, Category category, const std::string type) :
|
|
||||||
parent(parent), category(category), type(type) {}
|
|
||||||
virtual ~RuleCondition() {}
|
|
||||||
void setCompositeParent(RuleCompositeCondition* compositeParent) {
|
|
||||||
this->compositeParent = compositeParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Category getCategory() { return category; }
|
|
||||||
|
|
||||||
bool getCurrentState() { return currentState; }
|
|
||||||
virtual bool evaluate() { return currentState; }
|
|
||||||
|
|
||||||
bool isEnabled() { return enabled; }
|
|
||||||
virtual void enable() { enabled = true; }
|
|
||||||
virtual void disable() { enabled = false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class RuleCompositeCondition : public RuleCondition {
|
|
||||||
protected:
|
|
||||||
std::vector<std::shared_ptr<RuleCondition>> children;
|
|
||||||
public:
|
|
||||||
RuleCompositeCondition(Rule* parent, Category category, std::string type) :
|
|
||||||
RuleCondition(parent, category, type) {}
|
|
||||||
|
|
||||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) = 0;
|
|
||||||
|
|
||||||
virtual void addChild(std::shared_ptr<RuleCondition> child) {
|
|
||||||
if (child) {
|
|
||||||
child->setCompositeParent(this);
|
|
||||||
children.push_back(child);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual void enable() {
|
|
||||||
if (!enabled) {
|
|
||||||
for (auto c : children) {
|
|
||||||
c->enable();
|
|
||||||
}
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual void disable() {
|
|
||||||
if (enabled) {
|
|
||||||
for (auto c : children) {
|
|
||||||
c->disable();
|
|
||||||
}
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
|
||||||
} /* namespace service */
|
|
||||||
} /* namespace cosgi */
|
|
||||||
} /* namespace hos */
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_ */
|
|
||||||
-49
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* hos_ruleengine_service.h
|
|
||||||
*
|
|
||||||
* Created on: 26.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
|
||||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/Interface.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
|
|
||||||
namespace rule {
|
|
||||||
class RuleCondition;
|
|
||||||
class Rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RuleConditionFactory : public virtual interface::Object {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class RuleEngineService : public virtual interface::Service {
|
|
||||||
public:
|
|
||||||
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
|
||||||
|
|
||||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ruleengine
|
|
||||||
} // namespace service
|
|
||||||
} // namespace cosgi
|
|
||||||
} // namespace hos
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_ */
|
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Interface.h>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
namespace devicerepository { class DeviceRepositoryService; }
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace conditions {
|
||||||
|
class RuleCondition;
|
||||||
|
enum class ConditionTriggerType : int;
|
||||||
|
}
|
||||||
|
class RulePackage;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of a rule.
|
||||||
|
*/
|
||||||
|
class Rule
|
||||||
|
: public virtual interface::Object {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the parent rule package.
|
||||||
|
*
|
||||||
|
* \return rule package.
|
||||||
|
*/
|
||||||
|
virtual RulePackage* getParent() noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the rule.
|
||||||
|
*
|
||||||
|
* \return name.
|
||||||
|
*/
|
||||||
|
virtual const std::string& getName() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the rule is currently active.
|
||||||
|
*
|
||||||
|
* Only conditions of trigger type "state" can activate a rule.
|
||||||
|
*
|
||||||
|
* \return whether rule is active.
|
||||||
|
*/
|
||||||
|
virtual bool isActive() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates the conditions of the rule and may execute associated scripts.
|
||||||
|
*
|
||||||
|
* Only active conditions of trigger type "state" can return true here.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \return evaluation result.
|
||||||
|
*/
|
||||||
|
virtual bool evaluate() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the associated script.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param[in] local context.
|
||||||
|
*/
|
||||||
|
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the associated exit script.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param[in] local context.
|
||||||
|
*/
|
||||||
|
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this rule is enabled.
|
||||||
|
*
|
||||||
|
* \return enabled
|
||||||
|
*/
|
||||||
|
virtual bool isEnabled() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable this rule package.
|
||||||
|
*
|
||||||
|
* \param[in] enabled.
|
||||||
|
*/
|
||||||
|
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Interface for third-party conditions. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a new condition based on the given json config.
|
||||||
|
*
|
||||||
|
* \param[in] json config.
|
||||||
|
* \return new rule condition.
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<conditions::RuleCondition> createRuleCondition(const libvariant::Variant& raw) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that one of the conditions of the rule changed state.
|
||||||
|
*
|
||||||
|
* \param[in] newState new state.
|
||||||
|
* \param[in] trigger trigger type.
|
||||||
|
* \param[in] lcontext local context that should be passed to script.
|
||||||
|
*/
|
||||||
|
virtual void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& trigger,
|
||||||
|
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the device repository service.
|
||||||
|
*
|
||||||
|
* \return device repository service.
|
||||||
|
*/
|
||||||
|
virtual devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Interface.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace hos { namespace cosgi { namespace service {
|
||||||
|
namespace scripting { class ScriptingService; }
|
||||||
|
namespace scripting { class GlobalScriptContext; }
|
||||||
|
} } }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class RuleEngineService;
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
|
namespace rules {
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Rule;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of a rule package.
|
||||||
|
*/
|
||||||
|
class RulePackage
|
||||||
|
: public virtual interface::Object {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the rule engine service.
|
||||||
|
*
|
||||||
|
* \return rule engine service.
|
||||||
|
*/
|
||||||
|
virtual service::ruleengine::RuleEngineService* getParent() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the rule package.
|
||||||
|
*
|
||||||
|
* \return name.
|
||||||
|
*/
|
||||||
|
virtual const std::string& getName() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an identifier indicating the scripting language.
|
||||||
|
*
|
||||||
|
* \return scripting language identifier.
|
||||||
|
*/
|
||||||
|
virtual const std::string& getLanguage() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rule with the given name.
|
||||||
|
*
|
||||||
|
* \param[in] name rule name.
|
||||||
|
* \return weak reference to rule (expired reference in case of rule not found).
|
||||||
|
*/
|
||||||
|
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all rules contained within the rule package
|
||||||
|
*
|
||||||
|
* \return vector of weak references.
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of contained rules.
|
||||||
|
*
|
||||||
|
* \return rule count.
|
||||||
|
*/
|
||||||
|
virtual size_t getRuleCount() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this rule package is enabled.
|
||||||
|
*
|
||||||
|
* \return enabled
|
||||||
|
*/
|
||||||
|
virtual bool isEnabled() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable this rule package.
|
||||||
|
*
|
||||||
|
* \param[in] enabled.
|
||||||
|
*/
|
||||||
|
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the associated scripting service.
|
||||||
|
*
|
||||||
|
* \return scripting service.
|
||||||
|
*/
|
||||||
|
virtual service::scripting::ScriptingService* getScriptingService() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the associated global script context.
|
||||||
|
*
|
||||||
|
* \return global script context.
|
||||||
|
*/
|
||||||
|
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+163
@@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Interface.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
class Rule;
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
class RuleCompositeCondition;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Condition trigger type.
|
||||||
|
*
|
||||||
|
* Conditions can have two different trigger types:
|
||||||
|
* - Event trigger: Conditions are triggered by events happening.
|
||||||
|
* - State trigger: Condition are triggered by device state.
|
||||||
|
*
|
||||||
|
* "Both" indicates that an condition has both trigger types.
|
||||||
|
**/
|
||||||
|
enum class ConditionTriggerType : int {
|
||||||
|
Event = 1,
|
||||||
|
State = 2,
|
||||||
|
Both = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of a rule condition.
|
||||||
|
*/
|
||||||
|
class RuleCondition
|
||||||
|
: public virtual interface::Object {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the condition.
|
||||||
|
*
|
||||||
|
* \return condition type.
|
||||||
|
*/
|
||||||
|
virtual const std::string& getType() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the trigger type of the condition.
|
||||||
|
*
|
||||||
|
* \return trigger type.
|
||||||
|
*/
|
||||||
|
virtual ConditionTriggerType getTriggerType() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current state of the condition.
|
||||||
|
*
|
||||||
|
* This function returns a cached value.
|
||||||
|
*
|
||||||
|
* \return current state.
|
||||||
|
*/
|
||||||
|
virtual bool getCurrentState() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates the condition and returns the result.
|
||||||
|
*
|
||||||
|
* \return evaluation result.
|
||||||
|
*/
|
||||||
|
virtual bool evaluate() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the parent rule.
|
||||||
|
*
|
||||||
|
* \return parent rule.
|
||||||
|
*/
|
||||||
|
virtual rules::Rule* getParent() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this rule condition is enabled.
|
||||||
|
*
|
||||||
|
* \return enabled.
|
||||||
|
*/
|
||||||
|
virtual bool isEnabled() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable this rule condition.
|
||||||
|
*
|
||||||
|
* \param[in] enabled.
|
||||||
|
*/
|
||||||
|
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Interface for third-party conditions. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the composite condition this condition is contained within.
|
||||||
|
*
|
||||||
|
* \param[in] parent composite condition.
|
||||||
|
*/
|
||||||
|
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of a composite condition.
|
||||||
|
*/
|
||||||
|
class RuleCompositeCondition
|
||||||
|
: public virtual RuleCondition {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/* Interface for third-party conditions. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a contained condition has changed its state.
|
||||||
|
*
|
||||||
|
* \param[in] child condition whose state has changed.
|
||||||
|
* \param[in] newState new state.
|
||||||
|
* \param[in] trigger trigger type.
|
||||||
|
* \param[in] lcontext local context that should be passed to the script.
|
||||||
|
*/
|
||||||
|
virtual void childStateChanged( RuleCondition* child,
|
||||||
|
bool newState,
|
||||||
|
ConditionTriggerType trigger,
|
||||||
|
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new condition.
|
||||||
|
*
|
||||||
|
* \param[in] child child condition.
|
||||||
|
*/
|
||||||
|
virtual void addChild(std::shared_ptr<RuleCondition> child) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include "RuleCondition.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for condition implementations.
|
||||||
|
*/
|
||||||
|
class RuleConditionImpl
|
||||||
|
: public virtual RuleCondition {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
rules::Rule* parent;
|
||||||
|
ConditionTriggerType triggerType;
|
||||||
|
std::string type;
|
||||||
|
|
||||||
|
bool currentState = false;
|
||||||
|
RuleCompositeCondition* compositeParent = nullptr;
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
void notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext = libvariant::Variant());
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RuleConditionImpl(rules::Rule* parent, ConditionTriggerType triggerType, const std::string& type) :
|
||||||
|
parent(parent), triggerType(triggerType), type(type) {}
|
||||||
|
|
||||||
|
virtual rules::Rule* getParent() noexcept override {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept override {
|
||||||
|
this->compositeParent = compositeParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const std::string& getType() noexcept override {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ConditionTriggerType getTriggerType() noexcept override {
|
||||||
|
return triggerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool getCurrentState() noexcept override {
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool evaluate() noexcept override {
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isEnabled() noexcept override {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setEnabled(bool enabled) noexcept override {
|
||||||
|
this->enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for composite condition implementations.
|
||||||
|
*/
|
||||||
|
class RuleCompositeConditionImpl
|
||||||
|
: public virtual RuleCompositeCondition,
|
||||||
|
public RuleConditionImpl {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::shared_ptr<RuleCondition>> children;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RuleCompositeConditionImpl(Rule* parent, ConditionTriggerType category, std::string type) :
|
||||||
|
RuleConditionImpl(parent, category, type) {}
|
||||||
|
|
||||||
|
virtual void childStateChanged( RuleCondition* child,
|
||||||
|
bool newState,
|
||||||
|
ConditionTriggerType category,
|
||||||
|
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept override = 0;
|
||||||
|
|
||||||
|
virtual void addChild(std::shared_ptr<RuleCondition> child) override {
|
||||||
|
if (child) {
|
||||||
|
child->setCompositeParent(this);
|
||||||
|
children.push_back(child);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void setEnabled(bool enabled) noexcept override {
|
||||||
|
if (this->enabled != enabled) {
|
||||||
|
for (auto c : children) {
|
||||||
|
c->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
this->enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+1
-1
@@ -21,7 +21,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
#include "hos/cosgi/service/ruleengine/ruleengine_serviceimpl.h"
|
#include "hos/cosgi/service/ruleengine/RuleEngineServiceImpl.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
+29
-14
@@ -5,7 +5,6 @@
|
|||||||
* Author: matzman
|
* Author: matzman
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ruleengine_serviceimpl.h"
|
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -16,8 +15,12 @@
|
|||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
#include <Variant/Variant.h>
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
#include "rule/RulePackage.h"
|
#include "RuleEngineServiceImpl.h"
|
||||||
#include "rule/RuleConditionImpl.h"
|
|
||||||
|
#include "rules/conditions/LogicalAndCondition.h"
|
||||||
|
#include "rules/conditions/LogicalOrCondition.h"
|
||||||
|
#include "rules/conditions/DeviceMsgCondition.h"
|
||||||
|
#include "rules/RulePackageImpl.h"
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
namespace hos {
|
||||||
@@ -62,11 +65,11 @@ void RuleEngineServiceImpl::init() {
|
|||||||
XmlRpc::XmlRpcValue rawValue;
|
XmlRpc::XmlRpcValue rawValue;
|
||||||
nodehandle->getParam(ruleEnginePrefix, rawValue);
|
nodehandle->getParam(ruleEnginePrefix, rawValue);
|
||||||
schemaLoader.reset(new utils::SchemaLoader());
|
schemaLoader.reset(new utils::SchemaLoader());
|
||||||
registerRuleConditionFactory("logical_or", std::make_shared<rule::LogicalOrConditionFactory>());
|
registerRuleConditionFactory("logical_or", std::make_shared<rules::conditions::LogicalOrConditionFactory>());
|
||||||
registerRuleConditionFactory("logical_and", std::make_shared<rule::LogicalAndConditionFactory>());
|
registerRuleConditionFactory("logical_and", std::make_shared<rules::conditions::LogicalAndConditionFactory>());
|
||||||
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rule::DeviceStatusMsgConditionFactory>());
|
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rules::conditions::DeviceStatusMsgConditionFactory>());
|
||||||
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rule::DeviceCommandMsgConditionFactory>());
|
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rules::conditions::DeviceCommandMsgConditionFactory>());
|
||||||
registerRuleConditionFactory("devicestatechange", std::make_shared<rule::DeviceStateChangeConditionFactory>());
|
registerRuleConditionFactory("devicestatechange", std::make_shared<rules::conditions::DeviceStateChangeConditionFactory>());
|
||||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||||
for (auto pkg : rawValue) {
|
for (auto pkg : rawValue) {
|
||||||
std::string pname = pkg.first;
|
std::string pname = pkg.first;
|
||||||
@@ -96,11 +99,11 @@ void RuleEngineServiceImpl::addRulePkg(std::string name, std::string rawValue) {
|
|||||||
Variant m = Deserialize(rawValue, SERIALIZE_JSON);
|
Variant m = Deserialize(rawValue, SERIALIZE_JSON);
|
||||||
SchemaResult sr = SchemaValidate(s, m, schemaLoader.get());
|
SchemaResult sr = SchemaValidate(s, m, schemaLoader.get());
|
||||||
if (!sr.Error()) {
|
if (!sr.Error()) {
|
||||||
std::shared_ptr<rule::RulePackage> pkg = rule::RulePackage::createRulePackage(this, name, m);
|
std::shared_ptr<rules::RulePackageImpl> pkg = rules::RulePackageImpl::createRulePackage(this, name, m);
|
||||||
if (pkg) {
|
if (pkg) {
|
||||||
if (pkg->getScriptingService()) {
|
if (pkg->getScriptingService()) {
|
||||||
rulePkgs.insert({name, pkg});
|
rulePkgs.insert({name, pkg});
|
||||||
pkg->enable();
|
pkg->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
noExecRulePkgs.insert({name, pkg});
|
noExecRulePkgs.insert({name, pkg});
|
||||||
std::cout << "No execution service found for rule package \"" << name << "\"" << std::endl;
|
std::cout << "No execution service found for rule package \"" << name << "\"" << std::endl;
|
||||||
@@ -142,17 +145,17 @@ scripting::ScriptingService* RuleEngineServiceImpl::getExecutionBackend(std::str
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RuleEngineServiceImpl::registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) {
|
void RuleEngineServiceImpl::registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept {
|
||||||
condFactories.insert({type, factory});
|
condFactories.insert({type, factory});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) {
|
std::weak_ptr<rules::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) noexcept {
|
||||||
std::shared_ptr<rule::RulePackage> retval;
|
std::weak_ptr<rules::RulePackage> retval;
|
||||||
try {
|
try {
|
||||||
retval = rulePkgs.at(name);
|
retval = rulePkgs.at(name);
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
if (!retval) {
|
if (retval.expired()) {
|
||||||
try {
|
try {
|
||||||
retval = noExecRulePkgs.at(name);
|
retval = noExecRulePkgs.at(name);
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
@@ -160,6 +163,18 @@ std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const s
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::weak_ptr<rules::RulePackage>> RuleEngineServiceImpl::getRulePackages() noexcept {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t RuleEngineServiceImpl::getRulePackageCount() noexcept {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ruleengine
|
} // namespace ruleengine
|
||||||
} // namespace service
|
} // namespace service
|
||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
+33
-24
@@ -1,12 +1,7 @@
|
|||||||
/*
|
|
||||||
* hos_ruleengine_service_impl.h
|
|
||||||
*
|
|
||||||
* Created on: 26.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
#pragma once
|
||||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -15,10 +10,10 @@
|
|||||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||||
#include <hos/utils/SchemaLoader.h>
|
#include <hos/utils/SchemaLoader.h>
|
||||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
|
||||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
#include <hos/cosgi/service/Implementation.h>
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||||
|
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -45,18 +40,19 @@ namespace hos {
|
|||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace ruleengine {
|
namespace ruleengine {
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
class RulePackage;
|
namespace rules {
|
||||||
|
class RulePackageImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RuleEngineServiceImpl;
|
|
||||||
class RuleEngineServiceImpl :
|
class RuleEngineServiceImpl :
|
||||||
public virtual RuleEngineService,
|
public virtual RuleEngineService,
|
||||||
public virtual implementation::Service<RuleEngineServiceImpl> {
|
public virtual implementation::Service<RuleEngineServiceImpl> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<std::string, std::shared_ptr<rule::RulePackage>> rulePkgMap_t;
|
typedef std::map<std::string, std::shared_ptr<rules::RulePackageImpl>> rulePkgMap_t;
|
||||||
typedef std::map<std::string, scripting::ScriptingService*> execServiceMap_t;
|
typedef std::map<std::string, scripting::ScriptingService*> execServiceMap_t;
|
||||||
typedef std::map<std::string, std::shared_ptr<RuleConditionFactory>> condFactoryMap_t;
|
typedef std::map<std::string, std::shared_ptr<RuleConditionFactory>> condFactoryMap_t;
|
||||||
|
|
||||||
@@ -82,39 +78,52 @@ private:
|
|||||||
void init();
|
void init();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
void setCoreService(service::core::CoreService* coreService);
|
void setCoreService(service::core::CoreService* coreService);
|
||||||
|
|
||||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
||||||
|
|
||||||
|
|
||||||
/* Public Service Implementations */
|
/* Public Service Implementations */
|
||||||
|
|
||||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) override;
|
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept override;
|
||||||
|
|
||||||
|
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept override;
|
||||||
|
|
||||||
|
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual size_t getRulePackageCount() noexcept override;
|
||||||
|
|
||||||
|
|
||||||
/* Internal Stuff */
|
/* Internal Stuff */
|
||||||
|
|
||||||
bool isInitialized() { return initialized; }
|
bool isInitialized() { return initialized; }
|
||||||
|
|
||||||
void addExecutionBackend(scripting::ScriptingService* service);
|
void addExecutionBackend(scripting::ScriptingService* service);
|
||||||
|
|
||||||
scripting::ScriptingService* getExecutionBackend(std::string language);
|
scripting::ScriptingService* getExecutionBackend(std::string language);
|
||||||
|
|
||||||
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) { return condFactories[type]; }
|
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) {
|
||||||
|
return condFactories[type];
|
||||||
|
}
|
||||||
|
|
||||||
utils::SchemaLoader* getHOSSchemaLoader() { return schemaLoader.get(); }
|
utils::SchemaLoader* getHOSSchemaLoader() {
|
||||||
|
return schemaLoader.get();
|
||||||
|
}
|
||||||
|
|
||||||
devicerepository::DeviceRepositoryService* getDeviceRepository() { return repoService; }
|
devicerepository::DeviceRepositoryService* getDeviceRepository() {
|
||||||
|
return repoService;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<rule::RulePackage> getRulePackage(const std::string& name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ruleengine
|
} // namespace ruleengine
|
||||||
} // namespace service
|
} // namespace service
|
||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
} // namespace hos
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_ */
|
|
||||||
@@ -1,432 +0,0 @@
|
|||||||
/*
|
|
||||||
* RuleCondition.cpp
|
|
||||||
*
|
|
||||||
* Created on: 29.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RuleConditionImpl.h"
|
|
||||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
|
||||||
#include <ros/ros.h>
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RuleCondition> LogicalOrConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
|
||||||
std::shared_ptr<rule::LogicalOrCondition> retval;
|
|
||||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
|
||||||
retval = std::make_shared<rule::LogicalOrCondition>(parent);
|
|
||||||
for (auto c : raw["conditions"].AsList()) {
|
|
||||||
auto cond = parent->createRuleCondition(c);
|
|
||||||
if (cond) {
|
|
||||||
retval->addChild(cond);
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Could not create condition.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
|
||||||
}
|
|
||||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RuleCondition> LogicalAndConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
|
||||||
std::shared_ptr<rule::LogicalAndCondition> retval;
|
|
||||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
|
||||||
retval = std::make_shared<rule::LogicalAndCondition>(parent);
|
|
||||||
for (auto c : raw["conditions"].AsList()) {
|
|
||||||
auto cond = parent->createRuleCondition(c);
|
|
||||||
if (cond) {
|
|
||||||
retval->addChild(cond);
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Could not create condition.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
|
||||||
}
|
|
||||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RuleCondition::notifyStateChangeToParent(bool newState, Category category, Variant lcontext) {
|
|
||||||
if (compositeParent) {
|
|
||||||
compositeParent->childStateChanged(this, newState, category, lcontext);
|
|
||||||
} else {
|
|
||||||
parent->conditionStateChanged(newState, category, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
|
||||||
if (child->getCategory() == Category::Event) {
|
|
||||||
eventChildrenCount++;
|
|
||||||
} else if (child->getCategory() == Category::State) {
|
|
||||||
stateChildrenCount++;
|
|
||||||
} else {
|
|
||||||
mixedChildrenCount++;
|
|
||||||
}
|
|
||||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
|
||||||
category = Category::Mixed;
|
|
||||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
|
||||||
category = Category::Event;
|
|
||||||
} else {
|
|
||||||
category = Category::State;
|
|
||||||
}
|
|
||||||
RuleCompositeCondition::addChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
|
||||||
if (newState && category == Category::Event && !currentState) {
|
|
||||||
notifyStateChangeToParent(true, category, lcontext);
|
|
||||||
} else if (category == Category::State) {
|
|
||||||
if (newState) {
|
|
||||||
trueChildrenCount++;
|
|
||||||
if (!currentState) {
|
|
||||||
currentState = true;
|
|
||||||
notifyStateChangeToParent(true, category, lcontext);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trueChildrenCount--;
|
|
||||||
if (currentState && trueChildrenCount <= 0) {
|
|
||||||
currentState = false;
|
|
||||||
notifyStateChangeToParent(false, category, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool LogicalOrCondition::evaluate() {
|
|
||||||
// Event conditions always evaluate to false
|
|
||||||
if (category == Category::Event) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
trueChildrenCount = 0;
|
|
||||||
for (auto c : children) {
|
|
||||||
if (c->evaluate()) {
|
|
||||||
trueChildrenCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentState = trueChildrenCount > 0;
|
|
||||||
return currentState;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
|
||||||
if (child->getCategory() == Category::Event) {
|
|
||||||
if (eventChildrenCount > 0) {
|
|
||||||
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
|
||||||
}
|
|
||||||
eventChildrenCount++;
|
|
||||||
} else if (child->getCategory() == Category::State) {
|
|
||||||
stateChildrenCount++;
|
|
||||||
} else {
|
|
||||||
mixedChildrenCount++;
|
|
||||||
}
|
|
||||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
|
||||||
category = Category::Mixed;
|
|
||||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
|
||||||
category = Category::Event;
|
|
||||||
} else {
|
|
||||||
category = Category::State;
|
|
||||||
}
|
|
||||||
RuleCompositeCondition::addChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
|
||||||
if (newState && category == Category::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
|
||||||
notifyStateChangeToParent(true, category);
|
|
||||||
} else if (category == Category::State) {
|
|
||||||
if (newState) {
|
|
||||||
trueChildrenCount++;
|
|
||||||
if (!currentState && trueChildrenCount >= children.size()) {
|
|
||||||
currentState = true;
|
|
||||||
notifyStateChangeToParent(true, category, lcontext);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trueChildrenCount--;
|
|
||||||
if (currentState) {
|
|
||||||
currentState = false;
|
|
||||||
notifyStateChangeToParent(false, category, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool LogicalAndCondition::evaluate() {
|
|
||||||
// Event conditions always evaluate to false
|
|
||||||
if (category == Category::Event) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
trueChildrenCount = 0;
|
|
||||||
for (auto c : children) {
|
|
||||||
if (c->evaluate()) {
|
|
||||||
trueChildrenCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentState = trueChildrenCount == children.size();
|
|
||||||
return currentState;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
|
||||||
switch (key) {
|
|
||||||
case devicerepository::DeviceEvent::EventType::DEVICE_ADDED:
|
|
||||||
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
|
||||||
ROS_INFO_STREAM("Rule " << parent->name << ": Device " << deviceID << " appeared.");
|
|
||||||
device = e->device;
|
|
||||||
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
|
||||||
_registerAsListener();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEvent::EventType::DEVICE_REMOVED:
|
|
||||||
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
|
||||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Device " << deviceID << " disappeared.");
|
|
||||||
device->deleteObserver(this);
|
|
||||||
device = nullptr;
|
|
||||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceMsgCondition::enable() {
|
|
||||||
auto repoService = parent->getDeviceRepository();
|
|
||||||
auto device = repoService->getDevice(deviceID);
|
|
||||||
if (!device.expired()) {
|
|
||||||
this->device = device.lock().get();
|
|
||||||
_registerAsListener();
|
|
||||||
} else {
|
|
||||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Could not find device " << deviceID);
|
|
||||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceMsgCondition::disable() {
|
|
||||||
if (device) {
|
|
||||||
device->deleteObserver(this);
|
|
||||||
device = nullptr;
|
|
||||||
}
|
|
||||||
parent->getDeviceRepository()->deleteObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceMsgCondition::_registerAsListener() {
|
|
||||||
if (device) {
|
|
||||||
for (auto k : _listenerKeys) {
|
|
||||||
device->addObserver(k, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
|
||||||
std::shared_ptr<rule::DeviceStatusMsgCondition> retval;
|
|
||||||
std::string deviceID;
|
|
||||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
|
||||||
deviceID = raw["deviceid"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
|
||||||
}
|
|
||||||
std::string msgPointer;
|
|
||||||
if (raw.HasPath("msgpointer")) {
|
|
||||||
if (raw["msgpointer"].IsString()) {
|
|
||||||
msgPointer = raw["msgpointer"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Variant msgValue;
|
|
||||||
if (raw.HasPath("msgvalue")) {
|
|
||||||
msgValue = raw["msgvalue"];
|
|
||||||
}
|
|
||||||
retval = std::make_shared<rule::DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
|
||||||
switch (e->eventType) {
|
|
||||||
case devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED:
|
|
||||||
if (device && device == e->device) {
|
|
||||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
|
||||||
bool notify = true;
|
|
||||||
Variant value;
|
|
||||||
if (msgPointer.empty()) {
|
|
||||||
value = e2->statusMsg;
|
|
||||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
|
||||||
value = e2->statusMsg.GetPath(msgPointer);
|
|
||||||
} else {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
if (notify && !msgValue.IsNull()) {
|
|
||||||
if (msgValue != value) {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (notify) {
|
|
||||||
Variant lcontext;
|
|
||||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
|
||||||
lcontext["event_type"] = Variant("statusmsg");
|
|
||||||
lcontext["event_msg"] = e2->statusMsg;
|
|
||||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
|
||||||
std::shared_ptr<rule::DeviceCommandMsgCondition> retval;
|
|
||||||
std::string deviceID;
|
|
||||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
|
||||||
deviceID = raw["deviceid"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
|
||||||
}
|
|
||||||
std::string msgPointer;
|
|
||||||
if (raw.HasPath("msgpointer")) {
|
|
||||||
if (raw["msgpointer"].IsString()) {
|
|
||||||
msgPointer = raw["msgpointer"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Variant msgValue;
|
|
||||||
if (raw.HasPath("msgvalue")) {
|
|
||||||
msgValue = raw["msgvalue"];
|
|
||||||
}
|
|
||||||
retval = std::make_shared<rule::DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
|
||||||
switch (e->eventType) {
|
|
||||||
case devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED:
|
|
||||||
if (device && device == e->device) {
|
|
||||||
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
|
||||||
bool notify = true;
|
|
||||||
Variant value;
|
|
||||||
if (msgPointer.empty()) {
|
|
||||||
value = e2->cmdMsg;
|
|
||||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
|
||||||
value = e2->cmdMsg.GetPath(msgPointer);
|
|
||||||
} else {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
if (notify && !msgValue.IsNull()) {
|
|
||||||
if (msgValue != value) {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (notify) {
|
|
||||||
Variant lcontext;
|
|
||||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
|
||||||
lcontext["event_type"] = Variant("commandmsg");
|
|
||||||
lcontext["event_msg"] = e2->cmdMsg;
|
|
||||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<rule::RuleCondition> DeviceStateChangeConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
|
||||||
std::shared_ptr<rule::DeviceStateChangeCondition> retval;
|
|
||||||
std::string deviceID;
|
|
||||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
|
||||||
deviceID = raw["deviceid"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
|
||||||
}
|
|
||||||
std::string statePointer;
|
|
||||||
if (raw.HasPath("msgpointer")) {
|
|
||||||
if (raw["msgpointer"].IsString()) {
|
|
||||||
statePointer = raw["msgpointer"].AsString();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Variant fromValue;
|
|
||||||
if (raw.HasPath("fromvalue")) {
|
|
||||||
fromValue = raw["fromvalue"];
|
|
||||||
}
|
|
||||||
Variant toValue;
|
|
||||||
if (raw.HasPath("tovalue")) {
|
|
||||||
toValue = raw["tovalue"];
|
|
||||||
}
|
|
||||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
|
||||||
switch (e->eventType) {
|
|
||||||
case devicerepository::DeviceEvent::EventType::STATE_CHANGED:
|
|
||||||
if (device && device == e->device) {
|
|
||||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
|
||||||
bool notify = true;
|
|
||||||
Variant current, last;
|
|
||||||
if (msgPointer.empty()) {
|
|
||||||
current = device->getCurrentState();
|
|
||||||
last = device->getLastState();
|
|
||||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
|
||||||
current = device->getCurrentState().GetPath(msgPointer);
|
|
||||||
last = device->getLastState().GetPath(msgPointer);
|
|
||||||
} else {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
if (notify) {
|
|
||||||
if (current == last) {
|
|
||||||
notify = false;
|
|
||||||
} else if (!fromValue.IsNull() && fromValue != last) {
|
|
||||||
notify = false;
|
|
||||||
} else if (!msgValue.IsNull() && msgValue != current) {
|
|
||||||
notify = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (notify) {
|
|
||||||
Variant lcontext;
|
|
||||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
|
||||||
lcontext["event_type"] = Variant("statechange");
|
|
||||||
lcontext["event_msg"] = e2->statusMsg;
|
|
||||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
|
||||||
} /* namespace service */
|
|
||||||
} /* namespace cosgi */
|
|
||||||
} /* namespace hos */
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* RuleConditionImpl.h
|
|
||||||
*
|
|
||||||
* Created on: 11.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
|
||||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
|
||||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
|
|
||||||
// Service Namespace
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
|
|
||||||
class LogicalOrCondition : public RuleCompositeCondition {
|
|
||||||
protected:
|
|
||||||
unsigned eventChildrenCount = 0;
|
|
||||||
unsigned stateChildrenCount = 0;
|
|
||||||
unsigned mixedChildrenCount = 0;
|
|
||||||
unsigned trueChildrenCount = 0;
|
|
||||||
public:
|
|
||||||
LogicalOrCondition(Rule* parent) :
|
|
||||||
RuleCompositeCondition(parent, Category::Mixed, "logical_or") {}
|
|
||||||
|
|
||||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
|
||||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
|
||||||
virtual bool evaluate() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LogicalOrConditionFactory : public virtual RuleConditionFactory {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class LogicalAndCondition : public RuleCompositeCondition {
|
|
||||||
protected:
|
|
||||||
unsigned eventChildrenCount = 0;
|
|
||||||
unsigned stateChildrenCount = 0;
|
|
||||||
unsigned mixedChildrenCount = 0;
|
|
||||||
unsigned trueChildrenCount = 0;
|
|
||||||
public:
|
|
||||||
LogicalAndCondition(Rule* parent) :
|
|
||||||
RuleCompositeCondition(parent, Category::Mixed, "logical_and") {}
|
|
||||||
|
|
||||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
|
||||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
|
||||||
virtual bool evaluate() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LogicalAndConditionFactory : public virtual RuleConditionFactory {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceMsgCondition : public RuleCondition, public virtual interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent> {
|
|
||||||
protected:
|
|
||||||
const std::string deviceID;
|
|
||||||
devicerepository::Device* device = nullptr;
|
|
||||||
const std::string msgPointer;
|
|
||||||
const Variant msgValue;
|
|
||||||
std::set<devicerepository::DeviceEvent::EventType> _listenerKeys;
|
|
||||||
|
|
||||||
virtual void _registerAsListener();
|
|
||||||
|
|
||||||
public:
|
|
||||||
DeviceMsgCondition(Rule* parent, Category category, std::string type, const std::string deviceID, const std::string msgPointer, const Variant msgValue, std::set<devicerepository::DeviceEvent::EventType> _listenerKeys) :
|
|
||||||
RuleCondition(parent, category, type), deviceID(deviceID), msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
virtual void enable() override;
|
|
||||||
virtual void disable() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceStatusMsgCondition : public DeviceMsgCondition {
|
|
||||||
public:
|
|
||||||
DeviceStatusMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
|
||||||
DeviceMsgCondition(parent, Category::Event, "devicestatusmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED}) {}
|
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceStatusMsgConditionFactory : public virtual RuleConditionFactory {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceCommandMsgCondition : public DeviceMsgCondition {
|
|
||||||
public:
|
|
||||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
|
||||||
DeviceMsgCondition(parent, Category::Event, "devicecommandmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED}) {}
|
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceCommandMsgConditionFactory : public virtual RuleConditionFactory {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceStateChangeCondition : public DeviceMsgCondition {
|
|
||||||
protected:
|
|
||||||
const Variant fromValue;
|
|
||||||
public:
|
|
||||||
DeviceStateChangeCondition(Rule* parent, const std::string deviceID, const std::string statePointer, const Variant fromValue, const Variant toValue) :
|
|
||||||
DeviceMsgCondition(parent, Category::Event, "devicestatechange", deviceID, statePointer, toValue, {devicerepository::DeviceEvent::EventType::STATE_CHANGED}), fromValue(fromValue) {}
|
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceStateChangeConditionFactory : public virtual RuleConditionFactory {
|
|
||||||
public:
|
|
||||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
|
||||||
} /* namespace service */
|
|
||||||
} /* namespace cosgi */
|
|
||||||
} /* namespace hos */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_ */
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* RulePackage.h
|
|
||||||
*
|
|
||||||
* Created on: 29.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
|
||||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
class RuleEngineServiceImpl;
|
|
||||||
class RuleConditionFactory;
|
|
||||||
namespace rule {
|
|
||||||
class Rule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace scripting {
|
|
||||||
class GlobalScriptContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace ruleengine {
|
|
||||||
namespace rule {
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
class RulePackage {
|
|
||||||
private:
|
|
||||||
typedef std::map<std::string, std::shared_ptr<Rule>> ruleMap_t;
|
|
||||||
|
|
||||||
service::scripting::ScriptingService* executionService = nullptr;
|
|
||||||
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
|
||||||
ruleMap_t rules;
|
|
||||||
Variant rawValue;
|
|
||||||
bool enabled = false;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
service::ruleengine::RuleEngineServiceImpl* const parent;
|
|
||||||
const std::string name;
|
|
||||||
const std::string language;
|
|
||||||
|
|
||||||
static std::shared_ptr<RulePackage> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
|
||||||
RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
|
||||||
virtual ~RulePackage();
|
|
||||||
|
|
||||||
std::shared_ptr<Rule> getRule(const std::string& name);
|
|
||||||
size_t getRules(std::vector<std::shared_ptr<Rule>>& rules);
|
|
||||||
|
|
||||||
bool isEnabled() { return enabled; }
|
|
||||||
void enable();
|
|
||||||
void disable();
|
|
||||||
|
|
||||||
service::scripting::ScriptingService* getScriptingService() { return executionService; }
|
|
||||||
std::shared_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() { return globalContext; }
|
|
||||||
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
|
||||||
} /* namespace service */
|
|
||||||
} /* namespace cosgi */
|
|
||||||
} /* namespace hos */
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_ */
|
|
||||||
+36
-48
@@ -6,39 +6,36 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
#include "../rules/RuleImpl.h"
|
||||||
|
|
||||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include "RulePackage.h"
|
|
||||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||||
|
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||||
#include <hos/utils/SchemaLoader.h>
|
#include <hos/utils/SchemaLoader.h>
|
||||||
#include "../ruleengine_serviceimpl.h"
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
#include "../rules/RulePackageImpl.h"
|
||||||
|
|
||||||
|
#include "../RuleEngineServiceImpl.h"
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace ruleengine {
|
namespace ruleengine {
|
||||||
namespace rule {
|
namespace rules {
|
||||||
|
|
||||||
|
|
||||||
Rule::Rule(RulePackage* parent, std::string name)
|
RuleImpl::RuleImpl(RulePackageImpl* parent, std::string name)
|
||||||
: parent(parent), name(name) {}
|
: parent(parent), name(name) {}
|
||||||
|
|
||||||
|
std::shared_ptr<conditions::RuleCondition> RuleImpl::createRuleCondition(const Variant& condition) {
|
||||||
utils::SchemaLoader* Rule::getHOSSchemaLoader() {
|
std::shared_ptr<conditions::RuleCondition> retval;
|
||||||
return parent->parent->getHOSSchemaLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
|
||||||
std::shared_ptr<RuleCondition> retval;
|
|
||||||
if (condition.IsMap() && condition.HasPath("type") && condition["type"].IsString()) {
|
if (condition.IsMap() && condition.HasPath("type") && condition["type"].IsString()) {
|
||||||
if (condition.HasPath("$schema")) {
|
if (condition.HasPath("$schema")) {
|
||||||
SchemaResult sr = SchemaValidate(Variant(), condition, getHOSSchemaLoader());
|
SchemaResult sr = SchemaValidate(Variant(), condition, parent->parent->getHOSSchemaLoader());
|
||||||
if (sr.Error()) {
|
if (sr.Error()) {
|
||||||
throw std::runtime_error(sr.PrettyPrintMessage());
|
throw std::runtime_error(sr.PrettyPrintMessage());
|
||||||
}
|
}
|
||||||
@@ -60,13 +57,13 @@ std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Variant raw) {
|
std::shared_ptr<RuleImpl> RuleImpl::createRule(RulePackageImpl* parent, std::string name, Variant raw) {
|
||||||
std::shared_ptr<Rule> retval;
|
std::shared_ptr<RuleImpl> retval;
|
||||||
if (parent->getRule(name)) {
|
if (!parent->getRule(name).expired()) {
|
||||||
throw std::runtime_error("Rule with the same name already exists.");
|
throw std::runtime_error("Rule with the same name already exists.");
|
||||||
}
|
}
|
||||||
if (raw.IsMap()) {
|
if (raw.IsMap()) {
|
||||||
retval = std::make_shared<Rule>(parent, name);
|
retval = std::make_shared<RuleImpl>(parent, name);
|
||||||
if (raw.HasPath("condition") && raw["condition"].IsMap()) {
|
if (raw.HasPath("condition") && raw["condition"].IsMap()) {
|
||||||
auto condition = raw["condition"];
|
auto condition = raw["condition"];
|
||||||
auto cond = retval->createRuleCondition(condition);
|
auto cond = retval->createRuleCondition(condition);
|
||||||
@@ -78,7 +75,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
|||||||
auto scriptFactory = parent->getScriptingService();
|
auto scriptFactory = parent->getScriptingService();
|
||||||
//ToDo: Create Condition
|
//ToDo: Create Condition
|
||||||
if (raw.HasPath("script") && raw["script"].IsMap()) {
|
if (raw.HasPath("script") && raw["script"].IsMap()) {
|
||||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["script"]);
|
auto script = scriptFactory->createScript(raw["script"]);
|
||||||
if (script) {
|
if (script) {
|
||||||
retval->script = script;
|
retval->script = script;
|
||||||
} else {
|
} else {
|
||||||
@@ -88,7 +85,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
|||||||
throw std::runtime_error("Malformed JSON: missing property script or is not an object.");
|
throw std::runtime_error("Malformed JSON: missing property script or is not an object.");
|
||||||
}
|
}
|
||||||
if (raw.HasPath("exitscript") && raw["exitscript"].IsMap()) {
|
if (raw.HasPath("exitscript") && raw["exitscript"].IsMap()) {
|
||||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["exitscript"]);
|
auto script = scriptFactory->createScript(raw["exitscript"]);
|
||||||
if (script) {
|
if (script) {
|
||||||
retval->exitScript = script;
|
retval->exitScript = script;
|
||||||
} else {
|
} else {
|
||||||
@@ -105,43 +102,34 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
devicerepository::DeviceRepositoryService* Rule::getDeviceRepository() {
|
devicerepository::DeviceRepositoryService* RuleImpl::getDeviceRepository() noexcept {
|
||||||
return parent->parent->getDeviceRepository();
|
return parent->parent->getDeviceRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rule::enable() {
|
void RuleImpl::setEnabled(bool enabled) noexcept {
|
||||||
if (!enabled) {
|
if (this->enabled != enabled) {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
condition->enable();
|
condition->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
enabled = true;
|
this->enabled = enabled;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rule::disable() {
|
|
||||||
if (enabled) {
|
|
||||||
if (condition) {
|
|
||||||
condition->disable();
|
|
||||||
}
|
|
||||||
enabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Rule::execute(Variant lContext) {
|
void RuleImpl::executeScript(const libvariant::Variant& lContext) {
|
||||||
if (enabled && script) {
|
if (enabled && script) {
|
||||||
try {
|
try {
|
||||||
script->exec(parent->getGlobalScriptContext().get(), lContext);
|
script->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
ROS_ERROR_STREAM(e.what());
|
ROS_ERROR_STREAM(e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rule::executeExitScript(Variant lContext) {
|
void RuleImpl::executeExitScript(const libvariant::Variant& lContext) {
|
||||||
if (enabled && exitScript) {
|
if (enabled && exitScript) {
|
||||||
try {
|
try {
|
||||||
exitScript->exec(parent->getGlobalScriptContext().get(), lContext);
|
exitScript->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
ROS_ERROR_STREAM(e.what());
|
ROS_ERROR_STREAM(e.what());
|
||||||
}
|
}
|
||||||
@@ -149,13 +137,13 @@ void Rule::executeExitScript(Variant lContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Rule::evaluate() {
|
bool RuleImpl::evaluate() {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
bool retval = condition->evaluate();
|
bool retval = condition->evaluate();
|
||||||
if (retval != currentState) {
|
if (retval != currentState) {
|
||||||
currentState = retval;
|
currentState = retval;
|
||||||
if (retval) {
|
if (retval) {
|
||||||
execute();
|
executeScript();
|
||||||
} else {
|
} else {
|
||||||
executeExitScript();
|
executeExitScript();
|
||||||
}
|
}
|
||||||
@@ -168,13 +156,13 @@ bool Rule::evaluate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Rule::conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext) {
|
void RuleImpl::conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext) noexcept {
|
||||||
if (newState && !currentState && category == RuleCondition::Category::Event) {
|
if (newState && !currentState && category == conditions::ConditionTriggerType::Event) {
|
||||||
execute(lcontext);
|
executeScript(lcontext);
|
||||||
} else if (category == RuleCondition::Category::State && newState != currentState) {
|
} else if (category == conditions::ConditionTriggerType::State && newState != currentState) {
|
||||||
currentState = newState;
|
currentState = newState;
|
||||||
if (newState) {
|
if (newState) {
|
||||||
execute(lcontext);
|
executeScript(lcontext);
|
||||||
} else {
|
} else {
|
||||||
executeExitScript(lcontext);
|
executeExitScript(lcontext);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||||
|
|
||||||
|
#include "RulePackageImpl.h"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace devicerepository {
|
||||||
|
class Device;
|
||||||
|
class DeviceEvent;
|
||||||
|
class DeviceRepositoryService;
|
||||||
|
}
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
class RulePackageImpl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace scripting {
|
||||||
|
class ScriptingService;
|
||||||
|
class GlobalScriptContext;
|
||||||
|
class Script;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace utils {
|
||||||
|
class SchemaLoader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
|
||||||
|
using namespace ::libvariant;
|
||||||
|
|
||||||
|
class RuleImpl : public virtual Rule {
|
||||||
|
private:
|
||||||
|
std::shared_ptr<scripting::Script> script;
|
||||||
|
std::shared_ptr<scripting::Script> exitScript;
|
||||||
|
std::shared_ptr<conditions::RuleCondition> condition;
|
||||||
|
bool enabled = false;
|
||||||
|
bool currentState = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RulePackageImpl* const parent;
|
||||||
|
const std::string name;
|
||||||
|
|
||||||
|
RuleImpl(RulePackageImpl* parent, const std::string name);
|
||||||
|
static std::shared_ptr<RuleImpl> createRule(RulePackageImpl* parent, const std::string name, Variant raw);
|
||||||
|
|
||||||
|
virtual RulePackage* getParent() noexcept {
|
||||||
|
return dynamic_cast<RulePackage*>(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const std::string& getName() noexcept {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isActive() noexcept override {
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
virtual bool evaluate() override;
|
||||||
|
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||||
|
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||||
|
|
||||||
|
virtual bool isEnabled() noexcept override {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
virtual void setEnabled(bool enabled) noexcept override;
|
||||||
|
|
||||||
|
void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext = Variant()) noexcept override;
|
||||||
|
|
||||||
|
std::shared_ptr<conditions::RuleCondition> createRuleCondition(const Variant& raw) override;
|
||||||
|
devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+22
-32
@@ -5,29 +5,29 @@
|
|||||||
* Author: matzman
|
* Author: matzman
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "RulePackage.h"
|
#include "RuleImpl.h"
|
||||||
|
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <Variant/Variant.h>
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
#include "../ruleengine_serviceimpl.h"
|
#include "../RuleEngineServiceImpl.h"
|
||||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
#include "RulePackageImpl.h"
|
||||||
|
|
||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace ruleengine {
|
namespace ruleengine {
|
||||||
namespace rule {
|
namespace rules {
|
||||||
|
|
||||||
RulePackage::RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
RulePackageImpl::RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
||||||
: parent(parent), name(name), language(language), rawValue(raw) {}
|
: parent(parent), name(name), language(language), rawValue(raw) {}
|
||||||
|
|
||||||
RulePackage::~RulePackage() {}
|
RulePackageImpl::~RulePackageImpl() {}
|
||||||
|
|
||||||
std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
std::shared_ptr<RulePackageImpl> RulePackageImpl::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
||||||
std::shared_ptr<RulePackage> retval;
|
std::shared_ptr<RulePackageImpl> retval;
|
||||||
if (parent->getRulePackage(name)) {
|
if (!parent->getRulePackage(name).expired()) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Could not create package " << name << ": There already exists a rule package with the same name.";
|
ss << "Could not create package " << name << ": There already exists a rule package with the same name.";
|
||||||
throw std::runtime_error(ss.str());
|
throw std::runtime_error(ss.str());
|
||||||
@@ -39,7 +39,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
|||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Rule package JSON is missing language parameter or parameter has wrong type.");
|
throw std::runtime_error("Rule package JSON is missing language parameter or parameter has wrong type.");
|
||||||
}
|
}
|
||||||
retval = std::make_shared<RulePackage>(parent, name, language, raw);
|
retval = std::make_shared<RulePackageImpl>(parent, name, language, raw);
|
||||||
retval->executionService = parent->getExecutionBackend(retval->language);
|
retval->executionService = parent->getExecutionBackend(retval->language);
|
||||||
if (retval->executionService) {
|
if (retval->executionService) {
|
||||||
if (raw.HasPath("globalcontext")) {
|
if (raw.HasPath("globalcontext")) {
|
||||||
@@ -48,7 +48,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
|||||||
if (raw.HasPath("rules") && raw["rules"].IsMap()) {
|
if (raw.HasPath("rules") && raw["rules"].IsMap()) {
|
||||||
for (auto r : raw["rules"].AsMap()) {
|
for (auto r : raw["rules"].AsMap()) {
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<Rule> rule = Rule::createRule(retval.get(), r.first, r.second);
|
std::shared_ptr<RuleImpl> rule = RuleImpl::createRule(retval.get(), r.first, r.second);
|
||||||
if (rule) {
|
if (rule) {
|
||||||
retval->rules.insert({r.first, rule});
|
retval->rules.insert({r.first, rule});
|
||||||
}
|
}
|
||||||
@@ -70,49 +70,39 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<Rule> RulePackage::getRule(const std::string& name) {
|
std::weak_ptr<Rule> RulePackageImpl::getRule(const std::string& name) noexcept {
|
||||||
std::shared_ptr<Rule> retval;
|
std::weak_ptr<Rule> retval;
|
||||||
try {
|
try {
|
||||||
retval = rules.at(name);
|
retval = rules.at(name);
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RulePackage::getRules(std::vector<std::shared_ptr<Rule>>& rules) {
|
std::vector<std::weak_ptr<Rule>> RulePackageImpl::getRules() noexcept {
|
||||||
size_t retval = 0;
|
std::vector<std::weak_ptr<Rule>> retval;
|
||||||
for (auto item : this->rules) {
|
for (auto item : this->rules) {
|
||||||
rules.push_back(item.second);
|
retval.push_back(dynamic_pointer_cast<Rule>(item.second));
|
||||||
retval++;
|
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RuleConditionFactory> RulePackage::getConditionFactory(std::string type) {
|
std::shared_ptr<RuleConditionFactory> RulePackageImpl::getConditionFactory(std::string type) {
|
||||||
return parent->getRuleConditionFactory(type);
|
return parent->getRuleConditionFactory(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RulePackage::enable() {
|
void RulePackageImpl::setEnabled(bool enabled) noexcept {
|
||||||
if (!enabled) {
|
if (this->enabled != enabled) {
|
||||||
for (auto r : rules) {
|
for (auto r : rules) {
|
||||||
r.second->enable();
|
r.second->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
enabled = true;
|
this->enabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RulePackage::disable() {
|
|
||||||
if (enabled) {
|
|
||||||
for (auto r : rules) {
|
|
||||||
r.second->enable();
|
|
||||||
}
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} /* namespace rules */
|
||||||
} /* namespace rule */
|
|
||||||
} /* namespace ruleengine */
|
} /* namespace ruleengine */
|
||||||
} /* namespace service */
|
} /* namespace service */
|
||||||
} /* namespace cosgi */
|
} /* namespace cosgi */
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||||
|
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||||
|
#include "../RuleEngineServiceImpl.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
class RuleEngineServiceImpl;
|
||||||
|
class RuleConditionFactory;
|
||||||
|
namespace rules {
|
||||||
|
class RuleImpl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace scripting {
|
||||||
|
class GlobalScriptContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
|
||||||
|
using namespace ::libvariant;
|
||||||
|
|
||||||
|
class RulePackageImpl
|
||||||
|
: public virtual RulePackage {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::shared_ptr<RuleImpl>> ruleMap_t;
|
||||||
|
|
||||||
|
service::scripting::ScriptingService* executionService = nullptr;
|
||||||
|
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
||||||
|
ruleMap_t rules;
|
||||||
|
Variant rawValue;
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static std::shared_ptr<RulePackageImpl> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
||||||
|
RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
||||||
|
virtual ~RulePackageImpl();
|
||||||
|
|
||||||
|
service::ruleengine::RuleEngineServiceImpl* const parent;
|
||||||
|
const std::string name;
|
||||||
|
const std::string language;
|
||||||
|
|
||||||
|
virtual service::ruleengine::RuleEngineService* getParent() noexcept override {
|
||||||
|
return dynamic_cast<service::ruleengine::RuleEngineService*>(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const std::string& getName() noexcept override {
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
virtual const std::string& getLanguage() noexcept override {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept override;
|
||||||
|
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept override;
|
||||||
|
virtual size_t getRuleCount() noexcept override { return rules.size(); }
|
||||||
|
|
||||||
|
virtual bool isEnabled() noexcept override {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
virtual void setEnabled(bool enabled) noexcept override;
|
||||||
|
|
||||||
|
virtual service::scripting::ScriptingService* getScriptingService() noexcept override { return executionService; }
|
||||||
|
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept override { return globalContext; }
|
||||||
|
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+271
@@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "DeviceMsgCondition.h"
|
||||||
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include "../RuleImpl.h"
|
||||||
|
#include <ros/ros.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||||
|
switch (key) {
|
||||||
|
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
||||||
|
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
||||||
|
ROS_INFO_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " appeared.");
|
||||||
|
device = e->device;
|
||||||
|
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||||
|
_registerAsListener();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
||||||
|
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
||||||
|
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " disappeared.");
|
||||||
|
device->deleteObserver(this);
|
||||||
|
device = nullptr;
|
||||||
|
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceMsgCondition::setEnabled(bool enabled) noexcept {
|
||||||
|
if (this->enabled != enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
auto repoService = parent->getDeviceRepository();
|
||||||
|
auto device = repoService->getDevice(deviceID);
|
||||||
|
if (!device.expired()) {
|
||||||
|
this->device = device.lock().get();
|
||||||
|
_registerAsListener();
|
||||||
|
} else {
|
||||||
|
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Could not find device " << deviceID);
|
||||||
|
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (device) {
|
||||||
|
device->deleteObserver(this);
|
||||||
|
device = nullptr;
|
||||||
|
}
|
||||||
|
parent->getDeviceRepository()->deleteObserver(this);
|
||||||
|
}
|
||||||
|
this->enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceMsgCondition::_registerAsListener() {
|
||||||
|
if (device) {
|
||||||
|
for (auto k : _listenerKeys) {
|
||||||
|
device->addObserver(k, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
|
std::shared_ptr<DeviceStatusMsgCondition> retval;
|
||||||
|
std::string deviceID;
|
||||||
|
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||||
|
deviceID = raw["deviceid"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||||
|
}
|
||||||
|
std::string msgPointer;
|
||||||
|
if (raw.HasPath("msgpointer")) {
|
||||||
|
if (raw["msgpointer"].IsString()) {
|
||||||
|
msgPointer = raw["msgpointer"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variant msgValue;
|
||||||
|
if (raw.HasPath("msgvalue")) {
|
||||||
|
msgValue = raw["msgvalue"];
|
||||||
|
}
|
||||||
|
retval = std::make_shared<DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||||
|
switch (e->eventType) {
|
||||||
|
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
||||||
|
if (device && device == e->device) {
|
||||||
|
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||||
|
bool notify = true;
|
||||||
|
Variant value;
|
||||||
|
if (msgPointer.empty()) {
|
||||||
|
value = e2->statusMsg;
|
||||||
|
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||||
|
value = e2->statusMsg.GetPath(msgPointer);
|
||||||
|
} else {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
if (notify && !msgValue.IsNull()) {
|
||||||
|
if (msgValue != value) {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notify) {
|
||||||
|
Variant lcontext;
|
||||||
|
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||||
|
lcontext["event_type"] = Variant("statusmsg");
|
||||||
|
lcontext["event_msg"] = e2->statusMsg;
|
||||||
|
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
|
std::shared_ptr<DeviceCommandMsgCondition> retval;
|
||||||
|
std::string deviceID;
|
||||||
|
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||||
|
deviceID = raw["deviceid"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||||
|
}
|
||||||
|
std::string msgPointer;
|
||||||
|
if (raw.HasPath("msgpointer")) {
|
||||||
|
if (raw["msgpointer"].IsString()) {
|
||||||
|
msgPointer = raw["msgpointer"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variant msgValue;
|
||||||
|
if (raw.HasPath("msgvalue")) {
|
||||||
|
msgValue = raw["msgvalue"];
|
||||||
|
}
|
||||||
|
retval = std::make_shared<DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||||
|
switch (e->eventType) {
|
||||||
|
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
||||||
|
if (device && device == e->device) {
|
||||||
|
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
||||||
|
bool notify = true;
|
||||||
|
Variant value;
|
||||||
|
if (msgPointer.empty()) {
|
||||||
|
value = e2->cmdMsg;
|
||||||
|
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||||
|
value = e2->cmdMsg.GetPath(msgPointer);
|
||||||
|
} else {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
if (notify && !msgValue.IsNull()) {
|
||||||
|
if (msgValue != value) {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notify) {
|
||||||
|
Variant lcontext;
|
||||||
|
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||||
|
lcontext["event_type"] = Variant("commandmsg");
|
||||||
|
lcontext["event_msg"] = e2->cmdMsg;
|
||||||
|
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RuleCondition> DeviceStateChangeConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
|
std::shared_ptr<DeviceStateChangeCondition> retval;
|
||||||
|
std::string deviceID;
|
||||||
|
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||||
|
deviceID = raw["deviceid"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||||
|
}
|
||||||
|
std::string statePointer;
|
||||||
|
if (raw.HasPath("msgpointer")) {
|
||||||
|
if (raw["msgpointer"].IsString()) {
|
||||||
|
statePointer = raw["msgpointer"].AsString();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variant fromValue;
|
||||||
|
if (raw.HasPath("fromvalue")) {
|
||||||
|
fromValue = raw["fromvalue"];
|
||||||
|
}
|
||||||
|
Variant toValue;
|
||||||
|
if (raw.HasPath("tovalue")) {
|
||||||
|
toValue = raw["tovalue"];
|
||||||
|
}
|
||||||
|
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||||
|
switch (e->eventType) {
|
||||||
|
case devicerepository::DeviceEventType::STATE_CHANGED:
|
||||||
|
if (device && device == e->device) {
|
||||||
|
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||||
|
bool notify = true;
|
||||||
|
Variant current, last;
|
||||||
|
if (msgPointer.empty()) {
|
||||||
|
current = device->getCurrentState();
|
||||||
|
last = device->getLastState();
|
||||||
|
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||||
|
current = device->getCurrentState().GetPath(msgPointer);
|
||||||
|
last = device->getLastState().GetPath(msgPointer);
|
||||||
|
} else {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
if (notify) {
|
||||||
|
if (current == last) {
|
||||||
|
notify = false;
|
||||||
|
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||||
|
notify = false;
|
||||||
|
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||||
|
notify = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notify) {
|
||||||
|
Variant lcontext;
|
||||||
|
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||||
|
lcontext["event_type"] = Variant("statechange");
|
||||||
|
lcontext["event_msg"] = e2->statusMsg;
|
||||||
|
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||||
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
|
// main Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceMsgCondition
|
||||||
|
: public RuleConditionImpl,
|
||||||
|
public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent> {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const std::string deviceID;
|
||||||
|
devicerepository::Device* device = nullptr;
|
||||||
|
const std::string msgPointer;
|
||||||
|
const Variant msgValue;
|
||||||
|
std::set<devicerepository::DeviceEventType> _listenerKeys;
|
||||||
|
|
||||||
|
virtual void _registerAsListener();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeviceMsgCondition( Rule* parent,
|
||||||
|
ConditionTriggerType category,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& deviceID,
|
||||||
|
const std::string& msgPointer,
|
||||||
|
const Variant& msgValue,
|
||||||
|
const std::set<devicerepository::DeviceEventType> _listenerKeys )
|
||||||
|
: RuleConditionImpl(parent, category, type), deviceID(deviceID),
|
||||||
|
msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||||
|
|
||||||
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
|
const devicerepository::DeviceEventType& key,
|
||||||
|
const devicerepository::DeviceEvent* e) noexcept override;
|
||||||
|
|
||||||
|
virtual void setEnabled(bool enabled) noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStatusMsgCondition
|
||||||
|
: public DeviceMsgCondition {
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeviceStatusMsgCondition( Rule* parent,
|
||||||
|
const std::string& deviceID,
|
||||||
|
const std::string& msgPointer,
|
||||||
|
const Variant& msgValue)
|
||||||
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatusmsg", deviceID,
|
||||||
|
msgPointer, msgValue, {devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED}) {}
|
||||||
|
|
||||||
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
|
const devicerepository::DeviceEventType& key,
|
||||||
|
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStatusMsgConditionFactory
|
||||||
|
: public RuleConditionFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceCommandMsgCondition
|
||||||
|
: public DeviceMsgCondition {
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue)
|
||||||
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicecommandmsg", deviceID,
|
||||||
|
msgPointer, msgValue, {devicerepository::DeviceEventType::COMMAND_RECEIVED}) {}
|
||||||
|
|
||||||
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
|
const devicerepository::DeviceEventType& key,
|
||||||
|
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceCommandMsgConditionFactory
|
||||||
|
: public RuleConditionFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStateChangeCondition
|
||||||
|
: public DeviceMsgCondition {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Variant fromValue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeviceStateChangeCondition( Rule* parent,
|
||||||
|
const std::string deviceID,
|
||||||
|
const std::string statePointer,
|
||||||
|
const Variant fromValue,
|
||||||
|
const Variant toValue )
|
||||||
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatechange", deviceID, statePointer,
|
||||||
|
toValue, {devicerepository::DeviceEventType::STATE_CHANGED}), fromValue(fromValue) {}
|
||||||
|
|
||||||
|
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceStateChangeConditionFactory
|
||||||
|
: public RuleConditionFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
#include "LogicalAndCondition.h"
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RuleCondition> LogicalAndConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
|
std::shared_ptr<LogicalAndCondition> retval;
|
||||||
|
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||||
|
retval = std::make_shared<LogicalAndCondition>(parent);
|
||||||
|
for (auto c : raw["conditions"].AsList()) {
|
||||||
|
auto cond = parent->createRuleCondition(c);
|
||||||
|
if (cond) {
|
||||||
|
retval->addChild(cond);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Could not create condition.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||||
|
}
|
||||||
|
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||||
|
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||||
|
if (eventChildrenCount > 0) {
|
||||||
|
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
||||||
|
}
|
||||||
|
eventChildrenCount++;
|
||||||
|
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||||
|
stateChildrenCount++;
|
||||||
|
} else {
|
||||||
|
mixedChildrenCount++;
|
||||||
|
}
|
||||||
|
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||||
|
triggerType = ConditionTriggerType::Both;
|
||||||
|
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||||
|
triggerType = ConditionTriggerType::Event;
|
||||||
|
} else {
|
||||||
|
triggerType = ConditionTriggerType::State;
|
||||||
|
}
|
||||||
|
RuleCompositeConditionImpl::addChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||||
|
if (newState && category == ConditionTriggerType::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
||||||
|
notifyStateChangeToParent(true, category);
|
||||||
|
} else if (category == ConditionTriggerType::State) {
|
||||||
|
if (newState) {
|
||||||
|
trueChildrenCount++;
|
||||||
|
if (!currentState && trueChildrenCount >= children.size()) {
|
||||||
|
currentState = true;
|
||||||
|
notifyStateChangeToParent(true, category, lcontext);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trueChildrenCount--;
|
||||||
|
if (currentState) {
|
||||||
|
currentState = false;
|
||||||
|
notifyStateChangeToParent(false, category, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool LogicalAndCondition::evaluate() noexcept {
|
||||||
|
// Event conditions always evaluate to false
|
||||||
|
if (triggerType == ConditionTriggerType::Event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
trueChildrenCount = 0;
|
||||||
|
for (auto c : children) {
|
||||||
|
if (c->evaluate()) {
|
||||||
|
trueChildrenCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentState = trueChildrenCount == children.size();
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LogicalAndCondition
|
||||||
|
: public RuleCompositeConditionImpl {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned eventChildrenCount = 0;
|
||||||
|
unsigned stateChildrenCount = 0;
|
||||||
|
unsigned mixedChildrenCount = 0;
|
||||||
|
unsigned trueChildrenCount = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LogicalAndCondition(Rule* parent) :
|
||||||
|
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_and") {}
|
||||||
|
|
||||||
|
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||||
|
|
||||||
|
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||||
|
const Variant& lcontext = Variant()) noexcept override;
|
||||||
|
|
||||||
|
virtual bool evaluate() noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LogicalAndConditionFactory
|
||||||
|
: public RuleConditionFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
#include "LogicalOrCondition.h"
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RuleCondition> LogicalOrConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
|
std::shared_ptr<LogicalOrCondition> retval;
|
||||||
|
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||||
|
retval = std::make_shared<LogicalOrCondition>(parent);
|
||||||
|
for (auto c : raw["conditions"].AsList()) {
|
||||||
|
auto cond = parent->createRuleCondition(c);
|
||||||
|
if (cond) {
|
||||||
|
retval->addChild(cond);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Could not create condition.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||||
|
}
|
||||||
|
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||||
|
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||||
|
eventChildrenCount++;
|
||||||
|
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||||
|
stateChildrenCount++;
|
||||||
|
} else {
|
||||||
|
mixedChildrenCount++;
|
||||||
|
}
|
||||||
|
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||||
|
triggerType = ConditionTriggerType::Both;
|
||||||
|
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||||
|
triggerType = ConditionTriggerType::Event;
|
||||||
|
} else {
|
||||||
|
triggerType = ConditionTriggerType::State;
|
||||||
|
}
|
||||||
|
RuleCompositeConditionImpl::addChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState,
|
||||||
|
ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||||
|
if (newState && category == ConditionTriggerType::Event && !currentState) {
|
||||||
|
notifyStateChangeToParent(true, category, lcontext);
|
||||||
|
} else if (category == ConditionTriggerType::State) {
|
||||||
|
if (newState) {
|
||||||
|
trueChildrenCount++;
|
||||||
|
if (!currentState) {
|
||||||
|
currentState = true;
|
||||||
|
notifyStateChangeToParent(true, category, lcontext);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trueChildrenCount--;
|
||||||
|
if (currentState && trueChildrenCount <= 0) {
|
||||||
|
currentState = false;
|
||||||
|
notifyStateChangeToParent(false, category, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool LogicalOrCondition::evaluate() noexcept {
|
||||||
|
// Event conditions always evaluate to false
|
||||||
|
if (triggerType == ConditionTriggerType::Event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
trueChildrenCount = 0;
|
||||||
|
for (auto c : children) {
|
||||||
|
if (c->evaluate()) {
|
||||||
|
trueChildrenCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentState = trueChildrenCount > 0;
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||||
|
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LogicalOrCondition
|
||||||
|
: public RuleCompositeConditionImpl {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned eventChildrenCount = 0;
|
||||||
|
unsigned stateChildrenCount = 0;
|
||||||
|
unsigned mixedChildrenCount = 0;
|
||||||
|
unsigned trueChildrenCount = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LogicalOrCondition(Rule* parent) :
|
||||||
|
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_or") {}
|
||||||
|
|
||||||
|
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||||
|
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||||
|
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept override;
|
||||||
|
virtual bool evaluate() noexcept override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LogicalOrConditionFactory
|
||||||
|
: public RuleConditionFactory {
|
||||||
|
public:
|
||||||
|
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||||
|
#include "../RuleImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace ruleengine {
|
||||||
|
namespace rules {
|
||||||
|
namespace conditions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RuleConditionImpl::notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext) {
|
||||||
|
if (compositeParent) {
|
||||||
|
compositeParent->childStateChanged(this, newState, category, lcontext);
|
||||||
|
} else {
|
||||||
|
parent->conditionStateChanged(newState, category, lcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} /* namespace conditions */
|
||||||
|
} /* namespace rules */
|
||||||
|
} /* namespace ruleengine */
|
||||||
|
} /* namespace service */
|
||||||
|
} /* namespace cosgi */
|
||||||
|
} /* namespace hos */
|
||||||
|
|
||||||
@@ -93,6 +93,12 @@ catkin_package(
|
|||||||
## Build ##
|
## Build ##
|
||||||
###########
|
###########
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
include/${PROJECT_NAME}/
|
||||||
|
${catkin_INCLUDE_DIRS}
|
||||||
|
${libvariant_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
## Specify additional locations of header files
|
## Specify additional locations of header files
|
||||||
## Your package locations should be listed before other locations
|
## Your package locations should be listed before other locations
|
||||||
# include_directories(include)
|
# include_directories(include)
|
||||||
|
|||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Interface.h>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace scripting {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of an abstract global script context.
|
||||||
|
*
|
||||||
|
* It persists the global context across script executions (to implement global variables).
|
||||||
|
*
|
||||||
|
* Currently it is just an opaque handle that is passed to the script execution handle.
|
||||||
|
*/
|
||||||
|
class GlobalScriptContext
|
||||||
|
: public virtual interface::Object {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of an abstract script object.
|
||||||
|
*
|
||||||
|
* This object is supposed to be stateless, every state is carried in the global script context.
|
||||||
|
*/
|
||||||
|
class Script
|
||||||
|
: public virtual interface::Object {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the script object with the given contexts.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param[in] gContext reference to global context.
|
||||||
|
* \param[in] lContext map with local variables.
|
||||||
|
*/
|
||||||
|
virtual void execute( std::shared_ptr<GlobalScriptContext> gContext = std::shared_ptr<GlobalScriptContext>(),
|
||||||
|
const libvariant::Variant& lContext = libvariant::Variant() ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public COSGI interface of a scripting service.
|
||||||
|
*
|
||||||
|
* It offers following functionality:
|
||||||
|
* - Create scripts and related objects.
|
||||||
|
*/
|
||||||
|
class ScriptingService
|
||||||
|
: public virtual interface::Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common name for every scripting service implementation.
|
||||||
|
*/
|
||||||
|
static constexpr const char* SERVICE_NAME = "hos_scripting_service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unique identifier indicating the scripting language.
|
||||||
|
*
|
||||||
|
* \return unique language identifier.
|
||||||
|
*/
|
||||||
|
virtual const char* getLanguage() noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a global context object from the given json global context config.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param raw json config.
|
||||||
|
* \return global context object.
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<GlobalScriptContext> createGlobalScriptContext(const libvariant::Variant& raw) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a script object from the given json script config.
|
||||||
|
*
|
||||||
|
* May return exceptions derived from std::exception.
|
||||||
|
*
|
||||||
|
* \param raw json config.
|
||||||
|
* \return global context object.
|
||||||
|
*/
|
||||||
|
virtual std::shared_ptr<Script> createScript(const libvariant::Variant& raw) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace scripting
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* hos_ruleexecution_service.h
|
|
||||||
*
|
|
||||||
* Created on: 01.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_
|
|
||||||
#define INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/Interface.h>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace scripting {
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
class GlobalScriptContext : public virtual interface::Object {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Script : public virtual interface::Object {
|
|
||||||
public:
|
|
||||||
virtual void exec(GlobalScriptContext* gContext, Variant lContext = Variant()) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ScriptingService : public virtual interface::Service {
|
|
||||||
public:
|
|
||||||
static constexpr const char* SERVICE_NAME = "hos_scripting_service";
|
|
||||||
|
|
||||||
virtual std::string getLanguage() = 0;
|
|
||||||
|
|
||||||
virtual std::shared_ptr<GlobalScriptContext> createGlobalScriptContext(::libvariant::Variant raw) = 0;
|
|
||||||
virtual std::shared_ptr<Script> createScript(GlobalScriptContext* gContext, ::libvariant::Variant raw) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace scripting
|
|
||||||
} // namespace service
|
|
||||||
} // namespace cosgi
|
|
||||||
} // namespace hos
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INCLUDE_HOS_COSGI_SCRIPTING_HOS_COSGI_SERVICE_SCRIPTING_SCRIPTING_SERVICE_H_ */
|
|
||||||
@@ -121,9 +121,10 @@ set(BUNDLE_NAME "hos_scripting_python")
|
|||||||
|
|
||||||
bundle(hos_cosgi_scripting_python
|
bundle(hos_cosgi_scripting_python
|
||||||
SOURCES
|
SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/scripting_serviceimpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/PyScriptingServiceImpl
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/PyHOSAPI
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/utils/utils
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/scripting/python/hosapi/PyHOSAPI
|
||||||
)
|
)
|
||||||
target_link_libraries(hos_cosgi_scripting_python
|
target_link_libraries(hos_cosgi_scripting_python
|
||||||
${catkin_LIBRARIES}
|
${catkin_LIBRARIES}
|
||||||
|
|||||||
+17
-20
@@ -1,28 +1,19 @@
|
|||||||
/*
|
|
||||||
* bundle_activator.cpp
|
|
||||||
*
|
|
||||||
* Created on: 26.04.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// std
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
// ROS
|
||||||
|
#include <ros/ros.h>
|
||||||
|
// APR
|
||||||
#include <apr_general.h>
|
#include <apr_general.h>
|
||||||
|
// Celix
|
||||||
#include "ros/ros.h"
|
#include <hos/cosgi/celix.h>
|
||||||
|
// CoreService
|
||||||
extern "C" {
|
#include "hos/cosgi/service/scripting/python/PyScriptingServiceImpl.h"
|
||||||
#include "celix/bundle_activator.h"
|
|
||||||
#include "celix/bundle_context.h"
|
|
||||||
#include "celix/service_reference.h"
|
|
||||||
#include "celix/constants.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
#include "hos/cosgi/service/scripting/python/scripting_serviceimpl.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace hos::cosgi::service::scripting;
|
using namespace hos::cosgi::service::scripting;
|
||||||
@@ -42,6 +33,7 @@ struct UserData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
||||||
UserData* myUserData = (UserData*) ((serviceListener*)listener)->handle;
|
UserData* myUserData = (UserData*) ((serviceListener*)listener)->handle;
|
||||||
if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
|
if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
|
||||||
@@ -63,6 +55,7 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
|||||||
return CELIX_SUCCESS;
|
return CELIX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
|
||||||
celix_status_t status = CELIX_SUCCESS;
|
celix_status_t status = CELIX_SUCCESS;
|
||||||
apr_pool_t* memoryPool = nullptr;
|
apr_pool_t* memoryPool = nullptr;
|
||||||
@@ -87,6 +80,7 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_SUCCESS;
|
celix_status_t status = CELIX_SUCCESS;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
@@ -132,6 +126,7 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
@@ -152,6 +147,7 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
|
||||||
celix_status_t status = CELIX_ILLEGAL_STATE;
|
celix_status_t status = CELIX_ILLEGAL_STATE;
|
||||||
if (userData != nullptr) {
|
if (userData != nullptr) {
|
||||||
@@ -168,3 +164,4 @@ celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt contex
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
+68
-40
@@ -1,17 +1,8 @@
|
|||||||
/*
|
|
||||||
* hos_cosgi_ruleexecution_python_impl.cpp
|
|
||||||
*
|
|
||||||
* Created on: 01.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "scripting_serviceimpl.h"
|
|
||||||
|
|
||||||
|
#include "PyScriptingServiceImpl.h"
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
|
|
||||||
#include "PyHOSAPI.h"
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include "hosapi/PyHOSAPI.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -21,52 +12,77 @@ namespace service {
|
|||||||
namespace scripting {
|
namespace scripting {
|
||||||
namespace python {
|
namespace python {
|
||||||
|
|
||||||
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
|
||||||
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 0;
|
|
||||||
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 8;
|
|
||||||
|
|
||||||
void PyScriptingService::setCoreService(service::core::CoreService* coreService) {
|
|
||||||
|
// Service information
|
||||||
|
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
||||||
|
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 1;
|
||||||
|
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PyScriptingService::setCoreService(service::core::CoreService* coreService) noexcept {
|
||||||
if (coreService && !this->coreService) {
|
if (coreService && !this->coreService) {
|
||||||
this->coreService = coreService;
|
this->coreService = coreService;
|
||||||
this->nodehandle = &coreService->getPrivateNodeHandle();
|
this->nodehandle = &coreService->getPrivateNodeHandle();
|
||||||
int major = 0, minor = 0;
|
int major = 0, minor = 0;
|
||||||
coreService->getServiceVersion(major, minor);
|
coreService->getServiceVersion(major, minor);
|
||||||
ROS_INFO_STREAM("PyRuleExecutionService: Found HOSCoreService Version " << major << "." << minor);
|
ROS_INFO_STREAM("PyScriptingService: Found CoreService Version " << major << "." << minor);
|
||||||
if (repoService) {
|
if (repoService) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyScriptingService::setRepoService(devicerepository::DeviceRepositoryService* repoService) {
|
void PyScriptingService::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
||||||
if (repoService && !this->repoService) {
|
if (repoService && !this->repoService) {
|
||||||
this->repoService = repoService;
|
this->repoService = repoService;
|
||||||
int major = 0, minor = 0;
|
int major = 0, minor = 0;
|
||||||
repoService->getServiceVersion(major, minor);
|
repoService->getServiceVersion(major, minor);
|
||||||
ROS_INFO_STREAM("PyRuleExecutionService: Found HOSDeviceRepositoryService Version " << major << "." << minor);
|
ROS_INFO_STREAM("PyScriptingService: Found DeviceRepositoryService Version " << major << "." << minor);
|
||||||
if (coreService) {
|
if (coreService) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyScriptingService::init() {
|
void PyScriptingService::init() noexcept {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
|
|
||||||
|
// Initialize Python
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
|
|
||||||
|
// Import __main__
|
||||||
boost::python::object main_module = boost::python::import("__main__");
|
boost::python::object main_module = boost::python::import("__main__");
|
||||||
pyGlobalScope = main_module.attr("__dict__");// Load the sys module.
|
|
||||||
|
// Create default global scope
|
||||||
|
pyGlobalScope = main_module.attr("__dict__");
|
||||||
|
|
||||||
|
// import sys and get version
|
||||||
boost::python::object sys = boost::python::import("sys");
|
boost::python::object sys = boost::python::import("sys");
|
||||||
std::string version = boost::python::extract<std::string>(sys.attr("version"));
|
std::string version = boost::python::extract<std::string>(sys.attr("version"));
|
||||||
ROS_INFO_STREAM("PyRuleExecutionService: Python Version: " << version);
|
ROS_INFO_STREAM("PyScriptingService: Python Version: " << version);
|
||||||
|
|
||||||
|
// Initialize HOS Python API
|
||||||
|
inithos();
|
||||||
|
deviceService.reset(new hosapi::PyDeviceRepositoryWrapper(repoService));
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
ROS_INFO_STREAM("PyRuleExecutionService: Initialized and Ready.");
|
ROS_INFO_STREAM("PyRuleExecutionService: Initialized and Ready.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::createGlobalScriptContext(Variant raw) {
|
|
||||||
|
std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::createGlobalScriptContext(const Variant& raw) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::shared_ptr<PyGlobalScriptContext> retval;
|
std::shared_ptr<PyGlobalScriptContext> retval;
|
||||||
|
|
||||||
|
// Retrieve script code and execute it
|
||||||
if (raw.HasPath("code") && raw["code"].IsString()) {
|
if (raw.HasPath("code") && raw["code"].IsString()) {
|
||||||
retval = std::make_shared<PyGlobalScriptContext>(this->pyGlobalScope, raw["code"].AsString());
|
retval = std::make_shared<PyGlobalScriptContext>(this, this->pyGlobalScope, raw["code"].AsString());
|
||||||
try {
|
try {
|
||||||
boost::python::object result = boost::python::exec(retval->getCode().c_str(), pyGlobalScope);
|
// When no local context is given, all variable created during execution comes into the global scope
|
||||||
|
boost::python::object result = boost::python::exec(retval->getScriptCode().c_str(), pyGlobalScope);
|
||||||
|
|
||||||
} catch(boost::python::error_already_set const &) {
|
} catch(boost::python::error_already_set const &) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
throw std::runtime_error("Python error during global context creation.");
|
throw std::runtime_error("Python error during global context creation.");
|
||||||
@@ -75,10 +91,13 @@ std::shared_ptr<service::scripting::GlobalScriptContext> PyScriptingService::cre
|
|||||||
return std::static_pointer_cast<service::scripting::GlobalScriptContext>(retval);
|
return std::static_pointer_cast<service::scripting::GlobalScriptContext>(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(service::scripting::GlobalScriptContext* gContext, Variant raw) {
|
|
||||||
|
std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(const Variant& raw) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(serviceMutex);
|
||||||
std::shared_ptr<PyScript> retval;
|
std::shared_ptr<PyScript> retval;
|
||||||
|
// Retrieve script code and create script object
|
||||||
if (raw.HasPath("code") && raw["code"].IsString()) {
|
if (raw.HasPath("code") && raw["code"].IsString()) {
|
||||||
retval = std::make_shared<PyScript>(raw["code"].AsString(), *this);
|
retval = std::make_shared<PyScript>(this, raw["code"].AsString());
|
||||||
}
|
}
|
||||||
return std::static_pointer_cast<service::scripting::Script>(retval);
|
return std::static_pointer_cast<service::scripting::Script>(retval);
|
||||||
}
|
}
|
||||||
@@ -86,24 +105,33 @@ std::shared_ptr<service::scripting::Script> PyScriptingService::createScript(ser
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PyScript::exec(service::scripting::GlobalScriptContext* gContext, Variant lContext) {
|
|
||||||
|
|
||||||
|
void PyScript::execute( std::shared_ptr<GlobalScriptContext> gContext, const libvariant::Variant& lContext ) {
|
||||||
try {
|
try {
|
||||||
boost::python::object& gcont = service.getPyGlobalScope();
|
auto gCont = dynamic_pointer_cast<PyGlobalScriptContext>(gContext);
|
||||||
|
|
||||||
|
// Get global scope
|
||||||
|
boost::python::object* gscope;
|
||||||
if (gContext) {
|
if (gContext) {
|
||||||
gcont = dynamic_cast<PyGlobalScriptContext*>(gContext)->getPyGlobalContext();
|
gscope = &dynamic_pointer_cast<PyGlobalScriptContext>(gContext)->getPyObject();
|
||||||
}
|
|
||||||
boost::python::object lcont;
|
|
||||||
if (!lContext.IsNull()) {
|
|
||||||
lcont = convertVariantToBoostPython(lContext);
|
|
||||||
//gcont["local"] = lcont;
|
|
||||||
} else {
|
} else {
|
||||||
lcont = boost::python::dict();
|
gscope = &service->getPyDefaultScrope();
|
||||||
}
|
}
|
||||||
inithos();
|
|
||||||
PyDeviceRepositoryWrapper deviceService(service.getDeviceRepository());
|
// Create local scope
|
||||||
lcont["Devices"] = boost::python::object(boost::python::ptr(&deviceService));
|
boost::python::object lscope;
|
||||||
gcont["Devices"] = boost::python::object(deviceService);
|
if (!lContext.IsNull() && lContext.IsMap()) {
|
||||||
boost::python::object result = boost::python::exec(code.c_str(), gcont, lcont);
|
lscope = utils::convertVariantToBoostPython(lContext);
|
||||||
|
//gscope["local"] = lscope;
|
||||||
|
} else {
|
||||||
|
lscope = boost::python::dict();
|
||||||
|
}
|
||||||
|
lscope["Devices"] = boost::python::object(boost::python::ptr(service->getDeviceService()));
|
||||||
|
|
||||||
|
// Execute script scope
|
||||||
|
boost::python::object result = boost::python::exec(code.c_str(), *gscope, lscope);
|
||||||
|
|
||||||
} catch(boost::python::error_already_set const &) {
|
} catch(boost::python::error_already_set const &) {
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
throw std::runtime_error("Python error during execution.");
|
throw std::runtime_error("Python error during execution.");
|
||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||||
|
// hos includes
|
||||||
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include "hosapi/PyHOSAPI.h"
|
||||||
|
// libvariant includes
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
// ROS includes
|
||||||
|
#include <ros/ros.h>
|
||||||
|
// std includes
|
||||||
|
#include <memory>
|
||||||
|
// boost includes
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace scripting {
|
||||||
|
namespace python {
|
||||||
|
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
|
class PyScriptingService;
|
||||||
|
|
||||||
|
|
||||||
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python implementation of GlobalScriptContext.
|
||||||
|
*/
|
||||||
|
class PyGlobalScriptContext
|
||||||
|
: public virtual service::scripting::GlobalScriptContext {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PyScriptingService* service;
|
||||||
|
boost::python::object gContext;
|
||||||
|
std::string code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PyGlobalScriptContext(PyScriptingService* service, const boost::python::object& gContext, const std::string& code)
|
||||||
|
: service(service), gContext(gContext), code(code) {}
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
|
||||||
|
const std::string& getScriptCode() noexcept {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::python::object& getPyObject() noexcept {
|
||||||
|
return gContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python implementation of Script.
|
||||||
|
*/
|
||||||
|
class PyScript
|
||||||
|
: public virtual service::scripting::Script {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PyScriptingService* service;
|
||||||
|
std::string code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PyScript(PyScriptingService* service, const std::string& code)
|
||||||
|
: code(code), service(service) {}
|
||||||
|
|
||||||
|
|
||||||
|
/* Public Service Implementations */
|
||||||
|
|
||||||
|
virtual void execute( std::shared_ptr<GlobalScriptContext> gContext = std::shared_ptr<GlobalScriptContext>(),
|
||||||
|
const libvariant::Variant& lContext = libvariant::Variant() ) override;
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
|
||||||
|
const std::string& getScriptCode() noexcept {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of device repository service
|
||||||
|
**/
|
||||||
|
class PyScriptingService
|
||||||
|
: public virtual service::scripting::ScriptingService,
|
||||||
|
public virtual implementation::Service<PyScriptingService> {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::recursive_mutex serviceMutex;
|
||||||
|
|
||||||
|
service::core::CoreService* coreService = nullptr;;
|
||||||
|
devicerepository::DeviceRepositoryService* repoService = nullptr;;
|
||||||
|
ros::NodeHandle* nodehandle = nullptr;
|
||||||
|
|
||||||
|
boost::python::object pyGlobalScope;
|
||||||
|
std::unique_ptr<hosapi::PyDeviceRepositoryWrapper> deviceService;
|
||||||
|
|
||||||
|
bool initialized = false;
|
||||||
|
|
||||||
|
void init() noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Language identifier. */
|
||||||
|
static constexpr const char* LANGUAGE = "python";
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialization */
|
||||||
|
|
||||||
|
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||||
|
void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/* Public Service Implementations */
|
||||||
|
|
||||||
|
virtual const char* getLanguage() noexcept override {
|
||||||
|
return LANGUAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::shared_ptr<scripting::GlobalScriptContext> createGlobalScriptContext(const Variant& raw) override;
|
||||||
|
|
||||||
|
virtual std::shared_ptr<scripting::Script> createScript(const Variant& raw) override;
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
|
||||||
|
bool isInitialized() noexcept {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::python::object& getPyDefaultScrope() noexcept {
|
||||||
|
return pyGlobalScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
hosapi::PyDeviceRepositoryWrapper* getDeviceService() noexcept {
|
||||||
|
return deviceService.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace python
|
||||||
|
} // namespace scripting
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "PyHOSAPI.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python HOS API declaration.
|
||||||
|
*/
|
||||||
|
BOOST_PYTHON_MODULE(hos)
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace boost::python;
|
||||||
|
using namespace hos::cosgi::service::scripting::python::hosapi;
|
||||||
|
|
||||||
|
// Device class
|
||||||
|
class_<PyDeviceWrapper>("Device", no_init)
|
||||||
|
.def("deviceID", &PyDeviceWrapper::deviceID)
|
||||||
|
.def("sendCommand", &PyDeviceWrapper::sendCommand);
|
||||||
|
|
||||||
|
// Device Repository class.
|
||||||
|
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
||||||
|
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice)
|
||||||
|
.def("__getitem__", &PyDeviceRepositoryWrapper::getDevice)
|
||||||
|
.def("__len__", &PyDeviceRepositoryWrapper::deviceCount)
|
||||||
|
.def("keys", &PyDeviceRepositoryWrapper::deviceIDs);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
+47
-30
@@ -1,53 +1,72 @@
|
|||||||
/*
|
|
||||||
* PyHOSAPI.h
|
|
||||||
*
|
|
||||||
* Created on: 19.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
#pragma once
|
||||||
#define SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function declares the python hos module.
|
||||||
|
*/
|
||||||
|
extern "C" void inithos();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
namespace python {
|
namespace python {
|
||||||
|
namespace hosapi {
|
||||||
class PyScriptingService;
|
|
||||||
|
|
||||||
|
|
||||||
boost::python::object convertVariantToBoostPython(Variant var);
|
|
||||||
|
|
||||||
Variant convertBoostPythonTovariant(boost::python::object obj);
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python HOS API wrapper for devicerepository::Device.
|
||||||
|
*/
|
||||||
class PyDeviceWrapper {
|
class PyDeviceWrapper {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
devicerepository::Device* device;
|
devicerepository::Device* device;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PyDeviceWrapper(devicerepository::Device* device) : device(device) {}
|
|
||||||
|
|
||||||
std::string deviceID() { return device->getDeviceID(); }
|
PyDeviceWrapper(devicerepository::Device* device)
|
||||||
|
: device(device) {}
|
||||||
|
|
||||||
void sendCommand(boost::python::object cmd) {
|
const std::string deviceID() noexcept {
|
||||||
device->sendCommand(convertBoostPythonTovariant(cmd));
|
return device->getDeviceID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendCommand(const boost::python::object& cmd) {
|
||||||
|
device->sendCommand(utils::convertBoostPythonTovariant(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PyDeviceRepositoryWrapper {
|
|
||||||
private:
|
|
||||||
devicerepository::DeviceRepositoryService* service;
|
|
||||||
public:
|
|
||||||
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service) : service(service) {}
|
|
||||||
|
|
||||||
PyDeviceWrapper getDevice(std::string name) {
|
/**
|
||||||
|
* Python HOS API wrapper for devicerepository::DeviceRepositoryService.
|
||||||
|
*/
|
||||||
|
class PyDeviceRepositoryWrapper {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
devicerepository::DeviceRepositoryService* service;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PyDeviceRepositoryWrapper(devicerepository::DeviceRepositoryService* service)
|
||||||
|
: service(service) {}
|
||||||
|
|
||||||
|
PyDeviceWrapper getDevice(const std::string& name) {
|
||||||
return PyDeviceWrapper(service->getDevice(name).lock().get());
|
return PyDeviceWrapper(service->getDevice(name).lock().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,17 +81,15 @@ public:
|
|||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" void inithos();
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace hosapi
|
||||||
} // namespace python
|
} // namespace python
|
||||||
} // namespace scripting
|
} // namespace scripting
|
||||||
} // namespace service
|
} // namespace service
|
||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
} // namespace hos
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_PYHOSAPI_H_ */
|
|
||||||
-111
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* hos_cosgi_ruleexecution_python_impl.h
|
|
||||||
*
|
|
||||||
* Created on: 01.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_
|
|
||||||
#define SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_
|
|
||||||
|
|
||||||
#include <ros/ros.h>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
|
||||||
#include <hos/cosgi/service/Implementation.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace core {
|
|
||||||
class CoreService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace scripting {
|
|
||||||
namespace python {
|
|
||||||
|
|
||||||
class PyScriptingService;
|
|
||||||
using namespace ::libvariant;
|
|
||||||
|
|
||||||
class PyGlobalScriptContext : public virtual service::scripting::GlobalScriptContext {
|
|
||||||
private:
|
|
||||||
boost::python::object& gContext;
|
|
||||||
std::string code;
|
|
||||||
public:
|
|
||||||
PyGlobalScriptContext(boost::python::object& gContext, std::string code)
|
|
||||||
: gContext(gContext), code(code) {}
|
|
||||||
std::string getCode() { return code; }
|
|
||||||
boost::python::object& getPyGlobalContext() { return gContext; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PyScript : public virtual service::scripting::Script {
|
|
||||||
private:
|
|
||||||
std::string code;
|
|
||||||
PyScriptingService& service;
|
|
||||||
public:
|
|
||||||
PyScript(std::string code, PyScriptingService& service) : code(code), service(service) {}
|
|
||||||
std::string getCode() { return code; }
|
|
||||||
virtual void exec(service::scripting::GlobalScriptContext* gContext, Variant lContext = Variant());
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PyScriptingService;
|
|
||||||
class PyScriptingService : public virtual service::scripting::ScriptingService, public virtual implementation::Service<PyScriptingService> {
|
|
||||||
private:
|
|
||||||
service::core::CoreService* coreService = nullptr;;
|
|
||||||
devicerepository::DeviceRepositoryService* repoService = nullptr;;
|
|
||||||
ros::NodeHandle* nodehandle = nullptr;
|
|
||||||
|
|
||||||
boost::python::object pyGlobalScope;
|
|
||||||
|
|
||||||
bool initialized = false;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr const char* LANGUAGE = "python";
|
|
||||||
|
|
||||||
/* Initialization */
|
|
||||||
|
|
||||||
void setCoreService(service::core::CoreService* coreService);
|
|
||||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
|
||||||
|
|
||||||
/* Public Service Implementations */
|
|
||||||
virtual std::string getLanguage() { return LANGUAGE; }
|
|
||||||
|
|
||||||
virtual std::shared_ptr<scripting::GlobalScriptContext> createGlobalScriptContext(Variant raw);
|
|
||||||
virtual std::shared_ptr<scripting::Script> createScript(scripting::GlobalScriptContext* gContext, Variant raw);
|
|
||||||
|
|
||||||
/* Internal Stuff */
|
|
||||||
|
|
||||||
bool isInitialized() { return initialized; }
|
|
||||||
|
|
||||||
boost::python::object& getPyGlobalScope() { return pyGlobalScope; }
|
|
||||||
|
|
||||||
devicerepository::DeviceRepositoryService* getDeviceRepository() { return repoService; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace python
|
|
||||||
} // namespace scripting
|
|
||||||
} // namespace service
|
|
||||||
} // namespace cosgi
|
|
||||||
} // namespace hos
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_HOS_COSGI_SERVICE_SCRIPTING_PYTHON_SCRIPTING_SERVICEIMPL_H_ */
|
|
||||||
+19
-36
@@ -1,39 +1,21 @@
|
|||||||
/*
|
|
||||||
* PyHOSAPI.cpp
|
#include "utils.h"
|
||||||
*
|
#include "ros/ros.h"
|
||||||
* Created on: 19.05.2015
|
|
||||||
* Author: matzman
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "PyHOSAPI.h"
|
// main namespace
|
||||||
#include <ros/ros.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace scripting {
|
namespace scripting {
|
||||||
namespace python {
|
namespace python {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE(hos)
|
|
||||||
{
|
|
||||||
using namespace boost::python;
|
|
||||||
|
|
||||||
class_<PyDeviceWrapper>("Device", no_init)
|
|
||||||
.def("deviceID", &PyDeviceWrapper::deviceID)
|
|
||||||
.def("sendCommand", &PyDeviceWrapper::sendCommand) ;
|
|
||||||
|
|
||||||
class_<PyDeviceRepositoryWrapper>("DeviceRepository", no_init)
|
boost::python::object convertVariantToBoostPython(const libvariant::Variant& var) noexcept {
|
||||||
.def("getDevice", &PyDeviceRepositoryWrapper::getDevice)
|
|
||||||
.def("__getitem__", &PyDeviceRepositoryWrapper::getDevice)
|
|
||||||
.def("__len__", &PyDeviceRepositoryWrapper::deviceCount)
|
|
||||||
.def("keys", &PyDeviceRepositoryWrapper::deviceIDs) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::python::object convertVariantToBoostPython(Variant var) {
|
|
||||||
if (var.IsBool()) {
|
if (var.IsBool()) {
|
||||||
return boost::python::object(var.AsBool());
|
return boost::python::object(var.AsBool());
|
||||||
} else if (var.IsFloat()) {
|
} else if (var.IsFloat()) {
|
||||||
@@ -63,45 +45,46 @@ boost::python::object convertVariantToBoostPython(Variant var) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Variant convertBoostPythonTovariant(boost::python::object obj) {
|
libvariant::Variant convertBoostPythonTovariant(const boost::python::object& obj) noexcept {
|
||||||
Variant retval;
|
libvariant::Variant retval;
|
||||||
if (!obj.is_none()) {
|
if (!obj.is_none()) {
|
||||||
if (PyObject_TypeCheck(obj.ptr(), &PyString_Type)) {
|
if (PyObject_TypeCheck(obj.ptr(), &PyString_Type)) {
|
||||||
retval = Variant(boost::python::extract<std::string>(obj));
|
retval = libvariant::Variant(boost::python::extract<std::string>(obj));
|
||||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyBool_Type)) {
|
} else if (PyObject_TypeCheck(obj.ptr(), &PyBool_Type)) {
|
||||||
retval = Variant(boost::python::extract<bool>(obj));
|
retval = libvariant::Variant(boost::python::extract<bool>(obj));
|
||||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyFloat_Type)) {
|
} else if (PyObject_TypeCheck(obj.ptr(), &PyFloat_Type)) {
|
||||||
retval = Variant(boost::python::extract<double>(obj));
|
retval = libvariant::Variant(boost::python::extract<double>(obj));
|
||||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyInt_Type)) {
|
} else if (PyObject_TypeCheck(obj.ptr(), &PyInt_Type)) {
|
||||||
retval = Variant(boost::python::extract<int>(obj));
|
retval = libvariant::Variant(boost::python::extract<int>(obj));
|
||||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyDict_Type)) {
|
} else if (PyObject_TypeCheck(obj.ptr(), &PyDict_Type)) {
|
||||||
boost::python::dict dict = boost::python::extract<boost::python::dict>(obj);
|
boost::python::dict dict = boost::python::extract<boost::python::dict>(obj);
|
||||||
for (int i = 0; i < boost::python::len(dict); i++) {
|
for (int i = 0; i < boost::python::len(dict); i++) {
|
||||||
auto k = dict.keys()[i];
|
auto k = dict.keys()[i];
|
||||||
Variant key = convertBoostPythonTovariant(k);
|
libvariant::Variant key = convertBoostPythonTovariant(k);
|
||||||
Variant value = convertBoostPythonTovariant(dict[k]);
|
libvariant::Variant value = convertBoostPythonTovariant(dict[k]);
|
||||||
retval[key.AsString()] = value;
|
retval[key.AsString()] = value;
|
||||||
}
|
}
|
||||||
} else if (PyObject_TypeCheck(obj.ptr(), &PyList_Type)) {
|
} else if (PyObject_TypeCheck(obj.ptr(), &PyList_Type)) {
|
||||||
boost::python::list list = boost::python::extract<boost::python::list>(obj);
|
boost::python::list list = boost::python::extract<boost::python::list>(obj);
|
||||||
for (int i = 0; i < boost::python::len(list); i++) {
|
for (int i = 0; i < boost::python::len(list); i++) {
|
||||||
auto v = list[i];
|
auto v = list[i];
|
||||||
Variant value = convertBoostPythonTovariant(v);
|
libvariant::Variant value = convertBoostPythonTovariant(v);
|
||||||
retval.Append(value);
|
retval.Append(value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ROS_ERROR("Unknown PyObject type encountered while converting to Variant");
|
ROS_ERROR("Unknown PyObject type encountered while converting to Variant");
|
||||||
return Variant();
|
return libvariant::Variant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
} // namespace python
|
} // namespace python
|
||||||
} // namespace scripting
|
} // namespace ruleengine
|
||||||
} // namespace service
|
} // namespace service
|
||||||
} // namespace cosgi
|
} // namespace cosgi
|
||||||
} // namespace hos
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/python.hpp>
|
||||||
|
#include <Variant/Variant.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// main namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace scripting {
|
||||||
|
namespace python {
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Variant into a boost::python::object.
|
||||||
|
*
|
||||||
|
* \param[in] variant object.
|
||||||
|
* \return boost python object.
|
||||||
|
*/
|
||||||
|
boost::python::object convertVariantToBoostPython(const libvariant::Variant& var) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a boost::python::object into a Variant.
|
||||||
|
*
|
||||||
|
* \param[in] boost python object.
|
||||||
|
* \return variant object.
|
||||||
|
*/
|
||||||
|
libvariant::Variant convertBoostPythonTovariant(const boost::python::object& obj) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace python
|
||||||
|
} // namespace ruleengine
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
+7
-2
@@ -80,8 +80,13 @@ void DevicesHTTPResource::render_GET(const httpserver::http_request& req, httpse
|
|||||||
for (int i = prefixPathPieces+1; i < req.get_path_pieces_size(); i++) {
|
for (int i = prefixPathPieces+1; i < req.get_path_pieces_size(); i++) {
|
||||||
path.push_back(req.get_path_piece(i));
|
path.push_back(req.get_path_piece(i));
|
||||||
}
|
}
|
||||||
setDeviceState(device.lock().get(), setValue, path);
|
try {
|
||||||
*res = new http_response(http_response_builder("OK", 200).string_response());
|
setDeviceState(device.lock().get(), setValue, path);
|
||||||
|
*res = new http_response(http_response_builder("OK", 200).string_response());
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
auto msg = (boost::format("ERROR: %1%") % e.what()).str();
|
||||||
|
*res = new http_response(http_response_builder(msg , 400).string_response());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string info;
|
std::string info;
|
||||||
if (req.get_path_pieces_size() > prefixPathPieces+1) {
|
if (req.get_path_pieces_size() > prefixPathPieces+1) {
|
||||||
|
|||||||
@@ -14,16 +14,22 @@ namespace utils {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SchemaLoader: public libvariant::SchemaLoader {
|
class SchemaLoader
|
||||||
|
: public libvariant::SchemaLoader {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ros_param_ns;
|
std::string ros_param_ns;
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
ros::NodeHandle nodeHandle;
|
ros::NodeHandle nodeHandle;
|
||||||
|
|
||||||
bool loadTypeSchema(std::string schema);
|
bool loadTypeSchema(std::string schema);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SchemaLoader(std::string ns = "/hos/types/repository", std::string prefix = "hos:schema://")
|
SchemaLoader(const std::string& ns = "/hos/types/repository", const std::string& prefix = "hos:schema://")
|
||||||
: ros_param_ns(ns), prefix(prefix), nodeHandle("~") {}
|
: ros_param_ns(ns), prefix(prefix), nodeHandle("~") {}
|
||||||
virtual bool HandleMissing(const std::string &uri, LoaderError &error);
|
|
||||||
|
virtual bool HandleMissing(const std::string &uri, LoaderError &error) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user