Major Update:
- Implement new ApplicationCore:
- Manage Tools: Log, DataTree, JSONparser & Selector
- Load configuration, Manage FunctionBlocks
- FunctionCore & dirived classes, SignalCore:
- affects: SelectableCore, DeviceCore, FileCore, WatchdogCore
- Do not pass Log()
- Define and pass Type
- Update/reduce included headers
- Use ProcessName and Application global vars
- Get Log, DataTree from Application
- Use virtual Init() function to set must have Channels/Handles
- DataTreeCore:
- Bug fix: Check if child members exist and destroy in SetValuePtr()
- Add method GetFirstChild with BaseMember & Path
- Bug fix: do not use RootMember if no Parent in GetChildxxx() methods
- SignalCore, SelectCore:
- Use Application->Log()
- FunctionCore:
- Add itself to Application (function list)
- Add parameter: LinkConfigMember, Type
- Use virtual LoadConfigData() to configure from DataTree
- Rename methods: LoadConfig() -> InitConfig(),
InitLogging() -> SetLogParam(), SetDebugLevel() -> SetLogLevel()
- Add method: GetType(), LoadChannelLinkData(), InitChannelLinks()
- Modify LinkIn/OutputChannel() to use name for InFunction, not pointer
- SelectableCore & Dirived classes:
- Affects DeviceCore & WatchdogClient
- Rename parameter: Select -> Selector, BaseMember -> ConfigMember
- Get Selector from Application->Selector
- Change Handles JSON structure from Array to Key:Value pairs
- Bug fix: check if Selector exist during Input()
- Bug fix: do not set PortNo if not exist
This commit is contained in:
370
ApplicationCore.cpp
Normal file
370
ApplicationCore.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* FunctionListCore.cpp
|
||||
*
|
||||
* Created on: 12 Jul 2017
|
||||
* Author: wentzelc
|
||||
*/
|
||||
|
||||
// redA Libraries
|
||||
#include "ApplicationCore.h"
|
||||
#include "WatchdogCore.h"
|
||||
#include "FileCore.h"
|
||||
|
||||
// Standard C/C++ Libraries
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 CDataTree();
|
||||
ConfigParser = new CJSONparse( DataTree );
|
||||
|
||||
// Selector
|
||||
Selector = NULL;
|
||||
|
||||
// List
|
||||
FirstFunction = NULL;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CApplication::~CApplication()
|
||||
{
|
||||
TFunctionItem * NextFunction;
|
||||
|
||||
if (FirstFunction)
|
||||
{
|
||||
// Show Start of termination
|
||||
if (Log) Log->Message( dlLow, dlLow, "%s: Terminating...", ProcessName );
|
||||
|
||||
// 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 (ConfigParser) delete ConfigParser;
|
||||
|
||||
// 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 (ConfigParser->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, ConfigParser->GetError() );
|
||||
return false;
|
||||
}
|
||||
//ConfigParser->WriteToScreen( pConfigPath, 2 );
|
||||
|
||||
// Loaded successfully
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CApplication::SaveConfig()
|
||||
{
|
||||
// Save updated configuration
|
||||
if (ConfigFile && *ConfigFile)
|
||||
ConfigParser->WriteToFile( "config", ConfigFile );
|
||||
if (AddressFile && *AddressFile )
|
||||
ConfigParser->WriteToFile( "address", AddressFile );
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CApplication::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 );
|
||||
}
|
||||
SetLogParam( pLogLevel, pLogOutput );
|
||||
|
||||
// Load Address List
|
||||
if ((AddressFile = (char*)DataTree->GetStr( ConfigMember, "AddressList/Path", NULL )))
|
||||
{
|
||||
if (ConfigParser->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, ConfigParser->GetError() );
|
||||
}
|
||||
//ConfigParser->WriteToScreen( pAddressListPath, 2 );
|
||||
}
|
||||
|
||||
// Configure Selector
|
||||
if ((TempMember = DataTree->GetMember( ConfigMember, "Selector" )))
|
||||
{
|
||||
// Create Selector
|
||||
Selector = new CSelect( (int)DataTree->GetInt( TempMember, "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( NULL, pConfigPath ))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// LoadConfiguration
|
||||
LoadConfigData();
|
||||
Init();
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CApplication::InitFunctions( const char * pConfigPath )
|
||||
{
|
||||
CFunctionCore * Function;
|
||||
TDataMember * TempMember;
|
||||
char * Type;
|
||||
|
||||
// Check of path exists
|
||||
if (!DataTree || !(FunctionConfigMember = DataTree->GetMember( NULL, pConfigPath )))
|
||||
return false;
|
||||
|
||||
// Process each Channel
|
||||
TempMember = DataTree->GetFirstChild( FunctionConfigMember );
|
||||
while (TempMember)
|
||||
{
|
||||
// Get function parameters
|
||||
Type = (char*)DataTree->GetStr( TempMember, "Type", "Custom", true );
|
||||
|
||||
// Get or create function
|
||||
if (!strcasecmp( Type, "WatchdogClient" )) {
|
||||
Function = new CWatchdogCore( TempMember->Name );
|
||||
}
|
||||
else if (!strcasecmp( Type, "Selectable" )) {
|
||||
Function = new CSelectableCore( TempMember->Name );
|
||||
}
|
||||
else if (!strcasecmp( Type, "File" )) {
|
||||
Function = new CFileCore( TempMember->Name );
|
||||
}
|
||||
else {
|
||||
Function = GetFunction( TempMember->Name );
|
||||
}
|
||||
|
||||
// Load Function configuration and Initialise
|
||||
if (Function) {
|
||||
Function->InitConfig( TempMember );
|
||||
}
|
||||
|
||||
// Next
|
||||
TempMember = TempMember->Next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool CApplication::InitFunctionLinks( const char * pConfigPath )
|
||||
{
|
||||
TFunctionItem * FunctionItem;
|
||||
TDataMember * TempMember;
|
||||
|
||||
// Check of path exists
|
||||
if (!DataTree || !(LinkConfigMember = DataTree->GetMember( NULL, pConfigPath )))
|
||||
return false;
|
||||
|
||||
// Process each Channel
|
||||
FunctionItem = FirstFunction;
|
||||
while (FunctionItem)
|
||||
{
|
||||
// Build links for function
|
||||
if ((TempMember = DataTree->GetMember( LinkConfigMember, 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()
|
||||
{
|
||||
TFunctionItem * FunctionItem;
|
||||
|
||||
// Check for FD Events/States
|
||||
if (Selector) {
|
||||
Selector->Test();
|
||||
}
|
||||
|
||||
// Process Functions
|
||||
for (FunctionItem = FirstFunction; FunctionItem; FunctionItem = FunctionItem->Next )
|
||||
FunctionItem->Function->Process();
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user