/* * FunctionListCore.cpp * * Created on: 12 Jul 2017 * Author: wentzelc */ // Standard C/C++ Libraries /* none */ // redA Libraries #include "ApplicationCore.h" #include "WatchdogCore.h" #include "FileCore.h" #include "DeviceCore.h" //--------------------------------------------------------------------------- // Global Vars extern bool Terminate; extern char * ProcessName; //--------------------------------------------------------------------------- CApplication::CApplication( EDebugLevel pLogLevel ) { // Set signal handlers ConfigureSignalHandlers(); DefinitionFile = NULL; ConfigFile = NULL; AddressFile = NULL; // Create output logger Log = new CLogCore( stdout ); LogLevel = pLogLevel; LogOutput = loNormal; // Create Configuration DataTree = new CDataMember(); Config = DataTree->GetChild( "Config", true ); Definition = DataTree->GetChild( "Definition", true ); AddressList = DataTree->GetChild( "AddressList", true ); JSONparser = new CJSONparse( DataTree ); // Selector Selector = NULL; // List FirstFunctionType = NULL; FirstFunction = NULL; // Add Core Function Types //AddFunctionType( TYPE_FUNCTION, NewFunctionCore ); // <-- Can't add virtual function AddFunctionType( TYPE_SELECTABLE, NewSelectableCore ); AddFunctionType( TYPE_WATCHDOGPING, NewWatchdogCore ); AddFunctionType( TYPE_FILE, NewFileCore ); //AddFunctionType( TYPE_DEVICE, NewDeviceCore ); // <-- Can't add virtual function } //--------------------------------------------------------------------------- CApplication::~CApplication() { TFunctionItem * NextFunction; TFunctionType * NextType; // Destroy functions while (FirstFunction) { NextFunction = FirstFunction->Next; delete( FirstFunction->Function ); free( FirstFunction ); FirstFunction = NextFunction; } // Destroy function types while (FirstFunctionType) { NextType = FirstFunctionType->Next; free( FirstFunctionType->Name ); free( FirstFunctionType ); FirstFunctionType = NextType; } // Show Completion if (Log) Log->Message( dlLow, dlLow, "%s: Terminated.", ProcessName ); // Destroy tools if (Selector) delete Selector; if (Log) delete Log; if (DataTree) delete DataTree; if (JSONparser) delete JSONparser; // Free Process Name if (ProcessName) free( ProcessName ); } //--------------------------------------------------------------------------- void CApplication::GetProcessName( char ** ProcessName, char * pFilePath ) { char * TempStr; // Remove Path TempStr = strrchr( pFilePath, '/' ); if (TempStr[0] == '/') TempStr++; // Copy Process Name *ProcessName = strdup( TempStr ); // Remove extension TempStr = strrchr( *ProcessName, '.' ); if (TempStr) TempStr[0] = 0; } //--------------------------------------------------------------------------- bool CApplication::ReadParam( int argc, char *argv[] ) { // Read Parameters if ((argc != 2)) { // Get Process Name GetProcessName( &ProcessName, argv[0] ); // Incorrect no of parameters, show correct usage printf( "%s: Incorrect number of parameters\n", ProcessName ); printf( " usage: %s [ConfigFile]\n\n", ProcessName ); return false; } else { // Load parameters GetProcessName( &ProcessName, argv[1] ); ConfigFile = argv[1]; return true; } } //--------------------------------------------------------------------------- bool CApplication::LoadConfig() { // Load Configuration Data if (!JSONparser->ReadFromFile( "Config", ConfigFile )) { if (Log) Log->Message( dlLow, dlLow, "%s: Fail to load Configuration file (%s) - %s", ProcessName, ConfigFile, JSONparser->GetError() ); return false; } else { //JSONparser->WriteToScreen( "config", 2 ); if (Log) Log->Message( dlLow, dlLow, "%s: Configuration file loaded (%s)", ProcessName, ConfigFile ); } // Load Application Definition if (!(DefinitionFile = (char*)Config->GetChStr( "Application/Definition" ))) { if (Log) Log->Message( dlLow, dlLow, "%s: No Application Definition file specified", ProcessName ); return false; } else if (!JSONparser->ReadFromFile( "Definition", DefinitionFile )) { if (Log) Log->Message( dlLow, dlLow, "%s: Fail to load Application Definition file (%s) - %s", ProcessName, DefinitionFile, JSONparser->GetError() ); return false; } else { //JSONparser->WriteToScreen( "application", 2 ); if (Log) Log->Message( dlLow, dlLow, "%s: Application Definition file loaded (%s)", ProcessName, DefinitionFile ); } // Load Address List if (!(AddressFile = (char*)Config->GetChStr( "Application/Addresses/List" ))) { if (Log) Log->Message( dlLow, dlLow, "%s: No Address List file specified", ProcessName ); } else if (!JSONparser->ReadFromFile( "AddressList", AddressFile )) { if (Log) Log->Message( dlLow, dlLow, "%s: Fail to load Address List file (%s) - %s", ProcessName, AddressFile, JSONparser->GetError() ); return false; } else { //JSONparser->WriteToScreen( "address", 2 ); if (Log) Log->Message( dlLow, dlLow, "%s: Address List file loaded (%s)", ProcessName, AddressFile ); } // Loaded successfully return true; } //--------------------------------------------------------------------------- bool CApplication::SaveConfig() { // Save updated configuration if (ConfigFile && *ConfigFile) JSONparser->WriteToFile( "Config", ConfigFile ); if (DefinitionFile && *DefinitionFile) JSONparser->WriteToFile( "Definition", DefinitionFile ); if (AddressFile && *AddressFile ) JSONparser->WriteToFile( "AddressList", AddressFile ); return true; } //--------------------------------------------------------------------------- bool CApplication::SetLogParam( EDebugLevel pDebugLevel, int pOutputDisplay ) { // Output LogLevel = pDebugLevel; LogOutput = pOutputDisplay; return true; } //--------------------------------------------------------------------------- bool CApplication::InitApplication() { CDataMember * CoreConfig; CDataMember * LogConfig; CDataMember * SelectConfig; EDebugLevel pLogLevel; int pLogOutput; // Get Core definition CoreConfig = Definition->GetChild( "Core", true ); // Configure Logging/Debugging LogConfig = CoreConfig->GetChild( "Log", true ); pLogLevel = Log->ReadLogLevel( LogConfig ); pLogOutput = Log->ReadLogOutput( LogConfig ); SetLogParam( pLogLevel, pLogOutput ); // Configure Selector if ((SelectConfig = CoreConfig->GetChild( "Selector" ))) { Selector = new CSelect( (int)SelectConfig->GetChInt( "Wait", 5, true ), LogLevel ); } // Show status if (Log) Log->Message( LogLevel, dlLow, "%s: Application Core configured.", ProcessName ); return true; } //--------------------------------------------------------------------------- bool CApplication::InitFunction( CFunctionCore * Function ) { char FunctionPath[100]; CDataMember * FunctionConfig; // Validate if (!Function) return false; // Load configuration sprintf( FunctionPath, "FunctionBlocks/%s", Function->GetName() ); if (!(FunctionConfig = Definition->GetChild( FunctionPath, true ))) { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' cannot create config!", ProcessName, Function->GetName(), Function->GetType() ); } // Configure Function else if (!Function->Init( FunctionConfig )) { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' init failed!", ProcessName, Function->GetName(), Function->GetType() ); return false; } else { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' configured.", ProcessName, Function->GetName(), Function->GetType() ); } return true; } //--------------------------------------------------------------------------- bool CApplication::InitFunctions() { CDataMember * FunctionList; CDataMember * FunctionConfig; CFunctionCore * Function; char * Type; // Check of path exists if (!(FunctionList = Definition->GetChild( "FunctionBlocks" ))) { if (Log) Log->Message( LogLevel, dlLow, "%s: No Function Block specified", ProcessName ); return false; } // Process each Function FunctionConfig = FunctionList->GetFirstChild(); while (FunctionConfig) { // Get function parameters Type = (char*)FunctionConfig->GetChStr( "Type", "Custom", true ); if (Log) Log->Message( LogLevel, dlLow, "%s: Function '%s' - Type '%s' initialising...", ProcessName, FunctionConfig->GetName(), Type ); // Get or create function Function = AddFunction( Type, FunctionConfig->GetName() ); // Load Function configuration and Initialise if (!Function) { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' not found!", ProcessName, FunctionConfig->GetName(), Type ); } else if (!Function->Init( FunctionConfig )) { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' init failed!", ProcessName, Function->GetName(), Function->GetType() ); } else { if (Log) Log->Message( LogLevel, dlMedium, "%s: Function '%s' - Type '%s' configured.", ProcessName, Function->GetName(), Function->GetType() ); } // Next FunctionConfig = FunctionConfig->GetNextPeer(); } return true; } //--------------------------------------------------------------------------- bool CApplication::InitFunctionLinks() { CDataMember * LinkList; CDataMember * LinkConfig; TFunctionItem * FunctionItem; // Check of path exists if (!(LinkList = Definition->GetChild( "ChannelLinks", true ))) { if (Log) Log->Message( LogLevel, dlMedium, "%s: No Function Channel links specified.", ProcessName ); return false; } else { if (Log) Log->Message( LogLevel, dlLow, "%s: Linking Function Block Channels...", ProcessName ); } // Process each Channel FunctionItem = FirstFunction; while (FunctionItem) { // Build links for function if ((LinkConfig = LinkList->GetChild( FunctionItem->Function->GetName() ))) FunctionItem->Function->InitChannelLinks( LinkConfig ); // Next FunctionItem = FunctionItem->Next; } if (Log) Log->Message( LogLevel, dlLow, "%s: Function Block Channels linked.", ProcessName ); return true; } //--------------------------------------------------------------------------- bool CApplication::AddFunctionType( const char * Type, FFuncConstructor Constructor ) { TFunctionType ** FunctionType; // Get end of list FunctionType = &FirstFunctionType; while (*FunctionType && strcasecmp(Type, (*FunctionType)->Name)) FunctionType = &((*FunctionType)->Next); if (*FunctionType) { if (Log) Log->Message( dlLow, dlLow, "%s: Cannot add FunctionType '%s' - Already exists", ProcessName, Type ); return NULL; } // Add new Type *FunctionType = (TFunctionType*)calloc( sizeof(TFunctionType), 1 ); (*FunctionType)->Name = strdup( Type ); (*FunctionType)->Constructor = Constructor; return true; }; //--------------------------------------------------------------------------- // Build List CFunctionCore * CApplication::AddFunction( const char * Type, const char * Name ) { TFunctionItem ** FunctionPtr; TFunctionType * FunctionType; // Check if unique, else get end of list FunctionPtr = &FirstFunction; while (*FunctionPtr && strcasecmp( (*FunctionPtr)->Function->GetName(), Name )) FunctionPtr = &((*FunctionPtr)->Next); if (*FunctionPtr) return NULL; // Can't overwrite existing function // Check if type is valid FunctionType = FirstFunctionType; while (FunctionType && strcasecmp( FunctionType->Name, Type )) FunctionType = FunctionType->Next; if (!FunctionType) return NULL; // Type not defined // Add to end of list *FunctionPtr = (TFunctionItem*)calloc( sizeof(TFunctionItem), 1 ); (*FunctionPtr)->Function = FunctionType->Constructor( Name ); return (*FunctionPtr)->Function; } //--------------------------------------------------------------------------- // Search List CFunctionCore * CApplication::GetFunction( const char * Name ) { TFunctionItem * FunctionItem; // Find in list FunctionItem = FirstFunction; while (FunctionItem && strcasecmp( FunctionItem->Function->GetName(), Name )) FunctionItem = FunctionItem->Next; return ((FunctionItem)? FunctionItem->Function : NULL); } //--------------------------------------------------------------------------- CDataMember * CApplication::GetAddress( const char * SearchAddress ) { CDataMember * AddressDef = NULL; char NamePath[100]; char * Address; // Address renamed? sprintf( NamePath, "Application/Addresses/Rename/%s", SearchAddress ); if (!(Address = (char*)Config->GetChStr( NamePath, NULL, false ))) { Address = (char*)SearchAddress; } // Get address def AddressDef = AddressList->GetChild( Address ); return AddressDef; } //--------------------------------------------------------------------------- bool CApplication::Run( bool TerminateOnError ) { bool CleanTerminate = true; bool ProcessTerminate = false; TFunctionItem * FunctionItem; // Check for FD Events/States if (Selector) { Selector->Test(); } // Process Functions for (FunctionItem = FirstFunction; FunctionItem; FunctionItem = FunctionItem->Next ) { ProcessTerminate = !FunctionItem->Function->Process(); if (TerminateOnError) { if (ProcessTerminate) // Raise terminate flag for other processes Terminate = true; if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) // If needed, allow process to terminate cleanly CleanTerminate = false; } } if (Terminate && TerminateOnError && CleanTerminate) return false; else return true; } //---------------------------------------------------------------------------