/* * 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() { TDataMember * TempMember; EDebugLevel pLogLevel; int pLogOutput; char * TempStr; // Get debug level pLogLevel = dlNone; TempStr = (char*)DataTree->GetStr( ConfigMember, "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; TempMember = DataTree->GetFirstChild( ConfigMember, "Log/Output", true ); while (TempMember) { if (TempMember->Value) { if (!strcasecmp( TempMember->Value, "Normal")) pLogOutput |= OUT_NORMAL; else if (!strcasecmp( TempMember->Value, "Bin")) pLogOutput |= OUT_BIN; else if (!strcasecmp( TempMember->Value, "Hex")) pLogOutput |= OUT_HEX; else if (!strcasecmp( TempMember->Value, "Count")) pLogOutput |= OUT_COUNT; else if (!strcasecmp( TempMember->Value, "AsIs")) pLogOutput |= OUT_ASIS; else if (!strcasecmp( TempMember->Value, "CRLF")) pLogOutput |= OUT_CRLF; } // Next TempMember = DataTree->GetNextChild( TempMember ); } // Set Logging SetLogParam( pLogLevel, pLogOutput ); // Load Channels TempMember = DataTree->GetFirstChild( ConfigMember, "Channels" ); while (TempMember) { if (TempMember->Name) { AddChannel( TempMember->Name, DataTree->GetBool( TempMember, "InputEnabled", true, true ), DataTree->GetBool( TempMember, "OutputEnabled", false, true )); } // Next TempMember = DataTree->GetNextChild( TempMember ); } return true; } //--------------------------------------------------------------------------- bool CFunctionCore::LoadChannelLinkData() { TChannel * Channel; TDataMember * ChannelMember; TDataMember * FunctionMember; // Process each Channel ChannelMember = DataTree->GetFirstChild( LinkConfigMember ); while (ChannelMember) { if ((Channel = GetChannel( ChannelMember->Name ))) { FunctionMember = DataTree->GetFirstChild( ChannelMember ); while (FunctionMember) { // Get Parameters LinkOutputChannel( Channel->Name, DataTree->GetStr( FunctionMember, "Function" ), DataTree->GetStr( FunctionMember, "Channel" ), DataTree->GetBool( FunctionMember, "Bidirectional" ) ); // Next FunctionMember = DataTree->GetNextChild( FunctionMember ); } } // Next ChannelMember = DataTree->GetNextChild( ChannelMember ); } 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( NULL, pConfigPath, true ))) return false; // Load configuration LoadConfigData(); Init(); return true; } //--------------------------------------------------------------------------- bool CFunctionCore::InitConfig( TDataMember * 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( NULL, pLinkConfigPath, true ))) return false; // Load configuration LoadChannelLinkData(); return true; } //--------------------------------------------------------------------------- bool CFunctionCore::InitChannelLinks( TDataMember *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; // 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) { OutChannel->Function->Input( OutChannel->Name, Data, Len ); OutChannel = OutChannel->Next; } // Return processed bytes return Len; } //--------------------------------------------------------------------------- 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; } } //---------------------------------------------------------------------------