- DataTreeCore: - Rename all Get/SetChild...() methods to Get/SetMem...() - Update all other objects with new methods
597 lines
17 KiB
C++
597 lines
17 KiB
C++
/*
|
|
* FunctionCore.cpp
|
|
*
|
|
* Created on: 18 May 2016
|
|
* Author: wentzelc
|
|
*/
|
|
|
|
// Standard C/C++ Libraries
|
|
/* none */
|
|
|
|
// redA Libraries
|
|
#include "ApplicationCore.h"
|
|
#include "FunctionCore.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Global Vars
|
|
extern char * ProcessName;
|
|
extern CApplication * Application;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Life cycle
|
|
CFunctionCore::CFunctionCore( const char * pName, const char * pType )
|
|
{
|
|
// Set name
|
|
if (pName) {
|
|
Name = (char*)malloc( strlen(pName)+1 );
|
|
strcpy( Name, pName );
|
|
}
|
|
else {
|
|
Name = NULL;
|
|
}
|
|
|
|
// Set Type
|
|
if (pType) {
|
|
Type = (char*)malloc( strlen(pType)+1 );
|
|
strcpy( Type, pType );
|
|
}
|
|
else {
|
|
Type = NULL;
|
|
}
|
|
|
|
// Channels
|
|
FirstChannel = NULL;
|
|
|
|
// List
|
|
Application->AddFunction( this );
|
|
|
|
// Data Tree
|
|
DataTree = Application->DataTree;
|
|
ConfigMember = NULL;
|
|
LinkConfigMember = NULL;
|
|
|
|
// Logging
|
|
Log = Application->Log;
|
|
LogLevel = dlNone;
|
|
LogOutput = OUT_NORMAL;
|
|
|
|
// Stored output
|
|
StoredOutput = NULL;
|
|
StoredOutputLen = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CFunctionCore::~CFunctionCore()
|
|
{
|
|
TChannel * NextChannel = NULL;
|
|
TChannelLink * NextLinkedChannel = NULL;
|
|
|
|
// Destroy Channels
|
|
while (FirstChannel)
|
|
{
|
|
// Destroy Parameters
|
|
if (FirstChannel->Name) {
|
|
free( FirstChannel->Name );
|
|
}
|
|
|
|
// Destroy Linked Inputs
|
|
while (FirstChannel->FirstInput) {
|
|
if (FirstChannel->FirstInput->Name) {
|
|
free( FirstChannel->FirstInput->Name );
|
|
}
|
|
NextLinkedChannel = FirstChannel->FirstInput->Next;
|
|
free( FirstChannel->FirstInput );
|
|
FirstChannel->FirstInput = NextLinkedChannel;
|
|
}
|
|
|
|
// Destroy Linked Outputs
|
|
while (FirstChannel->FirstOutput) {
|
|
if (FirstChannel->FirstOutput->Name) {
|
|
free( FirstChannel->FirstOutput->Name );
|
|
}
|
|
NextLinkedChannel = FirstChannel->FirstOutput->Next;
|
|
free( FirstChannel->FirstOutput );
|
|
FirstChannel->FirstOutput = NextLinkedChannel;
|
|
}
|
|
|
|
// Destroy Channel
|
|
NextChannel = FirstChannel->Next;
|
|
free( FirstChannel );
|
|
FirstChannel = NextChannel;
|
|
}
|
|
|
|
// Report status
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Function '%s' - Destroyed", ProcessName, Name );
|
|
|
|
// Destroy Name
|
|
if (Name) free( Name );
|
|
if (Type) free( Type );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::LoadConfigData()
|
|
{
|
|
CDataMember * TempMember;
|
|
EDebugLevel pLogLevel;
|
|
int pLogOutput;
|
|
char * TempStr;
|
|
|
|
// Get debug level
|
|
pLogLevel = dlNone;
|
|
TempStr = (char*)ConfigMember->GetMemStr( "Log/Level", "Medium", true );
|
|
if (TempStr)
|
|
{
|
|
if (!strcasecmp( TempStr, "Low" ))
|
|
pLogLevel = dlLow;
|
|
else if (!strcasecmp( TempStr, "Medium" ))
|
|
pLogLevel = dlMedium;
|
|
else if (!strcasecmp( TempStr, "High" ))
|
|
pLogLevel = dlHigh;
|
|
}
|
|
|
|
// Set debug output
|
|
pLogOutput = 0;
|
|
if ((TempMember = ConfigMember->GetMember( "Log/Output", true )))
|
|
{
|
|
TempMember = TempMember->GetFirstChild();
|
|
while (TempMember)
|
|
{
|
|
if ((TempStr = (char*)TempMember->GetStr()))
|
|
{
|
|
if (!strcasecmp( TempStr, "Normal"))
|
|
pLogOutput |= OUT_NORMAL;
|
|
else if (!strcasecmp( TempStr, "Bin"))
|
|
pLogOutput |= OUT_BIN;
|
|
else if (!strcasecmp( TempStr, "Hex"))
|
|
pLogOutput |= OUT_HEX;
|
|
else if (!strcasecmp( TempStr, "Count"))
|
|
pLogOutput |= OUT_COUNT;
|
|
else if (!strcasecmp( TempStr, "AsIs"))
|
|
pLogOutput |= OUT_ASIS;
|
|
else if (!strcasecmp( TempStr, "CRLF"))
|
|
pLogOutput |= OUT_CRLF;
|
|
}
|
|
|
|
// Next
|
|
TempMember = TempMember->GetNextPeer();
|
|
}
|
|
}
|
|
|
|
// Set Logging
|
|
SetLogParam( pLogLevel, pLogOutput );
|
|
|
|
// Load Channels
|
|
TempMember = ConfigMember->GetMemFirstChild( "Channels" );
|
|
while (TempMember)
|
|
{
|
|
if (TempMember->GetName()) {
|
|
AddChannel( TempMember->GetName(),
|
|
TempMember->GetMemBool( "InputEnabled", true, true ),
|
|
TempMember->GetMemBool( "OutputEnabled", false, true ));
|
|
}
|
|
|
|
// Next
|
|
TempMember = TempMember->GetNextPeer();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::LoadChannelLinkData()
|
|
{
|
|
TChannel * Channel;
|
|
CDataMember * ChannelMember;
|
|
CDataMember * FunctionMember;
|
|
|
|
// Process each Channel
|
|
ChannelMember = LinkConfigMember->GetFirstChild();
|
|
while (ChannelMember)
|
|
{
|
|
if ((Channel = GetChannel( ChannelMember->GetName() )))
|
|
{
|
|
FunctionMember = ChannelMember->GetFirstChild();
|
|
while (FunctionMember)
|
|
{
|
|
// Get Parameters
|
|
LinkOutputChannel( Channel->Name,
|
|
FunctionMember->GetMemStr( "Function" ),
|
|
FunctionMember->GetMemStr( "Channel" ),
|
|
FunctionMember->GetMemBool( "Bidirectional" ) );
|
|
// Next
|
|
FunctionMember = FunctionMember->GetNextPeer();
|
|
}
|
|
}
|
|
// Next
|
|
ChannelMember = ChannelMember->GetNextPeer();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::Init()
|
|
{
|
|
// Report status
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Function '%s' - Initialised", ProcessName, Name );
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::InitConfig( const char * pConfigPath )
|
|
{
|
|
// Validate
|
|
if (!DataTree || !(ConfigMember = DataTree->GetMember( pConfigPath, true )))
|
|
return false;
|
|
|
|
// Load configuration
|
|
LoadConfigData();
|
|
Init();
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::InitConfig( CDataMember * pBaseMember )
|
|
{
|
|
// Validate
|
|
if (!DataTree || !(ConfigMember = pBaseMember ))
|
|
return false;
|
|
|
|
// Load configuration
|
|
LoadConfigData();
|
|
Init();
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::InitChannelLinks( const char * pLinkConfigPath )
|
|
{
|
|
// Validate
|
|
if (!DataTree || !(LinkConfigMember = DataTree->GetMember( pLinkConfigPath, true )))
|
|
return false;
|
|
|
|
// Load configuration
|
|
LoadChannelLinkData();
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::InitChannelLinks( CDataMember *pLinkConfigMember )
|
|
{
|
|
// Validate
|
|
if (!DataTree || !(LinkConfigMember = pLinkConfigMember))
|
|
return false;
|
|
|
|
// Load configuration
|
|
LoadChannelLinkData();
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::SetLogParam( EDebugLevel pDebugLevel, int pOutputDisplay )
|
|
{
|
|
// Output
|
|
LogLevel = pDebugLevel;
|
|
LogOutput = pOutputDisplay;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel )
|
|
{
|
|
LogLevel = pDebugLevel;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInputEnable, const bool pOutputEnable )
|
|
{
|
|
TChannel ** Channel = NULL;
|
|
|
|
// Validate
|
|
if (!ChannelName) {
|
|
return NULL;
|
|
}
|
|
|
|
// Check if exists
|
|
Channel = &FirstChannel;
|
|
while (*Channel && strcmp( ChannelName, (*Channel)->Name )) {
|
|
Channel = &((*Channel)->Next);
|
|
}
|
|
|
|
// Create if not exist
|
|
if (!*Channel) {
|
|
// Create
|
|
*Channel = (TChannel*)malloc( sizeof(TChannel) );
|
|
memset( *Channel, 0, sizeof(TChannel) );
|
|
|
|
// Set Name
|
|
(*Channel)->Name = (char*)malloc( strlen(ChannelName)+1 );
|
|
strcpy( (*Channel)->Name, ChannelName );
|
|
|
|
// Log Event
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Channel '%s' - Created", Name, ChannelName );
|
|
}
|
|
|
|
// Set parameters
|
|
(*Channel)->InputEnabled = pInputEnable;
|
|
(*Channel)->OutputEnabled = pOutputEnable;
|
|
|
|
return *Channel;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Automated Data Input/Output
|
|
bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional )
|
|
{
|
|
CFunctionCore * OutFunction = NULL;
|
|
TChannel * Channel = NULL;
|
|
TChannelLink ** LinkedChannel = NULL;
|
|
|
|
// Get Channel
|
|
if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) {
|
|
return false;
|
|
}
|
|
|
|
// Check if linked Channel exists
|
|
LinkedChannel = &(Channel->FirstInput);
|
|
while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) {
|
|
LinkedChannel = &((*LinkedChannel)->Next);
|
|
}
|
|
|
|
// Create if not found
|
|
if (!*LinkedChannel)
|
|
{
|
|
// Create
|
|
*LinkedChannel = (TChannelLink*)malloc( sizeof(TChannelLink) );
|
|
memset( *LinkedChannel, 0, sizeof( TChannelLink ));
|
|
|
|
// Set Parameters
|
|
(*LinkedChannel)->Function = OutFunction;
|
|
(*LinkedChannel)->Name = (char*)malloc( strlen(OutChannelName)+1 );
|
|
strcpy( (*LinkedChannel)->Name, OutChannelName );
|
|
|
|
// Log Event
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Input Linked - '%s'/'%s' <-- '%s'/'%s'", Name, Name, ChannelName, OutFunction->GetName(), OutChannelName );
|
|
}
|
|
|
|
// Link Return direction as well
|
|
if (Bidirectional) {
|
|
return OutFunction->LinkInputChannel( OutChannelName, Name, ChannelName, false );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional )
|
|
{
|
|
TChannel * OutChannel = NULL;
|
|
CFunctionCore * InFunction = NULL;
|
|
TChannel * InChannel = NULL;
|
|
TChannelLink ** LinkedChannel = NULL;
|
|
|
|
// Check if Channels & Function exist
|
|
if (!(OutChannel = GetChannel( ChannelName )) ||
|
|
!(InFunction = Application->GetFunction( InFunctionName )) ||
|
|
!(InChannel = InFunction->GetChannel( InChannelName )) ) {
|
|
return false;
|
|
}
|
|
|
|
// Check if linked Channel exists
|
|
LinkedChannel = &(OutChannel->FirstOutput);
|
|
while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) {
|
|
LinkedChannel = &((*LinkedChannel)->Next);
|
|
}
|
|
|
|
// Create if not found
|
|
if (!*LinkedChannel)
|
|
{
|
|
// Create
|
|
*LinkedChannel = (TChannelLink*)malloc( sizeof(TChannelLink) );
|
|
memset( *LinkedChannel, 0, sizeof( TChannelLink ));
|
|
|
|
// Set Parameters
|
|
(*LinkedChannel)->Function = InFunction;
|
|
(*LinkedChannel)->Name = (char*)malloc( strlen(InChannelName)+1 );
|
|
strcpy( (*LinkedChannel)->Name, InChannelName );
|
|
|
|
// Log Event
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Output Linked - '%s'/'%s' --> '%s'/'%s'", Name, Name, ChannelName, InFunction->GetName(), InChannelName );
|
|
}
|
|
|
|
// Link return direction as well
|
|
if (Bidirectional) {
|
|
return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Manual Data Input/Output
|
|
int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len )
|
|
{
|
|
TChannel * Channel = NULL;
|
|
|
|
// Validate
|
|
if (!ChannelName || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Get Channel
|
|
if (!(Channel = GetChannel( ChannelName ))) {
|
|
// Channel not found
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Input rejected, Channel not found", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
else if (!Channel->InputEnabled) {
|
|
// Channel disabled
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Input rejected, Channel input disabled", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
else {
|
|
// Return processed bytes
|
|
if (Len == -1) {
|
|
Len = strlen( Data );
|
|
}
|
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Channel '%s' - IN:", Name, ChannelName );
|
|
return Len;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFunctionCore::Output( const char * ChannelName, const char * Data, int Len )
|
|
{
|
|
TChannel * Channel = NULL;
|
|
|
|
// Validate
|
|
if (!ChannelName) {
|
|
return 0;
|
|
}
|
|
|
|
// Get Channel
|
|
if (!(Channel = GetChannel( ChannelName ))) {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Output rejected, Channel not found", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
else {
|
|
// Return processed bytes
|
|
return Output( Channel, Data, Len );
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len )
|
|
{
|
|
TChannelLink * OutChannel = NULL;
|
|
int TempLen = 0;
|
|
int OutLen = 0;
|
|
|
|
// Validate
|
|
if (!Channel || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Check if enabled
|
|
if (!Channel->OutputEnabled) {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Output rejected, Channel output disabled", Name, Channel->Name );
|
|
return 0;
|
|
}
|
|
|
|
// Log event
|
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s: Channel '%s' - OUT:", Name, Channel->Name );
|
|
|
|
// Pass output to all linked inputs
|
|
if (Len == -1) {
|
|
Len = strlen( Data );
|
|
}
|
|
OutChannel = Channel->FirstOutput;
|
|
while (OutChannel) {
|
|
TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len );
|
|
OutLen = (TempLen > OutLen)? TempLen : OutLen;
|
|
OutChannel = OutChannel->Next;
|
|
}
|
|
|
|
// Return processed bytes
|
|
return OutLen;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::PullInput( const char * ChannelName )
|
|
{
|
|
TChannel * Channel = NULL;
|
|
|
|
// Validate
|
|
if (!ChannelName) {
|
|
return false;
|
|
}
|
|
|
|
// Get Channel
|
|
if (!(Channel = GetChannel( ChannelName ))) {
|
|
// Channel not found
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Input failed, Channel not found", Name, ChannelName );
|
|
return false;
|
|
}
|
|
else {
|
|
// Return success
|
|
return PullInput( Channel );
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::PullInput( TChannel * Channel )
|
|
{
|
|
TChannelLink * InChannel = NULL;
|
|
char ** Data = NULL;
|
|
int * Len = NULL;
|
|
|
|
// Validate
|
|
if (!Channel) {
|
|
return false;
|
|
}
|
|
|
|
// Check if enabled
|
|
if (!Channel->InputEnabled) {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Input failed, Channel input disabled", Name, Channel->Name );
|
|
return false;
|
|
}
|
|
|
|
// Pass output to all linked inputs
|
|
InChannel = Channel->FirstInput;
|
|
while (InChannel)
|
|
{
|
|
// Pull Output from Channel
|
|
if (InChannel->Function->PullOutput( InChannel->Name, Data, Len ))
|
|
{
|
|
// Use input
|
|
Input( Channel->Name, *Data, ((*Len)? *Len : -1) );
|
|
}
|
|
InChannel = InChannel->Next;
|
|
}
|
|
|
|
// Return success
|
|
return Len;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFunctionCore::PullOutput( const char * ChannelName, char ** Data, int * Len )
|
|
{
|
|
TChannel * Channel = NULL;
|
|
int TempLen = 0;
|
|
|
|
// Validate
|
|
if (!ChannelName || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Get Channel
|
|
if (!(Channel = GetChannel( ChannelName ))) {
|
|
// Channel not found
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Output failed, Channel not found", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
else if (!Channel->InputEnabled) {
|
|
// Channel disabled
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Output failed, Channel output disabled", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
else {
|
|
// Return processed bytes
|
|
*Data = StoredOutput;
|
|
TempLen = (*Data)? strlen(*Data) : 0;
|
|
if (Len) *Len = TempLen;
|
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, ((*Data)? *Data : "(NULL)"), TempLen, "%s: Channel '%s' - IN:", Name, ChannelName );
|
|
return Len;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|