blob: 429dc6404efab0983e790a3af4dde2fadc62cf90 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 - 2018 fortiss GmbH
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Johannes Messmer - initial API and implementation and/or initial documentation
* Jose Cabral - Cleaning of namespaces
*******************************************************************************/
#ifndef SRC_CORE_IO_DEVICE_CONTROLLER_H_
#define SRC_CORE_IO_DEVICE_CONTROLLER_H_
#include <extevhan.h>
#include <forte_sync.h>
#include <forte_thread.h>
#include <devlog.h>
#include <fortelist.h>
#include <io/mapper/io_handle.h>
namespace forte {
namespace core {
namespace io {
class IOConfigFBController;
/*! @brief Abstract Device Controller
*
* Base class of the device controller implementation.
* All hardware specific IO implementations should inherit from this class.
*
* Features:
* - runs Device Controller in separate thread
* - thread safe communication with corresponding controller configuration fb (see #notifyConfigFB)
* - base structure for safe startups and resets (see #init, #runLoop, and #deInit)
* - automatic error handling and restart (see #IOConfigFBController)
*/
class IODeviceController : protected CExternalEventHandler, protected CThread {
friend class IOConfigFBController;
public:
/*! @brief Abstract configuration struct.
*
* The child controller should implement an own configuration struct, which inherits from this struct and is initialized with default parameters.
* The controller configuration fb uses the #setConfig method to set the runtime configuration.
*/
struct Config {
};
/*! @brief Abstract descriptor of device handles.
*
* Used to exchange information about handles between the device controller and the corresponding configuration fb.
* The device implementation should extend the struct with properties, which uniquely identify the handle.
* The #initHandle method then creates an #IOHandle instance based on the handle descriptor.
*/
class HandleDescriptor {
public:
CIEC_WSTRING const &mId;
IOMapper::Direction mDirection;
HandleDescriptor(CIEC_WSTRING const &paId, IOMapper::Direction paDirection) :
mId(paId), mDirection(paDirection) {
}
};
enum NotificationType {
UnknownNotificationType,
//! Notifies the configuration fb about a successful operation e.g. a successful startup.
Success,
//! Notifies the configuration about an error. It should be emitted during the init method or the runLoop method.
Error,
//! Placeholder for custom hardware specific communication between the device and configuration fb controller.
Custom
};
NotificationType mNotificationType;
const void* mNotificationAttachment;
bool mNotificationHandled;
/*! @brief Sets the configuration of the controller
*
* @param paConfig Pointer to the configuration struct provided by the corresponding controller configuration fb. Use *static_cast<CustomConfig*>(config) to retrieve the struct instance.
*/
virtual void setConfig(Config* paConfig) = 0;
void fireIndicationEvent(IOObserver *paObserver);
virtual void handleChangeEvent(IOHandle *paHandle);
//TODO: adapt this properly to the new handler model. This mockup is just to avoid the classes below to be abstract
virtual size_t getIdentifier() const {
return 0;
}
protected:
explicit IODeviceController(CDeviceExecution& paDeviceExecution);
/*! @brief Initializes the controller.
*
* The method should initialize and startup the controller.
* All required hardware libraries should be started and checked for errors.
* If the system requires an initialization sequence which is executed once at startup, place it here.
* In case of an error, return an error description.
*
* @return 0/NULL if the initialization was successful. Otherwise return an error description.
*/
virtual const char* init() = 0;
/*! @brief Contains the blocking run sequence.
*
* The method should implement the algorithm, which sets and gets the state of the hardware handles.
* In case of a runtime error, set the #error property.
* It should always check if the controller is still active (#isAlive method).
* If the controller got inactive or an error occurred, the method should return.
*
* @attention Never use While(true) loops without any sleep methods. They would consume all processing power and slow down FORTE.
*/
virtual void runLoop() = 0;
/*! @brief Deinitializes the controller.
*
* Stops all initialized hardware libraries.
* Frees the allocated resources of the controller.
*/
virtual void deInit() = 0;
bool hasError() const;
const char* mError;
/*! @brief Notifies the corresponding configuration fb about a startup or runtime event.
*
* The method should not be used for time critical operations, such as a write operation of an output fb.
* You should avoid multiple messages in a short time period, as notifications are not yet queued but dropped.
*
* @param paType Type of notification
* @param paAttachment Attachment of notification. E.g. a const* char pointer should be attached to an Error notification.
*/
void notifyConfigFB(NotificationType paType, const void* paAttachment = 0);
typedef CSinglyLinkedList<IOHandle *> THandleList;
/*! @brief Adds an IO handle to the controller
*
* This method is called by the corresponding configuration function block during the initialization.
* The handle is automatically added to the correct list (#inputHandles and #outputHandles).
* The handle lists should be accessed by the controller to read and write IOs.
*
* @param paHandleDescriptor Descriptor of the handle
*/
virtual void addHandle(HandleDescriptor *paHandleDescriptor);
/*! @brief Initializer for all IO handles.
*
* The method is called when a configuration fb adds an handle via the #addHandle method.
* It should return an handle instance based on the descriptor information.
*
* @param paHandleDescriptor Descriptor of the handle
*/
virtual IOHandle* initHandle(HandleDescriptor *paHandleDescriptor) = 0;
/*! @brief Iterates over all input handles and fires an indication event in case of a change.
*
* The method iterates over the #inputHandles list.
* It checks if the input handle has a bound observer and then calls the #isHandleValueEqual method.
* If the #isHandleValueEqual returns true, the indication event is fired for the bound observer.
* @attention The method does only work if the #isHandleValueEqual is overridden.
*/
void checkForInputChanges();
/*! @brief Checks if the value of a handle has changed. Used by the #checkForInputChanges method.
*
* @param paHandle IOHandle which should be compared to the previous IO state
* @return True if the current state is equal to the previous IO state. In case it has changed, return false.
*/
virtual bool isHandleValueEqual(IOHandle* paHandle);
/*! @brief Synchronizes the access to the #inputHandles and #outputHandles. Use it for iterations over the lists. */
CSyncObject mHandleMutex;
/*! @brief All input handles of the main controller
* The list should only contain input handles of the main controller.
* The list is managed by the #addHandle and #dropHandles method.
* #dropHandles is called automatically during deinitialization.
*/
THandleList mInputHandles;
/*! @brief All output handles of the main controller
* The list should only contain output handles of the main controller.
* The list is managed by the #addHandle and #dropHandles method.
* #dropHandles is called automatically during deinitialization.
*/
THandleList mOutputHandles;
private:
IOConfigFBController *mDelegate;
/*! @brief Drops all handle instances which were previously added by the #addHandle method
*
* The method is automatically called during the deinitialization of the corresponding configuration function block.
*/
void dropHandles();
void run();
void setInitDelay(int paDelay);
int mInitDelay;
void addHandle(THandleList* paList, CIEC_WSTRING const &paId, IOHandle* paHandle);
// Functions needed for the external event handler interface
void enableHandler(void) {
//do nothing
}
void disableHandler(void) {
//do nothing
}
void setPriority(int) {
//do nothing
}
int getPriority(void) const {
return 0;
}
};
} //namespace IO
} //namepsace core
} //namespace forte
#endif /* SRC_CORE_IO_DEVICE_CONTROLLER_H_ */