/* * 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; //--------------------------------------------------------------------------- // Function Constructor //CFunctionCore * NewFunctionCore( const char * Name ) { // return new CFunctionCore( Name, "Function" ); //} //--------------------------------------------------------------------------- // Life cycle CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType ) { // Set name if (pName) Name = strdup( pName ); // Logging Log = Application->Log; LogLevel = dlNone; LogOutput = loNormal; } //--------------------------------------------------------------------------- CFunctionCore::~CFunctionCore() { TChannel * NextChannel = NULL; // Destroy Channels while (FirstChannel) { // Destroy Linked Channels while (FirstChannel->FirstLink) UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name ); // Destroy Parameters if (FirstChannel->Name) free( FirstChannel->Name ); if (FirstChannel->Ref) free( FirstChannel->Ref ); // Destroy Channel NextChannel = FirstChannel->Next; delete FirstChannel; FirstChannel = NextChannel; } // Report status if (Log) Log->Message( LogLevel, dlLow, "%s: Function '%s' - Destroyed", ProcessName, Name ); // Destroy Name if (Name) free( Name ); } //--------------------------------------------------------------------------- bool CFunctionCore::Init( CDataMember * FunctionConfig ) { // Load configuration CDataMember * LogConfig; CDataMember * ChannelConfig; EDebugLevel pLogLevel; int pLogOutput; char * ConfigName = NULL; // Validate if (!FunctionConfig ) return false; // Set Type FunctionConfig->SetChStr( "Type", Type ); // Configure Logging/Debugging LogConfig = FunctionConfig->GetChild( "Log", true ); pLogLevel = Log->ReadLogLevel( LogConfig ); pLogOutput = Log->ReadLogOutput( LogConfig ); SetLogParam( pLogLevel, pLogOutput ); // Load Channels ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); while (ChannelConfig) { AddChannel( ChannelConfig->GetName(), CH_off ); ChannelConfig = ChannelConfig->GetNextPeer(); } // Get main configuration if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) { ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); Config = Application->Config->GetChild( ConfigName, true ); } return true; } //--------------------------------------------------------------------------- bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig ) { TChannel * Channel; CDataMember * ChannelMember; CDataMember * FunctionMember; // Validate if (!LinkConfig) return false; // Process each Channel ChannelMember = LinkConfig->GetFirstChild(); while (ChannelMember) { if ((Channel = GetChannel( ChannelMember->GetName() ))) { FunctionMember = ChannelMember->GetElement( 0 ); while (FunctionMember) { // Get Parameters LinkChannel( Channel->Name, FunctionMember->GetChStr( "Function", NULL, true ), FunctionMember->GetChStr( "Channel", NULL, true ), FunctionMember->GetChBool( "Input", false, true ), FunctionMember->GetChBool( "Output", false, true ) ); FunctionMember = FunctionMember->GetNextPeer(); } } ChannelMember = ChannelMember->GetNextPeer(); } 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 EChannelState State ) { 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 = new TChannel; // Set Name (*Channel)->Name = strdup( ChannelName ); (*Channel)->Ref = (char*)malloc( strlen(Name)+strlen(ChannelName)+2 ); sprintf( (*Channel)->Ref, "%s/%s", Name, ChannelName ); (*Channel)->InState = State; (*Channel)->OutState = CH_off; // Log Event if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', In:%s, Out:%s", ProcessName, Name, ChannelName, (*Channel)->Ref, ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]); } return *Channel; } //--------------------------------------------------------------------------- bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State ) { EChannelState OldState = Channel->InState; TChannelLink * LinkChannel; // Validate if (!Channel) return false; // Update state Channel->InState = State; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s", ProcessName, Name, Channel->Ref, ChannelStateName[State] ); // Update linked channels LinkChannel = Channel->FirstLink; while (LinkChannel) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s", ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] ); // Trigger Linked Channel Events LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State ); LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel ); LinkChannel = LinkChannel->Next; } return true; } //--------------------------------------------------------------------------- bool CFunctionCore::UpdateChannelOutState( TChannel * Channel ) { TChannelLink * LinkChannel; EChannelState OutState; // Check if channel Out state changed OutState = CH_off; LinkChannel = Channel->FirstLink; while (LinkChannel) { if (LinkChannel->Channel->InState > OutState) OutState = LinkChannel->Channel->InState; LinkChannel = LinkChannel->Next; } if (OutState != Channel->OutState) { // Update output state Channel->OutState = OutState; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - Out:%s", ProcessName, Name, Channel->Ref, ChannelStateName[OutState] ); } return true; } //--------------------------------------------------------------------------- EChannelState CFunctionCore::GetChannelOutState( TChannel * Channel, const char * TargetRef ) { TChannelLink * LinkChannel = NULL; // Validate if (!Channel) { return CH_off; } else if (!TargetRef || !*TargetRef) { return Channel->OutState; } else if ((LinkChannel = GetLinkChannel( Channel, TargetRef ))) { return LinkChannel->Channel->InState; } else { return CH_off; } } //--------------------------------------------------------------------------- // Automated Data Input/Output bool CFunctionCore::LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output ) { TChannel * Channel = NULL; CFunctionCore * LinkFunction = NULL; TChannel * LinkChannel = NULL; TChannelLink ** LinkedChannel = NULL; // Check if Channels & Function exist if (!(Channel = GetChannel( ChannelName )) || !(LinkFunction = Application->GetFunction( LinkFunctionName )) || !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) { return false; } // Check if linked Channel exists LinkedChannel = &(Channel->FirstLink); while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel)) LinkedChannel = &((*LinkedChannel)->Next); if (!*LinkedChannel) *LinkedChannel = new TChannelLink; // Set Parameters (*LinkedChannel)->Function = LinkFunction; (*LinkedChannel)->Channel = LinkChannel; (*LinkedChannel)->Input = Input; (*LinkedChannel)->Output = Output; // Log Event if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Linked - '%s'-->'%s' - In:%s, Out:%s", ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref, ((Input)? "Yes" : "No"), ((Output)? "Yes" : "No") ); // Find Linked channel on remote function LinkedChannel = &(LinkChannel->FirstLink); while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel)) LinkedChannel = &((*LinkedChannel)->Next); if (!*LinkedChannel) *LinkedChannel = new TChannelLink; // Set Parameters (*LinkedChannel)->Function = this; (*LinkedChannel)->Channel = Channel; (*LinkedChannel)->Input = Output; (*LinkedChannel)->Output = Input; // Log Event if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Linked - '%s'-->'%s' - In:%s, Out:%s", ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref, ((Output)? "Yes" : "No"), ((Input)? "Yes" : "No") ); // Trigger Forward Channel Events LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState ); LinkFunction->UpdateChannelOutState( LinkChannel ); // Trigger Reverse Channel Events ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState ); UpdateChannelOutState( Channel ); return true; } //--------------------------------------------------------------------------- bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName ) { TChannel * Channel = NULL; CFunctionCore * LinkFunction = NULL; TChannel * LinkChannel = NULL; TChannelLink ** LinkedChannel = NULL; TChannelLink * NextLinkedChannel = NULL; // Check if Channels & Function exist if (!(Channel = GetChannel( ChannelName )) || !(LinkFunction = Application->GetFunction( LinkFunctionName )) || !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) { return false; } // Check if linked Channel exists LinkedChannel = &(Channel->FirstLink); while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel)) LinkedChannel = &((*LinkedChannel)->Next); // Unlink channel if (*LinkedChannel) { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Unlinked - '%s'-x->'%s'", ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref ); NextLinkedChannel = (*LinkedChannel)->Next; delete *LinkedChannel; *LinkedChannel = NextLinkedChannel; } // Find Linked channel on remote function LinkedChannel = &(LinkChannel->FirstLink); while (*LinkedChannel && ((*LinkedChannel)->Channel != Channel)) LinkedChannel = &((*LinkedChannel)->Next); // Unlink channel if (*LinkedChannel) { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Reverse Channel Unlinked - '%s'-x->'%s'", ProcessName, Name, LinkChannel->Ref, (*LinkedChannel)->Channel->Ref ); NextLinkedChannel = (*LinkedChannel)->Next; delete *LinkedChannel; *LinkedChannel = NextLinkedChannel; } // Trigger Channel Events LinkFunction->UpdateChannelOutState( LinkChannel ); UpdateChannelOutState( Channel ); return true; } //--------------------------------------------------------------------------- int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len ) { TChannel * Channel = NULL; // Validate if (!ChannelName || !*ChannelName || !Data) { return 0; } // Get Channel if (!(Channel = GetChannel( ChannelName ))) { // Channel not found if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return 0; } else if (!Channel->InState) { if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->InState] ); return 0; } // Return processed bytes if (Len == -1) { Len = strlen( Data ); } if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName ); return Len; } //--------------------------------------------------------------------------- int CFunctionCore::Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len ) { TChannel * Channel = NULL; // Validate if (!ChannelName || !*ChannelName) { return 0; } // Get Channel if (!(Channel = GetChannel( ChannelName ))) { if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Output rejected, Output Channel not found", ProcessName, Name, ChannelName, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); return 0; } else { // Return processed bytes return Output( Channel, TargetRef, SourceRef, Data, Len ); } } //--------------------------------------------------------------------------- int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat ) { TChannelLink * LinkChannel = NULL; int TempLen = 0; int OutLen = 0; // Validate if (!Channel || !Data) { return 0; } // Log event if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s'->'%s' - OUT:", ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") ); // Pass output to all linked inputs if (Len == -1) Len = strlen( Data ); LinkChannel = Channel->FirstLink; while (LinkChannel) { if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) { TempLen = LinkChannel->Function->Input( LinkChannel->Channel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len ); OutLen = (TempLen > OutLen)? TempLen : OutLen; } LinkChannel = LinkChannel->Next; } // Return processed bytes return OutLen; } //---------------------------------------------------------------------------