Files
redAcore/FunctionCore.cpp
Charl Wentzel e9b50f1af9 Important Update:
- FunctionCore/SelectableCore:
  - Replace Channel->State with InState
  - Add Channel-OutState (ready for output) updated by ChannelStateEvent()
- TimingCore:
  - Add GetUpCounter() for calculating uptime string (in seconds)
2019-06-23 10:38:27 +02:00

464 lines
16 KiB
C++

/*
* 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::SetChannelState( 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->Name, ChannelStateName[State] );
// Update linked channels
LinkChannel = Channel->FirstLink;
while (LinkChannel) {
LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State );
LinkChannel = LinkChannel->Next;
}
return true;
}
//---------------------------------------------------------------------------
bool CFunctionCore::ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState )
{
TChannelLink * UpdateChannel;
TChannelLink * LinkChannel;
EChannelState OutState;
// Validate
if (!Channel)
return false;
if (!(UpdateChannel = GetLinkChannel( Channel, SourceRef )))
return false;
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s",
ProcessName, Name, Channel->Name, UpdateChannel->Channel->Ref, ChannelStateName[NewState] );
// 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->Name, ChannelStateName[OutState] );
}
return true;
}
//---------------------------------------------------------------------------
EChannelState CFunctionCore::ChannelOutState( 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") );
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;
}
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;
}
//---------------------------------------------------------------------------