- DataTreeCore: - Rename all Get/SetChild...() methods to Get/SetMem...() - Update all other objects with new methods
379 lines
11 KiB
C++
379 lines
11 KiB
C++
/*
|
|
* 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"
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Global Vars
|
|
extern char * ProcessName;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
CApplication::CApplication( EDebugLevel pLogLevel )
|
|
{
|
|
// Set signal handlers
|
|
ConfigureSignalHandlers();
|
|
|
|
// Variables used for configuration
|
|
ConfigMember = NULL;
|
|
FunctionConfigMember = NULL;
|
|
LinkConfigMember = NULL;
|
|
|
|
ConfigFile = NULL;
|
|
AddressFile = NULL;
|
|
|
|
// Create output logger
|
|
Log = new CLogCore( stdout );
|
|
LogLevel = pLogLevel;
|
|
LogOutput = OUT_NORMAL;
|
|
|
|
// Create Configuration
|
|
DataTree = new CDataMember();
|
|
JSONparser = new CJSONparse( DataTree );
|
|
|
|
// Selector
|
|
Selector = NULL;
|
|
|
|
// List
|
|
FirstFunction = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CApplication::~CApplication()
|
|
{
|
|
TFunctionItem * NextFunction;
|
|
|
|
if (FirstFunction)
|
|
{
|
|
// Destroy functions
|
|
while (FirstFunction)
|
|
{
|
|
NextFunction = FirstFunction->Next;
|
|
delete( FirstFunction->Function );
|
|
free( FirstFunction );
|
|
FirstFunction = NextFunction;
|
|
}
|
|
}
|
|
|
|
// 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 = (char*)malloc( strlen(TempStr)+1 );
|
|
strcpy( *ProcessName, TempStr );
|
|
|
|
// Remove extension
|
|
TempStr = strrchr( *ProcessName, '.' );
|
|
if (TempStr) TempStr[0] = 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::LoadConfig( int argc, char *argv[], const char * pConfigPath )
|
|
{
|
|
// 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];
|
|
}
|
|
|
|
// Load Application List
|
|
if (JSONparser->ReadFromFile( pConfigPath, ConfigFile )) {
|
|
if (Log) Log->Message( dlLow, dlLow, "%s: Config file loaded (%s)", ProcessName, ConfigFile );
|
|
} else {
|
|
if (Log) Log->Message( dlLow, dlLow, "%s: Fail to load config file (%s)- %s", ProcessName, ConfigFile, JSONparser->GetError() );
|
|
return false;
|
|
}
|
|
//JSONparser->WriteToScreen( pConfigPath, 2 );
|
|
|
|
// Loaded successfully
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::SaveConfig()
|
|
{
|
|
// Save updated configuration
|
|
if (ConfigFile && *ConfigFile)
|
|
JSONparser->WriteToFile( "config", ConfigFile );
|
|
if (AddressFile && *AddressFile )
|
|
JSONparser->WriteToFile( "address", AddressFile );
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::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();
|
|
}
|
|
}
|
|
SetLogParam( pLogLevel, pLogOutput );
|
|
|
|
// Load Address List
|
|
if ((AddressFile = (char*)ConfigMember->GetMemStr( "AddressList/Path", NULL )))
|
|
{
|
|
if (JSONparser->ReadFromFile( "address", AddressFile )) {
|
|
if (Log) Log->Message( dlLow, dlLow, "%s: Address file loaded (%s)", ProcessName, AddressFile );
|
|
} else {
|
|
if (Log) Log->Message( dlLow, dlLow, "%s: Fail to load Address file (%s) - %s", ProcessName, AddressFile, JSONparser->GetError() );
|
|
}
|
|
//JSONparser->WriteToScreen( pAddressListPath, 2 );
|
|
}
|
|
|
|
// Configure Selector
|
|
if ((TempMember = ConfigMember->GetMember( "Selector" )))
|
|
{
|
|
// Create Selector
|
|
Selector = new CSelect( (int)TempMember->GetMemInt( "Wait", 5, true ), LogLevel );
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::SetLogParam( EDebugLevel pDebugLevel, int pOutputDisplay )
|
|
{
|
|
// Output
|
|
LogLevel = pDebugLevel;
|
|
LogOutput = pOutputDisplay;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::Init()
|
|
{
|
|
// Report status
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s: Application Initialised", ProcessName );
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::InitConfig( const char * pConfigPath )
|
|
{
|
|
// Check if Datatree exists
|
|
if (!DataTree || !(ConfigMember = DataTree->GetMember( pConfigPath ))) {
|
|
return false;
|
|
}
|
|
|
|
// LoadConfiguration
|
|
LoadConfigData();
|
|
Init();
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::InitFunctions( const char * pConfigPath )
|
|
{
|
|
CFunctionCore * Function;
|
|
CDataMember * TempMember;
|
|
char * Type;
|
|
|
|
// Check of path exists
|
|
if (!DataTree || !(FunctionConfigMember = DataTree->GetMember( pConfigPath )))
|
|
return false;
|
|
|
|
// Process each Channel
|
|
TempMember = FunctionConfigMember->GetFirstChild();
|
|
while (TempMember)
|
|
{
|
|
// Get function parameters
|
|
Type = (char*)TempMember->GetMemStr( "Type", "Custom", true );
|
|
|
|
// Get or create function
|
|
if (!strcasecmp( Type, "WatchdogClient" )) {
|
|
Function = new CWatchdogCore( TempMember->GetName() );
|
|
}
|
|
else if (!strcasecmp( Type, "Selectable" )) {
|
|
Function = new CSelectableCore( TempMember->GetName() );
|
|
}
|
|
else if (!strcasecmp( Type, "File" )) {
|
|
Function = new CFileCore( TempMember->GetName() );
|
|
}
|
|
else {
|
|
Function = GetFunction( TempMember->GetName() );
|
|
}
|
|
|
|
// Load Function configuration and Initialise
|
|
if (Function) {
|
|
Function->InitConfig( TempMember );
|
|
}
|
|
|
|
// Next
|
|
TempMember = TempMember->GetNextPeer();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::InitFunctionLinks( const char * pConfigPath )
|
|
{
|
|
TFunctionItem * FunctionItem;
|
|
CDataMember * TempMember;
|
|
|
|
// Check of path exists
|
|
if (!DataTree || !(LinkConfigMember = DataTree->GetMember( pConfigPath )))
|
|
return false;
|
|
|
|
// Process each Channel
|
|
FunctionItem = FirstFunction;
|
|
while (FunctionItem)
|
|
{
|
|
// Build links for function
|
|
if ((TempMember = LinkConfigMember->GetMember( FunctionItem->Function->GetName() )))
|
|
FunctionItem->Function->InitChannelLinks( TempMember );
|
|
|
|
// Next
|
|
FunctionItem = FunctionItem->Next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Build List
|
|
bool CApplication::AddFunction( CFunctionCore * Function )
|
|
{
|
|
TFunctionItem ** FunctionPtr;
|
|
|
|
// Check if unique, else get end of list
|
|
FunctionPtr = &FirstFunction;
|
|
while (*FunctionPtr && strcasecmp( (*FunctionPtr)->Function->GetName(), Function->GetName() ))
|
|
FunctionPtr = &((*FunctionPtr)->Next);
|
|
|
|
// Check if exists
|
|
if (*FunctionPtr)
|
|
return false;
|
|
|
|
// Add to end of list
|
|
*FunctionPtr = (TFunctionItem*)calloc( sizeof(TFunctionItem), 1 );
|
|
(*FunctionPtr)->Function = Function;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// 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);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CApplication::Run( bool TerminateOnError )
|
|
{
|
|
bool AllGood = true;
|
|
TFunctionItem * FunctionItem;
|
|
|
|
// Check for FD Events/States
|
|
if (Selector) {
|
|
Selector->Test();
|
|
}
|
|
|
|
// Process Functions
|
|
for (FunctionItem = FirstFunction; FunctionItem; FunctionItem = FunctionItem->Next )
|
|
{
|
|
if (!FunctionItem->Function->Process())
|
|
{
|
|
if (TerminateOnError)
|
|
return false;
|
|
else {
|
|
AllGood = false;
|
|
}
|
|
}
|
|
}
|
|
return AllGood;
|
|
}
|
|
//---------------------------------------------------------------------------
|