Merge branch 'master' into InterAfrica

This commit is contained in:
Charl Wentzel
2019-08-18 14:15:27 +02:00
20 changed files with 1417 additions and 1086 deletions

View File

@@ -27,9 +27,9 @@ CApplication::CApplication( EDebugLevel pLogLevel )
// Set signal handlers
ConfigureSignalHandlers();
DefinitionFile = NULL;
ConfigFile = NULL;
AddressFile = NULL;
DefinitionFile = NULL;
ConfigFile = NULL;
AddressFile = NULL;
// Create output logger
Log = new CLogCore( stdout );
@@ -420,9 +420,9 @@ bool CApplication::Run( bool TerminateOnError )
{
ProcessTerminate = !FunctionItem->Function->Process();
if (TerminateOnError) {
if (ProcessTerminate)
if (ProcessTerminate) // Raise terminate flag for other processes
Terminate = true;
if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate)
if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) // If needed, allow process to terminate cleanly
CleanTerminate = false;
}
}

View File

@@ -127,10 +127,8 @@ CDataMember * CDataMember::CreateChild( const char * Name, const int Len )
bool CDataMember::Clear()
{
// Clear value
if (Value) {
if (Value)
free( Value );
Value = NULL;
}
// Clear children
while (FirstChild) {
@@ -138,7 +136,9 @@ bool CDataMember::Clear()
}
// Reset value
Type = jtNull;
Type = jtNull;
Value = NULL;
Len = 0;
return true;
}
//---------------------------------------------------------------------------

View File

@@ -20,24 +20,24 @@ static char ReturnStr[30];
//---------------------------------------------------------------------------
// Set current time on real-time clock
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{
struct tm NewTime;
struct timeval tv;
struct timezone tz;
// Get current date and time
// Get current Epoch (UTC)
gettimeofday( &tv, &tz);
// Change to new time
// Convert to local time
localtime_r( &tv.tv_sec, &NewTime );
// Set new time (keep date as is)
NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds;
// Convert back
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0;
@@ -47,43 +47,24 @@ bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds
}
//---------------------------------------------------------------------------
// Get current time from real-time clock
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current date and time
time( &UTC );
localtime_r( &UTC, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
// Set current date on real-time clock
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
{
struct tm NewDate;
struct timeval tv;
struct timezone tz;
// Get current date and time
// Get current Epoch (UTC)
gettimeofday( &tv, &tz );
// Change to new time
// Convert to local time
localtime_r( &tv.tv_sec, &NewDate );
// Set new date (keep time as is)
NewDate.tm_year = Year - 1900;
NewDate.tm_mon = Month - 1;
NewDate.tm_mday = Day;
// Convert back
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewDate );
tv.tv_usec = 0;
@@ -94,17 +75,70 @@ bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
}
//---------------------------------------------------------------------------
// Get current data from real-time clock
bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{
struct tm NewTime;
struct timeval tv;
struct timezone tz;
// Get current Epoch (UTC)
gettimeofday( &tv, &tz);
// Convert to local time
localtime_r( &tv.tv_sec, &NewTime );
// Set new date & time
NewTime.tm_year = Year - 1900;
NewTime.tm_mon = Month - 1;
NewTime.tm_mday = Day;
NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds;
// Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0;
// Set date and new time
settimeofday( &tv, &tz);
return true;
}
//---------------------------------------------------------------------------
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentTime );
// Extract time only
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
{
struct tm CurrentDate;
time_t UTC;
// Get current date and time
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentDate );
// Extract date
// Extract date only
Day = CurrentDate.tm_mday;
Month = CurrentDate.tm_mon + 1;
Year = CurrentDate.tm_year + 1900;
@@ -113,7 +147,31 @@ bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
}
//---------------------------------------------------------------------------
// Get the current date in a string
bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
time_t UTC;
// Get current UTC date and time
time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentTime );
// Extract Date & time
Day = CurrentTime.tm_mday;
Month = CurrentTime.tm_mon + 1;
Year = CurrentTime.tm_year + 1900;
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
return true;
}
//---------------------------------------------------------------------------
char const * GetDateStr( const char * DateSeparator )
{
unsigned char Day;
@@ -172,12 +230,15 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar
//---------------------------------------------------------------------------
// Get current time from real-time clock
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
struct tm CurrentTime;
// Get current date and time
localtime_r( &EpochTime, &CurrentTime );
if (LocalTime)
localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
@@ -188,12 +249,15 @@ bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minu
}
//---------------------------------------------------------------------------
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year )
bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year )
{
struct tm CurrentDate;
// Get current date and time
localtime_r( &EpochTime, &CurrentDate );
if (LocalTime)
localtime_r( &EpochTime, &CurrentDate );
else
gmtime_r( &EpochTime, &CurrentDate );
// Extract date
Day = CurrentDate.tm_mday;
@@ -204,16 +268,134 @@ bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month,
}
//---------------------------------------------------------------------------
// Get the current date in a string
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator )
bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{
unsigned char Day;
unsigned char Month;
unsigned int Year;
struct tm CurrentTime;
// Get Date
ReadDate( EpochTime, Day, Month, Year );
// Get current date and time
if (LocalTime)
localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time
Hours = CurrentTime.tm_hour;
Minutes = CurrentTime.tm_min;
Seconds = CurrentTime.tm_sec;
// Extract date
Day = CurrentTime.tm_mday;
Month = CurrentTime.tm_mon + 1;
Year = CurrentTime.tm_year + 1900;
return true;
}
//---------------------------------------------------------------------------
bool ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime )
{
int ItemsAssigned;
struct tm NewTime;
// Read time
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&(NewTime.tm_year), &(NewTime.tm_mon), &(NewTime.tm_mday),
&(NewTime.tm_hour), &(NewTime.tm_min), &(NewTime.tm_sec) );
if (ItemsAssigned != 6)
return false;
// Update time
NewTime.tm_year -= 1900;
NewTime.tm_mon -= 1;
NewTime.tm_zone = "UTC";
// Convert to Epoch Time
EpochTime = mktime( &NewTime ) + ((LocalTime)? 0 : NewTime.tm_gmtoff);
return true;
}
//---------------------------------------------------------------------------
// Read components from date/time string
bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0;
Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0;
Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Day = TempDay;
Month = TempMonth;
Year = TempYear;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime )
{
int ItemsAssigned;
int TempDay;
int TempMonth;
int TempYear;
int TempHours = -1;
int TempMinutes = -1;
int TempSeconds = -1;
// Read string
ItemsAssigned = sscanf( DateTimeStr, "%d%*[/-]%d%*[/-]%d%*[ ]%d%*[:]%d%*[:]%d",
&TempYear, &TempMonth, &TempDay, &TempHours, &TempMinutes, &TempSeconds );
// Return Values
Day = TempDay;
Month = TempMonth;
Year = TempYear;
Hours = (TempHours != -1)? TempHours : (Maxtime)? 23 : 0;
Minutes = (TempMinutes != -1)? TempMinutes : (Maxtime)? 59 : 0;
Seconds = (TempSeconds != -1)? TempSeconds : (Maxtime)? 59 : 0;
// Check if success
return ((ItemsAssigned >= 3)? true : false);
}
//---------------------------------------------------------------------------
char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator )
{
// Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d",
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day );
@@ -223,15 +405,8 @@ char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator )
}
//---------------------------------------------------------------------------
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator )
char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator )
{
unsigned char Hours;
unsigned char Minutes;
unsigned char Seconds;
// Get Date & Time
ReadTime( EpochTime, Hours, Minutes, Seconds );
// Build String
sprintf( ReturnStr, "%02d%s%02d%s%02d",
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
@@ -240,7 +415,49 @@ char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator )
}
//---------------------------------------------------------------------------
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator, const char * TimeSeparator )
char const * BuildDateTimeStr( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds,
const char * DateSeparator, const char * TimeSeparator )
{
// Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d",
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day,
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
return (ReturnStr);
}
//---------------------------------------------------------------------------
// Get the current date in a string
char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator )
{
unsigned char Day;
unsigned char Month;
unsigned int Year;
// Get Date
ReadDate( EpochTime, LocalTime, Day, Month, Year );
// Build String
return BuildDateStr( Day, Month, Year, DateSeparator );
}
//---------------------------------------------------------------------------
char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator )
{
unsigned char Hours;
unsigned char Minutes;
unsigned char Seconds;
// Get Date & Time
ReadTime( EpochTime, LocalTime, Hours, Minutes, Seconds );
// Build String
return BuildTimeStr( Hours, Minutes, Seconds, TimeSeparator );
}
//---------------------------------------------------------------------------
char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator, const char * TimeSeparator )
{
unsigned char Day;
unsigned char Month;
@@ -250,13 +467,8 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato
unsigned char Seconds;
// Get Date & Time
ReadDate( EpochTime, Day, Month, Year );
ReadTime( EpochTime, Hours, Minutes, Seconds );
ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds );
// Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d",
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day,
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
return (ReturnStr);
return BuildDateTimeStr( Day, Month, Year, Hours, Minutes, Seconds, DateSeparator, TimeSeparator );
}

View File

@@ -17,11 +17,15 @@
//---------------------------------------------------------------------------
// Get and set System Date and Time
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
bool GetTime( unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year );
bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year );
bool GetDateTime( unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
bool SetDate( unsigned char Day, unsigned char Month, unsigned Year );
bool SetDateTime( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds );
char const * GetDateStr( const char * DateSeparator = "/" );
char const * GetTimeStr( const char * TimeSeparator = ":" );
@@ -29,12 +33,28 @@ char const * GetDateTimeStr( const char * DateSeparator = "/", const char * Tim
//---------------------------------------------------------------------------
bool ReadTime( const time_t EpochTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool ReadDate( const time_t EpochTime, unsigned char &Day, unsigned char &Month, unsigned &Year );
// Build or interpret time data
bool ReadTime( const time_t EpochTime, bool LocalTime, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
bool ReadDate( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year );
bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds );
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator = "/" );
char const * BuildTimeStr( const time_t EpochTime, const char * TimeSeparator = ":" );
char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" );
bool ReadDateTime( const char * DateTimeStr, bool LocalTime, time_t &EpochTime );
bool ReadTimeStr( const char *DateTimeStr, unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false );
bool ReadDateStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year );
bool ReadDateTimeStr( const char *DateTimeStr, unsigned char &Day, unsigned char &Month, unsigned &Year,
unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds, bool Maxtime = false );
char const * BuildDateStr( unsigned char Day, unsigned char Month, unsigned Year, const char * DateSeparator = "/" );
char const * BuildTimeStr( unsigned char Hours, unsigned char Minutes, unsigned char Seconds, const char * TimeSeparator = ":" );
char const * BuildDateTimeStr( unsigned char Day, unsigned char Month, unsigned Year,
unsigned char Hours, unsigned char Minutes, unsigned char Seconds,
const char * DateSeparator = "/", const char * TimeSeparator = ":" );
char const * BuildDateStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/" );
char const * BuildTimeStr( const time_t EpochTime, bool LocalTime, const char * TimeSeparator = ":" );
char const * BuildDateTimeStr( const time_t EpochTime, bool LocalTime, const char * DateSeparator = "/", const char * TimeSeparator = ":" );
//---------------------------------------------------------------------------

View File

@@ -13,12 +13,13 @@
// redA Libraries
#include "ApplicationCore.h"
#include "DeviceCore.h"
#include "DateTimeCore.h"
//---------------------------------------------------------------------------
// Global Vars
extern char * ProcessName;
extern CApplication * Application;
//extern CApplication * Application;
//---------------------------------------------------------------------------
@@ -30,22 +31,12 @@ extern CApplication * Application;
CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
{
// Polling
PollCycle = 0;
PollStep = 0;
PollInterval = 250;
SetStartTime( &PollWait );
WaitingForReply = false;
ReplyTimeout = 200;
InvalidReply = false;
PollRetry = 0;
MaxRetries = 3;
// Data Structures
DeviceInit = true;
ConfigTypes = new CDataMember();
ValueTree = new CDataMember();
EventData = new CDataMember();
JSONparse = new CJSONparse();
}
//---------------------------------------------------------------------------
@@ -63,6 +54,8 @@ CDeviceCore::~CDeviceCore()
delete ConfigTypes;
if (ValueTree)
delete ValueTree;
if (EventData)
delete EventData;
}
//---------------------------------------------------------------------------
@@ -72,6 +65,7 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig )
CDataMember * PollConfig = NULL;
int IntVal1;
int IntVal2;
char * StrVal;
// Call Previous load config
if (!CFunctionCore::Init( FunctionConfig ))
@@ -79,11 +73,19 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig )
// Add Channels
if (!(CmdChannel = GetChannel( "Command" )))
CmdChannel = AddChannel( "Command", true, true );
CmdChannel = AddChannel( "Command", CH_ready );
else
SetChannelInState( CmdChannel, CH_ready );
if (!(DeviceChannel = GetChannel( "Device" )))
DeviceChannel = AddChannel( "Device", true, true );
DeviceChannel = AddChannel( "Device", CH_ready );
else
SetChannelInState( DeviceChannel, CH_ready );
if (!(EventChannel = GetChannel( "Event" )))
EventChannel = AddChannel( "Event", true, true );
EventChannel = AddChannel( "Event", CH_ready );
else
SetChannelInState( EventChannel, CH_ready );
// Load Polling configuration
PollConfig = Config->GetChild( "Polling", true );
@@ -108,6 +110,13 @@ bool CDeviceCore::Init( CDataMember * FunctionConfig )
ProcessName, Name, PersistFile );
}
// Event Output
StrVal = (char*)Config->GetChStr( "EventOutput", "None", true );
EventOutputType = GetEventType( StrVal );
Log->Message( LogLevel, dlMedium, "%s/%s: Event Output - Type:%s",
ProcessName, Name, EventTypeName[EventOutputType] );
// Update Devices -- may want to do it from derived class intead
if (DeviceInit) {
InitDevices( FunctionConfig );
@@ -235,15 +244,16 @@ bool CDeviceCore::CopyTemplateParam( TDevice * Device, TDeviceParam * Template,
SetDataPath( Param, DataPath, DataNode );
}
if ((Template->DataType == dtUnsigned16) || (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) {
UpdateUnsignedValue( Param, *((u_int16_t*)Template->Value), Template->Changed );
if ((Template->DataType == dtBool) || (Template->DataType == dtUnsigned16) ||
(Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) {
UpdateUnsignedValue( Param, *((u_int32_t*)Template->Value), Template->Changed );
if (Template->SetChanged)
SetUnsignedValue( Param, *((u_int16_t*)Template->Value), true );
SetUnsignedValue( Param, *((u_int32_t*)Template->Value), true );
}
else if ((Template->DataType == dtSigned16) || (Template->DataType == dtSigned32_HL) || (Template->DataType == dtSigned32_LH)) {
UpdateSignedValue( Param, *((int16_t*)Template->Value), Template->Changed );
UpdateSignedValue( Param, *((int32_t*)Template->Value), Template->Changed );
if (Template->SetChanged)
SetSignedValue( Param, *((int16_t*)Template->Value), true );
SetSignedValue( Param, *((int32_t*)Template->Value), true );
}
else if ((Template->DataType == dtFloat32_L) || (Template->DataType == dtFloat32_B)) {
UpdateFloatValue( Param, *((float*)Template->Value), Template->Changed );
@@ -381,7 +391,8 @@ bool CDeviceCore::InitDeviceParam( TDevice * Device, CDataMember * ParamConfig,
SetDataPath( Param, DataPath, DataNode );
if ((InitVal = ParamConfig->GetChild( "InitValue", false ))) {
if ((DataType == dtUnsigned16) || (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) {
if ((DataType == dtBool) || (DataType == dtUnsigned16) ||
(DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) {
UpdateUnsignedValue( Param, InitVal->GetInt(0), Read );
if (Write)
SetUnsignedValue( Param, InitVal->GetInt(0), true );
@@ -432,6 +443,7 @@ bool CDeviceCore::SetPollParam( int pPollInterval )
bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries )
{
DefReplyTimeout = pReplyTimeout;
ReplyTimeout = pReplyTimeout;
MaxRetries = pMaxRetries;
return true;
@@ -456,12 +468,13 @@ bool CDeviceCore::DeviceOnline( TDevice * Device, bool Online )
}
//---------------------------------------------------------------------------
void CDeviceCore::SetWaitForReply()
void CDeviceCore::SetWaitForReply( int CustomTimeout )
{
// Start timer
SetStartTime( &PollWait );
// Set flag
ReplyTimeout = (CustomTimeout >= 0)? CustomTimeout : DefReplyTimeout;
WaitingForReply = true;
InvalidReply = false;
}
@@ -673,6 +686,18 @@ TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * Param
// Init values
switch (DataType)
{
case dtBool :
// Create Value pointer
(*Param)->Value = (bool*)malloc( sizeof(bool) );
*((bool*)(*Param)->Value) = 0;
(*Param)->Len = sizeof(bool);
// Create Set Value pointer
(*Param)->SetValue = (bool*)malloc( sizeof(bool) );
*((bool*)(*Param)->SetValue) = 0;
(*Param)->SetLen = sizeof(bool);
break;
case dtUnsigned16 :
// Create Value pointer
(*Param)->Value = (u_int16_t*)malloc( sizeof(u_int16_t) );
@@ -963,6 +988,25 @@ bool CDeviceCore::UpdateUnsignedValue( TDeviceParam * Param, const u_int32_t Val
switch (Param->DataType)
{
case dtBool :
if (Init || (*((bool*)Param->Value) != Value))
{
// Set new value & mark change
*((bool*)Param->Value) = Value;
if (Param->DataNode)
Param->DataNode->SetInt( *((bool*)Param->Value) );
// Mark change & log event
Changed = true;
if (Log) {
char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type;
Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %u", ProcessName, Name,
((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) );
}
}
break;
case dtUnsigned16 :
if (Init || (*((u_int16_t*)Param->Value) != Value))
{
@@ -1046,6 +1090,25 @@ bool CDeviceCore::UpdateSignedValue( TDeviceParam * Param, const int32_t Value,
switch (Param->DataType)
{
case dtBool :
if (Init || (*((bool*)Param->Value) != Value))
{
// Set new value & mark change
*((bool*)Param->Value) = Value;
if (Param->DataNode)
Param->DataNode->SetInt( *((bool*)Param->Value) );
// Mark change & log event
Changed = true;
if (Log) {
char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type;
Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %d", ProcessName, Name,
((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) );
}
}
break;
case dtSigned16 :
if (Init || (*((int16_t*)Param->Value) != Value))
{
@@ -1201,6 +1264,17 @@ bool CDeviceCore::SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value,
switch (Param->DataType)
{
case dtBool :
if (Force || (*((bool*)Param->SetValue) != Value))
{
// Set new value
*((bool*)Param->SetValue) = Value;
// Mark change
Param->SetChanged = true;
}
break;
case dtUnsigned16 :
if (Force || (*((u_int16_t*)Param->SetValue) != Value))
{
@@ -1241,6 +1315,17 @@ bool CDeviceCore::SetSignedValue( TDeviceParam * Param, const int32_t Value, boo
switch (Param->DataType)
{
case dtBool :
if (Force || (*((bool*)Param->SetValue) != Value))
{
// Set new value
*((bool*)Param->SetValue) = Value;
// Mark change
Param->SetChanged = true;
}
break;
case dtSigned16 :
if (Force || (*((int16_t*)Param->SetValue) != Value))
{
@@ -1361,6 +1446,7 @@ bool CDeviceCore::SetValue( TDeviceParam * Param, const char * Value, const int
// Convert to correct type
switch (Param->DataType)
{
case dtBool :
case dtUnsigned16 :
case dtUnsigned32_HL :
case dtUnsigned32_LH :
@@ -1405,6 +1491,10 @@ bool CDeviceCore::GetValue( TDeviceParam * Param, char * Value, int &Len )
// Check if return value longer than actual value
switch (Param->DataType)
{
case dtBool :
sprintf( Value, "%u", (*((bool*)Param->Value)) );
break;
case dtUnsigned16 :
sprintf( Value, "%u", (*((u_int16_t*)Param->Value)) );
break;
@@ -1535,7 +1625,7 @@ bool CDeviceCore::GetCmdParam( const char * Start, char * Param, char ** NextPar
}
//---------------------------------------------------------------------------
int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, const int MaxLen )
int CDeviceCore::HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen )
{
int Len;
char Value[50];
@@ -1584,7 +1674,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
@@ -1593,7 +1683,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Get",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else if (!strcasecmp( "set", Value ))
@@ -1630,7 +1720,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
sprintf( OutputStr, "> set %s,%s = %s\n", Device->Name, Param->Name, Value );
Output( ChannelName, OutputStr );
Output( ChannelName, NULL, true, OutputStr );
}
}
@@ -1639,7 +1729,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Set",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else if (!strcasecmp( "status", Value ))
@@ -1659,7 +1749,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
}
else {
sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") );
Output( ChannelName, OutputStr );
Output( ChannelName, NULL, true, OutputStr );
}
// Report error
@@ -1667,7 +1757,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Status",
ProcessName, Name, ChannelName, OutputStr );
strcat( OutputStr, "\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
}
else
@@ -1677,7 +1767,7 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s', %s%s",
ProcessName, Name, ChannelName, Value, OutputStr );
strcat( OutputStr, " (comma separated values)\n" );
Output( ChannelName, OutputStr, strlen(OutputStr) );
Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) );
}
return MaxLen;
}
@@ -1686,49 +1776,114 @@ int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, cons
// Generate Event output
bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force )
{
int EventLen = EventMsgLen;
CDataMember * Path = NULL;
// Validate
if (!Param || !(Param->EventChannel))
return false;
if (EventOutputType == et_None)
return false;
// Check Timer or force
if (Force ||
(Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) )
{
// Create message
// Post event
char Message[200];
switch (Param->DataType)
{
case dtUnsigned16 :
sprintf( Message, "%s: %u\n", Param->Name, *((u_int16_t*)Param->Value) );
break;
if (true) {
// JSON output
EventData->Clear();
EventData->SetChStr( "Type", "ParamEvent" );
EventData->SetChStr( "Time", GetDateTimeStr() );
case dtUnsigned32_HL :
case dtUnsigned32_LH :
sprintf( Message, "%s: %u\n", Param->Name, *((u_int32_t*)Param->Value) );
break;
Path = EventData->GetChild( "Path", true );
Path->SetArray();
bool NewMember = true;
char * Start = NULL;
char * Pos = Param->DataPath;
while (true) {
if (!*Pos || (*Pos == '/')) {
NewMember = true;
if (Start)
Path->SetChStr( "[]", Start, Pos-Start );
if (!*Pos)
break;
}
else if (NewMember) {
NewMember = false;
Start = Pos;
}
Pos++;
}
EventData->SetChStr( "Device", Param->Device->Name );
EventData->SetChStr( "Param", Param->Name );
case dtSigned16 :
sprintf( Message, "%s: %d\n", Param->Name, *((int16_t*)Param->Value) );
break;
switch (Param->DataType) {
case dtBool : EventData->SetChBool( "Value", *((bool*)Param->Value) );
break;
case dtSigned32_HL :
case dtSigned32_LH :
sprintf( Message, "%s: %d\n", Param->Name, *((int32_t*)Param->Value) );
break;
case dtUnsigned16 : EventData->SetChBool( "Value", *((u_int16_t*)Param->Value) );
break;
case dtFloat32_L :
case dtFloat32_B :
sprintf( Message, "%s: %f\n", Param->Name, *((float*)Param->Value) );
break;
case dtUnsigned32_HL :
case dtUnsigned32_LH : EventData->SetChBool( "Value", *((u_int32_t*)Param->Value) );
break;
case dtString :
sprintf( Message, "%s: %s\n", Param->Name, (char*)Param->Value );
break;
case dtSigned16 : EventData->SetChBool( "Value", *((int16_t*)Param->Value) );
break;
default :
break;
case dtSigned32_HL :
case dtSigned32_LH : EventData->SetChBool( "Value", *((int32_t*)Param->Value) );
break;
case dtFloat32_L :
case dtFloat32_B : EventData->SetChBool( "Value", *((float*)Param->Value) );
break;
case dtString : EventData->SetChBool( "Value", (char*)Param->Value );
break;
default : EventData->SetChNull( "Value" );
break;
}
JSONparse->SetBase( EventData );
JSONparse->WriteToString( NULL, EventMsg, EventLen, 0 );
}
Output( Param->EventChannel, Message, strlen(Message) );
else {
switch (Param->DataType)
{
case dtBool : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) );
break;
case dtUnsigned16 : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) );
break;
case dtUnsigned32_HL :
case dtUnsigned32_LH : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) );
break;
case dtSigned16 : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) );
break;
case dtSigned32_HL :
case dtSigned32_LH : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) );
break;
case dtFloat32_L :
case dtFloat32_B : sprintf( EventMsg, "%s: %f\n", Param->DataPath, *((float*)Param->Value) );
break;
case dtString : sprintf( EventMsg, "%s: %s\n", Param->DataPath, (char*)Param->Value );
break;
default : sprintf( EventMsg, "%s:\n", Param->DataPath );
break;
}
}
// Send event
Output( Param->EventChannel, NULL, true, EventMsg, strlen(EventMsg) );
// Reset timer
if (Param->EventInterval) {

View File

@@ -18,14 +18,16 @@
//---------------------------------------------------------------------------
// Enumerated types
typedef enum { dtNone = 0, dtUnsigned16 = 1, dtSigned16 = 2, dtUnsigned32_HL = 3, dtUnsigned32_LH = 4,
dtSigned32_HL = 5, dtSigned32_LH = 6, dtFloat32_L = 7, dtFloat32_B = 8, dtString = 9 } EDeviceDataType;
// Constants
typedef enum { dtNone = 0, dtBool = 1, dtUnsigned16 = 2, dtSigned16 = 3, dtUnsigned32_HL = 4, dtUnsigned32_LH = 5,
dtSigned32_HL = 6, dtSigned32_LH = 7, dtFloat32_L = 8, dtFloat32_B = 9, dtString = 10 } EDeviceDataType;
const char DataTypeCount = 10;
const char DataTypeName[][20] = { "None", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH",
const char DataTypeName[][20] = { "None", "Boolean", "Unsigned16", "Signed16", "Unsigned32_HL", "Unsigned32_LH",
"Signed32_HL", "Signed32_LH", "Float32_L", "Float32_B", "String" };
typedef enum { et_None = 0, et_Simple = 1, et_JSON = 2 } EEventType;
const char EventTypeCount = 3;
const char EventTypeName[][10] = { "None", "Simple", "JSON" };
//---------------------------------------------------------------------------
// Structure prototypes
@@ -121,10 +123,10 @@ class CDeviceCore : public CFunctionCore
{
protected:
// Configuration
CDataMember * ConfigTypes = NULL;
CDataMember * ValueTree = NULL;
CJSONparse * JSONparse = NULL;
bool DeviceInit = false;
CDataMember * ConfigTypes = NULL;
CDataMember * ValueTree = NULL;
CJSONparse * JSONparse = NULL;
bool DeviceInit = false; // Initialise device on start
// Devices & Type
TDevice * FirstDeviceType = NULL;
@@ -132,24 +134,31 @@ protected:
TDevice * ActiveDevice = NULL;
// Standard channels
TChannel * DeviceChannel = NULL;
TChannel * CmdChannel = NULL;
TChannel * EventChannel = NULL;
TChannel * DeviceChannel = NULL;
TChannel * CmdChannel = NULL;
TChannel * EventChannel = NULL;
// Poll
int PollCycle; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown
int PollStep; // Position in polling sequence
timeval PollWait; // Time at which last poll was done
long PollInterval; // Minimum delay between polls
int PollCycle = 0; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown
int PollStep = 0; // Position in polling sequence
timeval PollWait = {0,0}; // Time at which last poll was done
long PollInterval = 250; // Minimum delay between polls
// Reply
bool WaitingForReply; // Command sent, waiting for reply
bool InvalidReply; // Invalid reply received
long ReplyTimeout; // Max waiting time for reply
bool WaitingForReply = false; // Command sent, waiting for reply
bool InvalidReply = false; // Invalid reply received
long DefReplyTimeout = 500; // Default Max waiting time for reply
long ReplyTimeout = 500; // Max waiting time for reply
// Retry
int PollRetry; // No of polling retries that has timed out
int MaxRetries; // Max allowed retries
int PollRetry = 0; // No of polling retries that has timed out
int MaxRetries = 3; // Max allowed retries
// Event output
EEventType EventOutputType = et_None;
CDataMember * EventData = NULL;
const int EventMsgLen = 1000;
char EventMsg[1000] = {0};
// Manage Devices
bool DestroyDevice( TDevice ** Device );
@@ -231,11 +240,7 @@ protected:
Param = &((*Param)->Next);
return Param;
}
inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) {
if (!Device) return NULL;
TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup;
return ParamGroup;
}
inline TDeviceParam * GetNextReadParam( TDevice * Device, TDeviceParam * LastParam = NULL ) {
if (!Device) return NULL;
TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam;
@@ -275,6 +280,12 @@ protected:
return Group;
}
inline TDeviceParamGroup * GetNextParamGroup( TDevice * Device, TDeviceParamGroup * LastParamGroup = NULL ) {
if (!Device) return NULL;
TDeviceParamGroup * ParamGroup = (LastParamGroup)? LastParamGroup->NextGroup : Device->FirstParamGroup;
return ParamGroup;
}
// Find Param Groups Items
inline TDeviceParamItem * GetParamItem( TDeviceParamGroup * Group, const char * ParamName ) {
TDeviceParamItem ** Item = GetParamItemPtr( Group, ParamName );
@@ -295,6 +306,12 @@ protected:
if (!strcasecmp( TypeName, DataTypeName[Type])) break;
return (Type == DataTypeCount)? dtNone : (EDeviceDataType)Type;
}
inline EEventType GetEventType( const char * TypeName ) {
int Type;
for (Type = 0; Type < EventTypeCount; Type++)
if (!strcasecmp( TypeName, EventTypeName[Type])) break;
return (Type == EventTypeCount)? et_None : (EEventType)Type;
}
bool CompareParamString( const char * ParamValue, const int ParamLen, const char * Value, const int Len );
@@ -306,7 +323,7 @@ protected:
virtual bool DeviceOnline( TDevice * Device, bool Online );
// Handle Reply Timing
virtual void SetWaitForReply();
virtual void SetWaitForReply( int CustomTimeout = -1 );
virtual void ValidReplyReceived();
virtual bool CheckReplyTimeout();
@@ -386,7 +403,7 @@ public:
// Handle Interface Commands
bool GetCmdParam( const char * Start, char * Param, char ** NextParam );
int HandleCommand( const char *ChannelName, const char * Data, const int MaxLen );
int HandleCommand( const char *ChannelName, const char * SourceRef, const char * Data, const int MaxLen );
// Command Text Interfaces
bool SetValue( TDeviceParam * Param, const char * Value, const int Len, bool Force );

View File

@@ -86,7 +86,7 @@ TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Ap
// Create Channel if necessary
if (CreateChannel) {
AddChannel( Name );
AddChannel( Name, CH_ready );
}
// Set Parameters
@@ -260,7 +260,7 @@ int CFileCore::WriteToFD( int FD, const char * Data, int Len )
//---------------------------------------------------------------------------
// Manual Data Input/Output
int CFileCore::Input( const char * ChannelName, const char * Data, int Len )
int CFileCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len )
{
TFileHandle * FileHandle = NULL;
int BytesWritten = 0;

View File

@@ -73,7 +73,7 @@ public:
virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout );
// Data Input
virtual int Input( const char * ChannelName, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
// Processing data
virtual bool Process();

View File

@@ -1,222 +0,0 @@
/*
* FunctionCore.h
*
* Created on: 18 May 2016
* Author: wentzelc
*/
#ifndef REDACORE_FUNCTIONCORE_H_
#define REDACORE_FUNCTIONCORE_H_
// Standard C/C++ Libraries
/* none */
// redA Libraries
#include "LogCore.h"
#include "DataTreeCore.h"
#include "CharBufferCore.h"
#include "ItemBufferCore.h"
//---------------------------------------------------------------------------
// Preview
typedef struct SChannel TChannel;
typedef struct SChannelLink TChannelLink;
typedef struct SProcessBuffer TProcessBuffer;
typedef struct SProcessItem TProcessItem;
class CFunctionCore;
//---------------------------------------------------------------------------
struct SChannel
{
char * Name;
TChannelLink * FirstInput;
TChannelLink * FirstOutput;
bool InputEnabled;
bool OutputEnabled;
TProcessBuffer * InputBuffer;
TChannel * Next;
};
//---------------------------------------------------------------------------
struct SChannelLink
{
CFunctionCore * Function;
char * Name;
SChannelLink * Next;
};
//---------------------------------------------------------------------------
struct SProcessBuffer
{
// Process buffer
char * Name; // Name of buffer;
CItemBufferCore Buffer; // Message buffer
unsigned long LastRefNo; // Last RefNo for item
// Input parameters
bool PassthroughCallback; // Send Callback once processed message has been passed on, else once processed
// Output parameters
TChannel * OutputChannel; // Channel to which to pass buffer output
bool OutputCallback; // Expect callback on output?
TProcessBuffer * Next; // Next buffer in list
};
//---------------------------------------------------------------------------
struct SProcessItem
{
// Input Parameters
TChannel * SourceChannel;
char * SourceRef;
bool SourceCallback;
// Processing Parameters
bool Processed;
bool Completed;
// Output Parameters
timeval CallbackTimer;
TChannelLink FirstOutput;
// Input Data
void * DataIn;
int DataInLen;
// Output Data
void * DataOut;
int DateOutLen;
};
//---------------------------------------------------------------------------
class CFunctionCore_not_used
{
protected:
// Function Definition
char * Name;
char * Type;
// Configuration
CDataTree * DataTree;
TDataMember * ConfigMember;
TDataMember * LinkConfigMember;
// Channels
TChannel * FirstChannel;
// Processing Queues
TProcessBuffer * FirstProcessBuffer;
// Logging
CLogCore * Log;
EDebugLevel LogLevel;
int LogOutput;
// Stored Output
char * StoredOutput;
int StoredOutputLen;
// Manage Channel
inline TChannel * GetChannel( const char * Name ) {
if (!Name) return NULL;
TChannel * Channel = FirstChannel;
while (Channel && strcmp( Name, Channel->Name ))
Channel = Channel->Next;
return Channel;
}
// Load configuration
virtual bool LoadConfigData();
virtual bool LoadChannelLinkData();
// Data Input/Output
virtual int Output( const TChannel * Channel, const char * Data, int Len );
virtual bool PullInput( TChannel * Channel );
// Processing Queue
TProcessItem * CreateProcessItem();
public:
// Life cycle
CFunctionCore_not_used( const char * pName, const char * Type );
virtual ~CFunctionCore_not_used();
// Load Configuration
virtual bool Init();
bool InitConfig( const char * pConfigPath );
bool InitConfig( TDataMember * pConfigMember );
bool InitChannelLinks( const char * pLinkConfigPath );
bool InitChannelLinks( TDataMember *pLinkConfigMember );
// Set Parameters Manually
bool SetLogParam( EDebugLevel pDebugLevel, int pOutputDisplay );
bool SetLogLevel( EDebugLevel pDebugLevel );
// Miscellaneous
inline const char * GetName() { return Name; };
inline const char * GetType() { return Type; };
// Manage Channels
virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true );
inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->OutputEnabled = pOutputEnable;
return true;
}
inline bool SetChannelInEnable( const char * ChannelName, const bool pInputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->InputEnabled = pInputEnable;
return true;
}
inline bool isInputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->InputEnabled : false);
}
inline bool isOutputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->OutputEnabled : false);
}
// Pushing Data Output -> Input
virtual int Output( const char * ChannelName, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * Data, int Len = -1 );
// Pulling Data Input <- Output
virtual bool PullInput( const char * ChannelName );
virtual bool PullOutput( const char * ChannelName, char ** Data, int * Len = NULL );
// Manages Process Buffers
TProcessBuffer * CreateProcessBuffer( const char * Name );
TProcessBuffer * GetProcessBuffer( const char * Name );
TProcessItem * CreateProcessItem( const char * BufferName );
TProcessItem * GetProcessItem( const char BufferName, const int Ref );
bool DestroyProcessItem( const char * BufferName, const int Ref );
// Queued Output
virtual bool OutputMessage( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, bool Callback, const char * Data, int Len = -1 );
virtual bool OutputMessageCallback( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, const bool Success, const char * Error );
virtual bool InputMessage( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo, bool Callback, const char * Data, int Len = -1 );
virtual bool InputMessageCancel( TChannel * SourceChannel, const char * TargetChannelName, const int RefNo );
// Automated Data Input/Output
virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional );
virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional );
virtual bool Process() = 0;
};
//---------------------------------------------------------------------------
#endif /* REDACORE_FUNCTIONCORE_H_ */

View File

@@ -30,9 +30,8 @@ extern CApplication * Application;
CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType )
{
// Set name
if (pName) {
if (pName)
Name = strdup( pName );
}
// Logging
Log = Application->Log;
@@ -44,35 +43,19 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p
CFunctionCore::~CFunctionCore()
{
TChannel * NextChannel = NULL;
TChannelLink * NextLinkedChannel = 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) {
if (FirstChannel->Name)
free( FirstChannel->Name );
}
// Destroy Linked Inputs
while (FirstChannel->FirstInput) {
if (FirstChannel->FirstInput->Name) {
free( FirstChannel->FirstInput->Name );
}
NextLinkedChannel = FirstChannel->FirstInput->Next;
delete FirstChannel->FirstInput;
FirstChannel->FirstInput = NextLinkedChannel;
}
// Destroy Linked Outputs
while (FirstChannel->FirstOutput) {
if (FirstChannel->FirstOutput->Name) {
free( FirstChannel->FirstOutput->Name );
}
NextLinkedChannel = FirstChannel->FirstOutput->Next;
delete FirstChannel->FirstOutput;
FirstChannel->FirstOutput = NextLinkedChannel;
}
if (FirstChannel->Ref)
free( FirstChannel->Ref );
// Destroy Channel
NextChannel = FirstChannel->Next;
@@ -101,6 +84,9 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
if (!FunctionConfig )
return false;
// Set Type
FunctionConfig->SetChStr( "Type", Type );
// Configure Logging/Debugging
LogConfig = FunctionConfig->GetChild( "Log", true );
pLogLevel = Log->ReadLogLevel( LogConfig );
@@ -109,13 +95,8 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
// Load Channels
ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true );
while (ChannelConfig)
{
if (ChannelConfig->GetName()) {
AddChannel( ChannelConfig->GetName(),
ChannelConfig->GetChBool( "InputEnabled", true, true ),
ChannelConfig->GetChBool( "OutputEnabled", false, true ));
}
while (ChannelConfig) {
AddChannel( ChannelConfig->GetName(), CH_off );
ChannelConfig = ChannelConfig->GetNextPeer();
}
@@ -124,7 +105,6 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
ConfigName = (char*)FunctionConfig->GetChStr( "Config" );
Config = Application->Config->GetChild( ConfigName, true );
}
if (Config->isNull()) Config->SetObject();
return true;
}
@@ -150,10 +130,11 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig )
while (FunctionMember)
{
// Get Parameters
LinkOutputChannel( Channel->Name,
FunctionMember->GetChStr( "Function" ),
FunctionMember->GetChStr( "Channel" ),
FunctionMember->GetChBool( "Bidirectional" ) );
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();
}
}
@@ -181,7 +162,7 @@ bool CFunctionCore::SetLogLevel( EDebugLevel pDebugLevel )
}
//---------------------------------------------------------------------------
TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInputEnable, const bool pOutputEnable )
TChannel * CFunctionCore::AddChannel( const char * ChannelName, const EChannelState State )
{
TChannel ** Channel = NULL;
@@ -203,166 +184,263 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu
// 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",
ProcessName, Name, ChannelName );
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]);
}
// 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 )
bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State )
{
CFunctionCore * OutFunction = NULL;
TChannel * Channel = NULL;
TChannelLink ** LinkedChannel = NULL;
EChannelState OldState = Channel->InState;
TChannelLink * LinkChannel;
// Get Channel
if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) {
// Validate
if (!Channel)
return false;
}
// Check if linked Channel exists
LinkedChannel = &(Channel->FirstInput);
while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) {
LinkedChannel = &((*LinkedChannel)->Next);
}
// Update state
Channel->InState = State;
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s",
ProcessName, Name, Channel->Ref, ChannelStateName[State] );
// Create if not found
if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink;
// Update linked channels
LinkChannel = Channel->FirstLink;
while (LinkChannel) {
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s",
ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] );
// Set Parameters
(*LinkedChannel)->Function = OutFunction;
(*LinkedChannel)->Name = strdup( OutChannelName );
// Trigger Linked Channel Events
LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel );
LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State );
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Input Linked - '%s'/'%s' <-- '%s'/'%s'",
ProcessName, Name, Name, ChannelName, OutFunction->GetName(), OutChannelName );
}
// Link Return direction as well
if (Bidirectional) {
return OutFunction->LinkInputChannel( OutChannelName, Name, ChannelName, false );
LinkChannel = LinkChannel->Next;
}
return true;
}
//---------------------------------------------------------------------------
bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional )
bool CFunctionCore::UpdateChannelOutState( TChannel * Channel )
{
TChannel * OutChannel = NULL;
CFunctionCore * InFunction = NULL;
TChannel * InChannel = NULL;
TChannelLink * LinkChannel;
EChannelState OutState;
// 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->Ref, ChannelStateName[OutState] );
}
return true;
}
//---------------------------------------------------------------------------
EChannelState CFunctionCore::GetChannelOutState( 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 (!(OutChannel = GetChannel( ChannelName )) ||
!(InFunction = Application->GetFunction( InFunctionName )) ||
!(InChannel = InFunction->GetChannel( InChannelName )) ) {
if (!(Channel = GetChannel( ChannelName )) ||
!(LinkFunction = Application->GetFunction( LinkFunctionName )) ||
!(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) {
return false;
}
// Check if linked Channel exists
LinkedChannel = &(OutChannel->FirstOutput);
while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) {
LinkedChannel = &(Channel->FirstLink);
while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel))
LinkedChannel = &((*LinkedChannel)->Next);
}
// Create if not found
if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink;
// Set Parameters
(*LinkedChannel)->Function = InFunction;
(*LinkedChannel)->Name = strdup( InChannelName );
// Set Parameters
(*LinkedChannel)->Function = LinkFunction;
(*LinkedChannel)->Channel = LinkChannel;
(*LinkedChannel)->Input = Input;
(*LinkedChannel)->Output = Output;
// Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s'/'%s' --> '%s'/'%s'",
ProcessName, Name, Name, ChannelName, InFunction->GetName(), InChannelName );
}
// 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") );
// Link return direction as well
if (Bidirectional) {
return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false );
}
// 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") );
// Trigger Forward Channel Events
LinkFunction->UpdateChannelOutState( LinkChannel );
LinkFunction->ChannelStateEvent( LinkChannel, Channel->Ref, CH_off, Channel->InState );
// Trigger Reverse Channel Events
UpdateChannelOutState( Channel );
ChannelStateEvent( Channel, LinkChannel->Ref, CH_off, LinkChannel->InState );
return true;
}
//---------------------------------------------------------------------------
// Manual Data Input/Output
int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len )
bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName )
{
TChannel * Channel = NULL;
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;
}
// Trigger Channel Events
LinkFunction->UpdateChannelOutState( LinkChannel );
UpdateChannelOutState( Channel );
return true;
}
//---------------------------------------------------------------------------
int CFunctionCore::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
// Validate
if (!ChannelName || !Data) {
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' - Input rejected, Channel not found",
ProcessName, Name, ChannelName );
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->InputEnabled) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
ProcessName, Name, ChannelName );
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;
}
else {
// Return processed bytes
if (Len == -1) {
Len = strlen( Data );
}
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
return Len;
// 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 * Data, int Len )
int CFunctionCore::Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
// Validate
if (!ChannelName) {
if (!ChannelName || !*ChannelName) {
return 0;
}
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel not found",
ProcessName, Name, 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, Data, Len );
return Output( Channel, TargetRef, SourceRef, Data, Len );
}
}
//---------------------------------------------------------------------------
int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat )
int CFunctionCore::Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat )
{
TChannelLink * OutChannel = NULL;
TChannelLink * LinkChannel = NULL;
int TempLen = 0;
int OutLen = 0;
@@ -371,123 +449,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len,
return 0;
}
// Check if enabled
if (!Channel->OutputEnabled) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel output disabled",
ProcessName, Name, Channel->Name );
return 0;
}
// Log event
if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:",
ProcessName, Name, Channel->Name );
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) {
if (Len == -1)
Len = strlen( Data );
}
OutChannel = Channel->FirstOutput;
while (OutChannel) {
TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len );
OutLen = (TempLen > OutLen)? TempLen : OutLen;
OutChannel = OutChannel->Next;
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;
}
//---------------------------------------------------------------------------
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/%s: Channel '%s' - Input failed, Channel not found",
ProcessName, 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/%s: Channel '%s' - Input failed, Channel input disabled",
ProcessName, 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/%s: Channel '%s' - Output failed, Channel not found",
ProcessName, Name, ChannelName );
return 0;
}
else if (!Channel->InputEnabled) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output failed, Channel output disabled",
ProcessName, 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/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
return Len;
}
}
//---------------------------------------------------------------------------

View File

@@ -17,6 +17,12 @@
//---------------------------------------------------------------------------
// Enumarate Types
typedef enum { CH_off = 0, CH_standby = 1, CH_wait = 2, CH_ready = 3 } EChannelState;
const char ChannelStateName[][15] = { "Off", "Standby", "Waiting", "Ready" };
//---------------------------------------------------------------------------
// Preview
typedef struct SChannel TChannel;
typedef struct SChannelLink TChannelLink;
@@ -28,12 +34,12 @@ class CFunctionCore;
struct SChannel
{
char * Name = NULL;
char * Ref = NULL;
TChannelLink * FirstInput = NULL;
TChannelLink * FirstOutput = NULL;
TChannelLink * FirstLink = NULL; // List of channels linked for input/output
bool InputEnabled = NULL;
bool OutputEnabled = NULL;
EChannelState InState = CH_off; // Channel ready to receive input (determined by parent function)
EChannelState OutState = CH_off; // Channel ready to send output (determined by InStates of linked channels)
TChannel * Next = NULL;
};
@@ -42,7 +48,10 @@ struct SChannel
struct SChannelLink
{
CFunctionCore * Function = NULL;
char * Name = NULL;
TChannel * Channel = NULL;
bool Input = false;
bool Output = false;
SChannelLink * Next = NULL;
};
@@ -73,10 +82,6 @@ protected:
EDebugLevel LogLevel = dlNone;
int LogOutput = loNone;
// Stored Output
char * StoredOutput = NULL;
int StoredOutputLen = 0;
// Manage Channel
inline TChannel * GetChannel( const char * pName ) {
if (!pName) return NULL;
@@ -85,10 +90,16 @@ protected:
Channel = Channel->Next;
return Channel;
}
inline TChannelLink * GetLinkChannel( TChannel * Channel, const char * LinkRef ) {
if (!Channel || !LinkRef ) return NULL;
SChannelLink * LinkChannel = Channel->FirstLink;
while (LinkChannel && strcmp( LinkRef, LinkChannel->Channel->Ref ))
LinkChannel = LinkChannel->Next;
return LinkChannel;
}
// Data Input/Output
virtual int Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat = loNone );
virtual bool PullInput( TChannel * Channel );
virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone );
public:
// Life cycle
@@ -108,39 +119,20 @@ public:
inline const char * GetType() { return Type; };
// Manage Channels
virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true );
inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->OutputEnabled = pOutputEnable;
return true;
}
inline bool SetChannelInEnable( const char * ChannelName, const bool pInputEnable ) {
TChannel * Channel = GetChannel( ChannelName );
if (!Channel) return false;
Channel->InputEnabled = pInputEnable;
return true;
}
inline bool isInputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->InputEnabled : false);
}
inline bool isOutputEnabled( const char * ChannelName ) {
TChannel * Channel = GetChannel( ChannelName );
return ((Channel)? Channel->OutputEnabled : false);
}
virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State );
virtual bool SetChannelInState( TChannel * Channel, const EChannelState State );
virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { return true; };
virtual bool UpdateChannelOutState( TChannel * Channel );
virtual EChannelState GetChannelOutState( TChannel * Channel, const char * TargetRef );
// Pushing Data Output -> Input
virtual int Output( const char * ChannelName, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * Data, int Len = -1 );
// Pulling Data Input <- Output
virtual bool PullInput( const char * ChannelName );
virtual bool PullOutput( const char * ChannelName, char ** Data, int * Len = NULL );
virtual int Output( const char * ChannelName, const char * TargetRef, const bool SourceRef, const char * Data, int Len = -1 );
virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
// Automated Data Input/Output
virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional );
virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional );
virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output );
virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName );
virtual bool Process() = 0;
friend class CApplication;

View File

@@ -8,6 +8,7 @@
// Standard C/C++ Libraries
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
// redA Libraries
#include "JSONparseCore.h"
@@ -145,7 +146,7 @@ bool CJSONparse::WriteToFile( const char * BasePath, const char * FilePath, cons
// Open file
if ((Handle = open( FilePath, O_CREAT|O_WRONLY|O_TRUNC, 0660 )) < 0) {
Error = true;
sprintf( ErrorText, "Could not open file" );
sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) );
return false;
}
@@ -243,7 +244,7 @@ bool CJSONparse::ReadFromFile( const char * BasePath, const char * FilePath )
// Open file
if ((Handle = open( FilePath, O_RDONLY )) < 0) {
Error = true;
sprintf( ErrorText, "Could not open file" );
sprintf( ErrorText, "Could not open file - [%d] %s", errno, strerror(errno) );
return false;
}
@@ -272,7 +273,7 @@ bool CJSONparse::ReadFromHandle( const char * BasePath, int Handle, bool pRefill
InputHandle = Handle;
// Load Buffer
CreateBuffer( 500 );
CreateBuffer( 1000 );
if (!FillBuffer()) {
Error = true;
sprintf( ErrorText, "Could not read from file" );
@@ -351,11 +352,11 @@ bool CJSONparse::ReadFromBuffer( const char * BasePath )
// Parse Root Object
SkipWhiteSpace();
if (!ParseObject( BaseMember )) {
if (!ParseObject( BaseMember ) && !Error && !ParseArray( BaseMember )) {
if (!Error) {
Error = true;
CharNo += BufPos-Mark;
sprintf( ErrorText, "First entry in file must be an Object on line %d:%d", LineNo, CharNo );
sprintf( ErrorText, "First entry in file must be an Object or Array on line %d:%d", LineNo, CharNo );
}
FreeBuffer();
return false;
@@ -474,7 +475,7 @@ bool CJSONparse::ParseString( char ** Value, int &Len )
while (true)
{
// Check for special characters
if ((EndMark = strpbrk( BufPos, "\"/\\\n\t\b\f\n\r" ))) {
if ((EndMark = strpbrk( BufPos, "\"\\\n\t\b\f\n\r" ))) { /*"\"/\\\n\t\b\f\n\r" (forward slash included)*/
BufPos = EndMark;
} else if (RefillBuffer) {
FillBuffer();
@@ -690,7 +691,7 @@ bool CJSONparse::ParseArray( CDataMember * Array )
SkipWhiteSpace();
if (!ParseObject( *Member ) && !Error && !ParseArray( *Member ) && !Error && !ParseString( *Member ) && !Error && !ParsePrimitive( *Member ) ) {}
if (Error) {
delete Member;
delete *Member;
return false;
}
else {
@@ -815,7 +816,7 @@ bool CJSONparse::PrintString( char * String, int Len )
{
// Scan for special chars
Mark = BufPos;
while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && (*BufPos != '/') && (*BufPos != '"'))
while ((*BufPos >= 32) && (*BufPos <= 126) && (*BufPos != '\\') && /*(*BufPos != '/') &&*/ (*BufPos != '"'))
BufPos++;
// Print Portion
@@ -1028,9 +1029,7 @@ bool CJSONparse::PrintArray( CDataMember * Array, const int Indent )
break;
case jtString :
if ((Print( this, "\"", 1 ) < 0) ||
(Print( this, Member->Value, Member->Len ) < 0) ||
(Print( this, "\"", 1 ) < 0))
if (!PrintString( Member->Value, Member->Len ))
return false;
break;

View File

@@ -17,7 +17,7 @@
//---------------------------------------------------------------------------
// Global vars
char LogStr[1000]; // Temporary var to create log messages, globally available to save on memory operations
char LogStr[5000]; // Temporary var to create log messages, globally available to save on memory operations
const char * LogOutputName[] = { "None", "Raw", "Normal", "Hex", "Bin" };

View File

@@ -38,9 +38,6 @@ CSelectableBare::CSelectableBare( const char * pName, const char * pType ) : CFu
{
// Quick access
Selector = Application->Selector;
// Handles
FirstHandle = NULL;
}
//---------------------------------------------------------------------------
@@ -97,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
if (!*Handle)
{
// Create File handle at end of list
*Handle = (THandle*)calloc( 1, sizeof(THandle) );
*Handle = new THandle;
// Set name
if (HandleName) {
@@ -106,7 +103,8 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
}
// Set File Descriptor
(*Handle)->FD = -1;
(*Handle)->Function = this;
(*Handle)->FD = -1;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Created",
@@ -115,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
// Create Matching Channel
if (CreateChannel) {
(*Handle)->Channel = AddChannel( HandleName );
(*Handle)->Channel = AddChannel( HandleName, CH_off );
}
return *Handle;
@@ -162,61 +160,41 @@ bool CSelectableBare::DestroyHandle( THandle * Handle )
free( Handle->Name );
if (Handle->Path)
free( Handle->Path );
if (Handle->HostName)
free( Handle->HostName );
if (Handle->PortName)
free( Handle->PortName );
if (Handle->AddressInfo)
freeaddrinfo( Handle->AddressList );
// Destroy Buffers
if (Handle->InBuffer)
delete Handle->InBuffer;
if (Handle->OutBuffer)
delete Handle->OutBuffer;
// Clear Input Markers
if (Handle->InMarker)
free( Handle->InMarker );
// Destroy Pointer
free( Handle );
delete Handle;
return true;
}
//---------------------------------------------------------------------------
bool CSelectableBare::ClearHandle( THandle * Handle )
bool CSelectableBare::HandleState( THandle * Handle, EConnectState State )
{
EChannelState ChannelState = CH_off;
// Validate
if (!Handle) {
if (!Handle || (Handle->State == State))
return false;
}
// Reset Type related parameters
if (Handle->Path) {
free( Handle->Path );
Handle->Path = NULL;
}
if (Handle->HostName) {
free( Handle->HostName );
Handle->HostName = NULL;
}
if (Handle->PortName) {
free( Handle->PortName );
Handle->PortName = NULL;
}
if (Handle->AddressList) {
freeaddrinfo( Handle->AddressList );
Handle->AddressList = NULL;
Handle->AddressInfo = NULL;
}
// Execute call back for state
if (Handle->StateCallback[ (int)State ])
(Handle->StateCallback[ (int)State ])( this, Handle, State );
// Reset Parameters
Handle->Type = ctNone;
// Change state
Handle->State = State;
// Log event
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None",
ProcessName, Name, Handle->Name );
// Update Channel
if (Handle->Channel) {
if ((Handle->State == csPreparing) || (Handle->State == csPrepared) || (Handle->State == csWaitingtoOpen))
ChannelState = CH_wait;
else if ((Handle->State == csOpen) || (Handle->State == csDataWaiting))
ChannelState = CH_ready;
else if (Handle->AutoManage)
ChannelState = CH_standby;
else
ChannelState = CH_off;
if (Handle->Channel->InState != ChannelState)
SetChannelInState( Handle->Channel, ChannelState );
}
return true;
}
//---------------------------------------------------------------------------
@@ -322,9 +300,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len );
Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else {
Output( Handle->Channel, Data, Len );
Output( Handle->Channel, NULL, true, Data, Len );
}
// Clear processed bytes from buffer
@@ -342,9 +320,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len );
Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else {
Output( Handle->Channel, Data, Len );
Output( Handle->Channel, NULL, true, Data, Len );
}
// Clear processed bytes from buffer
@@ -355,10 +333,11 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
}
//---------------------------------------------------------------------------
int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
int CSelectableBare::Open( THandle * Handle )
{
THandle * NewHandle = NULL;
// Validate
if (!Handle || (Handle->Type == ctNone)) {
return -1;
@@ -394,11 +373,11 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
Selector->Add( Handle->FD, true, false, Handle, this );
}
// Set state
ChangeState( Handle, csOpen );
// Set timer (for re-open or auto-close)
SetStartTime( &Handle->LastAction );
// Set state
HandleState( Handle, csOpen );
return (NewHandle)? NewHandle->FD : -1;
};
//---------------------------------------------------------------------------
@@ -414,7 +393,16 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
// Close Handle
Fail = (close( Handle->FD ))? true : false;
ChangeState( Handle, ((Fail)? csFailed : csClosed) );
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Start timer (for re-open)
if (QuickReopen)
@@ -426,15 +414,8 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s",
ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") );
// Remove from Select List
if (!Fail && Selector) {
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
// Set State
HandleState( Handle, ((Fail)? csFailed : csClosed) );
return true;
}
//---------------------------------------------------------------------------
@@ -534,7 +515,7 @@ bool CSelectableBare::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Attempt to re-open port
Open( Handle, true );
Open( Handle );
}
}
@@ -678,7 +659,7 @@ int CSelectableBare::WriteToFD( int FD, const char * Data, int Len, bool Force )
}
//---------------------------------------------------------------------------
int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len )
int CSelectableBare::Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len )
{
TChannel * Channel = NULL;
THandle * Handle = NULL;
@@ -694,20 +675,20 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
// Get Channel
if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName );
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->InputEnabled) {
else if (Channel->InState == CH_off) {
// Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel off",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
// Log event
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
ProcessName, Name, ChannelName );
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
// Find Linked handle
Handle = FirstHandle;
@@ -725,8 +706,8 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
if (!HandleCount) {
// Handle not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found",
ProcessName, Name, ChannelName );
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, No Handles found",
ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0;
}
@@ -752,11 +733,11 @@ int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{
// Complete opening process
Open( Handle, true );
Open( Handle );
// Check if Handle is open
if (Handle->State == csOpenRequest) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle",
if ((Handle->State == csPreparing) || (Handle->State == csPrepared)) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Preparing (auto-managed) Handle",
ProcessName, Name, Handle->Name );
return 0;
}
@@ -833,27 +814,25 @@ bool CSelectableBare::Process()
while (Handle)
{
// Auto manage handles
if ((Handle->State == csOpenRequest))
{
// Resolve then open socket
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
}
if (Handle->State == csPrepared) {
// Proceed to open
Open( Handle );
}
else if (((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) )
{
else if ((Handle->State != csOpen) && Handle->AutoManage && Handle->Persistent) {
// Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) {
Open( Handle, false );
Open( Handle );
}
}
else if (Handle->Channel && (Handle->Channel->InState == CH_off) && Handle->AutoManage) {
// Set channel to standby
SetChannelInState( Handle->Channel, CH_standby );
}
// Check Input buffers
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0))
{
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) {
// Check duration since last PortIn
if (Timeout( Handle->InStart, Handle->InTimeout ))
{
if (Timeout( Handle->InStart, Handle->InTimeout )) {
// Process Input
ProcessInputBuffer( Handle, true );
@@ -863,95 +842,14 @@ bool CSelectableBare::Process()
}
// Check for auto close (but not on servers)
if ((Handle->State == csOpen) && (Handle->Type != ctTCPserver) && (Handle->Type != ctUNIXserver) && Handle->AutoManage && !Handle->Persistent)
{
if ((Handle->State == csOpen) && Handle->AutoManage && !Handle->Persistent) {
// Close port after timeout
if (Timeout( Handle->LastAction, Handle->CloseTimeout )) {
Close( Handle, true );
}
}
Handle = Handle->Next;
}
return true;
}
//---------------------------------------------------------------------------
bool CSelectableBare::BuildArgs( const char * ExecPath, int &Count, char * Args[] )
{
bool ParamStarted = false;
bool OpenQuotes = false;
char * MatchPos = NULL;
char * StartPos = NULL;
int Len;
// Validate
if (!ExecPath || !*ExecPath) {
return false;
}
// Split params
MatchPos = (char*)ExecPath;
for (;;)
{
// Look for whitespace
if (!ParamStarted)
{
// Quotes starts quoted parameter
if (*MatchPos == '"') {
ParamStarted = true;
OpenQuotes = true;
StartPos = MatchPos+1; // Skip starting quote
}
// Non-whitespace starts normal parameter
else if ((*MatchPos != ' ') && (*MatchPos != 0)) {
ParamStarted = true;
StartPos = MatchPos;
}
}
else if (OpenQuotes)
{
// Another quote ends parameter
if (*MatchPos == '"') {
Len = MatchPos-StartPos-1; // Skip end quote
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
OpenQuotes = false;
}
}
else
{
// Whitespace ends parameter
if ((*MatchPos == ' ') || (*MatchPos == 0)) {
Len = MatchPos-StartPos;
Args[Count] = (char*)malloc( Len+1 );
strncpy( Args[Count], StartPos, Len );
Args[Count][Len] = 0;
Count++;
ParamStarted = false;
}
}
// Next char, unless NULL
if (*MatchPos)
MatchPos++;
else
break;
}
// Check all parameters closed
if (ParamStarted) {
Count = 0;
Args[0] = NULL;
return false;
}
// Set last Param to NULL
Args[Count] = NULL;
return true;
}
//---------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,8 @@
// Standard C/C++ Libraries
#include <ctype.h>
#include <signal.h>
#include <netdb.h>
// redA Libraries
#include "FunctionCore.h"
@@ -22,8 +24,8 @@ typedef enum { ctNone = 0, ctSerial = 1, ctLinePrinter = 2, ctForkPipe = 3, ctUN
const char ConnectTypeName[][20] = { "None", "Serial Port", "Line Printer", "Fork Pipe", "UNIX Server", "UNIX Client", "UNIX Remote Client",
"UDP Server", "UDP Client", "UDP Remote Client", "TCP Server", "TCP Client", "TCP Remote Client", "Custom" };
typedef enum { csNone = 0, csOpenRequest = 1, csWaitingtoOpen = 2, csOpen = 3, csDataWaiting = 4, csClosed = 5, csFailed = 6 } EConnectState;
const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" };
typedef enum { csNone = 0, csPreparing = 1, csPrepared = 2, csWaitingtoOpen = 3, csOpen = 4, csDataWaiting = 5, csClosed = 6, csFailed = 7 } EConnectState;
const char ConnectStateName[][15] = { "None", "Preparing", "Prepared", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" };
//---------------------------------------------------------------------------
@@ -44,13 +46,14 @@ const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "O
// Previews
typedef struct SSelectHandle TSelectHandle;
typedef struct SHandle THandle;
typedef struct SResolveReq TResolveReq;
class CSelect;
class CSelectableBare;
class CSelectableCore;
// Callback function for handle events
typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState State );
typedef void (*FHandleCallback)( CSelectableBare * Function, THandle * Handle, EConnectState OldState );
//---------------------------------------------------------------------------
@@ -68,7 +71,6 @@ struct SSelectHandle {
// List
TSelectHandle * Next = NULL;
};
//---------------------------------------------------------------------------
// List or Handles for Selectable Function Object
@@ -76,6 +78,7 @@ struct SHandle {
// Description
char * Name = NULL;
EConnectType Type = ctNone;
CSelectableBare * Function = NULL;
// State
int FD = -1;
@@ -88,7 +91,7 @@ struct SHandle {
long CloseTimeout = 1000; // millisecs of no traffic before closing socket
// Callback functions
FHandleCallback StateCallback[ 7 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
FHandleCallback StateCallback[ 8 ] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
// Type specific parameters
char * Path = NULL; // Port (file)name or Exec path
@@ -103,7 +106,8 @@ struct SHandle {
struct addrinfo * AddressInfo = NULL; // Current selected IP Address
bool AddressFailed = false; // Indicate failure to connect to address
short Queue = 2; // Max waiting connections
long ResolveDelay = 0; // Delay before resolving hostname via DNS
TResolveReq * ResolveReq = NULL; // DNS resolve request
// Serial Port config
bool SerialConfig = false;
@@ -132,6 +136,16 @@ struct SHandle {
THandle * Parent = NULL;
THandle * Next = NULL;
};
//---------------------------------------------------------------------------
struct SResolveReq {
THandle * Handle = NULL;
gaicb * Request = NULL;
};
//---------------------------------------------------------------------------
// Resolving
void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context );
//---------------------------------------------------------------------------
@@ -192,8 +206,9 @@ protected:
CSelect * Selector = NULL;
// Managing File Handles
bool RemoveHandle( THandle * Handle );
bool DestroyHandle( THandle * Handle );
virtual bool RemoveHandle( THandle * Handle );
virtual bool DestroyHandle( THandle * Handle );
virtual bool HandleState( THandle * Handle, EConnectState State );
// Get Parameters
inline int GetFD( const char * HandleName ) {
@@ -201,15 +216,6 @@ protected:
return ((Handle)? Handle->FD : -1);
};
// General fucntions
inline bool ChangeState( THandle * Handle, EConnectState State ) {
if (!Handle || (Handle->State == State)) return false;
if (Handle->StateCallback[ (int)State ])
(Handle->StateCallback[ (int)State ])( this, Handle, State );
Handle->State = State;
return true;
}
// Mutual Operations
int ReadFromFD( int FD, char * Data, int MaxLen );
int WriteToFD( int FD, const char * Data, int Len, bool Force );
@@ -217,9 +223,6 @@ protected:
// Buffer operations
virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
// Convert string to lower case
inline char * strlcase( char * Str ) {
for (char * Ch = Str; *Ch; Ch++ )
@@ -233,19 +236,17 @@ public:
virtual ~CSelectableBare();
// Configuration
virtual bool Init( CDataMember * FunctionConfig ) = 0;
virtual bool Init( CDataMember * FunctionConfig ) = 0;
// Finding Handles
inline THandle * GetHandle( const char * HandleName )
{
inline THandle * GetHandle( const char * HandleName ) {
if (!HandleName) return NULL;
THandle * Handle = FirstHandle;
while ( Handle && strcmp( HandleName, Handle->Name ))
Handle = Handle->Next;
return Handle;
}
inline THandle * GetHandle( int FD )
{
inline THandle * GetHandle( int FD ) {
if (FD < 0) return NULL;
THandle * Handle = FirstHandle;
while ( Handle && (FD != Handle->FD))
@@ -254,7 +255,7 @@ public:
}
// General port parameters
THandle * CreateHandle( const char * HandleName, bool CreateChannel );
virtual THandle * CreateHandle( const char * HandleName, bool CreateChannel );
virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef );
bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback );
@@ -262,17 +263,14 @@ public:
bool SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen );
bool SetOutBuffer( THandle * Handle, int OutBufSize );
// Specific port parameters
bool ClearHandle( THandle * Handle );
// FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false ) = 0;
virtual int Open( THandle * Handle ) = 0;
virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle );
// FD operations
inline virtual int Open( const char * HandleName, bool DelayResolve = false ) { return (Open( GetHandle( HandleName ), DelayResolve)); };
inline virtual int Open( const char * HandleName ) { return (Open( GetHandle( HandleName ))); };
inline virtual bool Close( const char * HandleName, bool QuickReopen ) { return (Close( GetHandle( HandleName ), QuickReopen )); };
inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); };
@@ -294,8 +292,8 @@ public:
};
// Function Interface
virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 );
int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process();
};
@@ -304,6 +302,8 @@ public:
class CSelectableCore : public CSelectableBare
{
protected:
struct sigaction ResolveAct;
// Port Operations
THandle * OpenSerialPort( THandle * Handle );
bool WriteSerialConfig( THandle * Handle );
@@ -318,18 +318,27 @@ protected:
THandle * OpenUNIXremoteSocket( THandle * Handle );
// Socket Operations
bool ResolveAddress( THandle * Handle, bool DelayResolve );
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve );
bool ResolveAddress( THandle * Handle );
bool HandleResolve( THandle * Handle );
bool DestroyResolveReq( THandle * Handle, bool DestroyResult );
// Managing File Handles
virtual bool DestroyHandle( THandle * Handle );
THandle * OpenUDPserverSocket( THandle * Handle );
THandle * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve );
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve );
THandle * OpenUDPclientSocket( THandle * Handle );
THandle * OpenTCPserverSocket( THandle * Handle );
THandle * OpenTCPremoteSocket( THandle * Handle );
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve );
THandle * OpenTCPclientSocket( THandle * Handle );
// Mutual Operations
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
public:
// Life Cycle
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
@@ -339,22 +348,25 @@ public:
virtual bool Init( CDataMember * FunctionConfig );
// Specific port parameters
bool ClearHandle( THandle * Handle );
bool SetSerialHandle( THandle * Handle, const char * FileName );
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue );
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue, long ResolveDelay );
bool SetSocketHandle( THandle * Handle, EConnectType Type, const char * HostName, const char * PortName, short Queue );
// FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false );
virtual int Open( THandle * Handle );
virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle );
// Function Interface
int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process();
virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context );
};
//---------------------------------------------------------------------------

View File

@@ -41,21 +41,21 @@ void ConfigureSignalHandlers()
sigemptyset( &TermAct.sa_mask );
TermAct.sa_flags = SA_RESTART;
sigaction( SIGHUP, &TermAct, 0 );
sigaction( SIGINT, &TermAct, 0 );
sigaction( SIGQUIT, &TermAct, 0 );
sigaction( SIGTERM, &TermAct, 0 );
sigaction( SIGTSTP, &TermAct, 0 );
sigaction( SIGHUP, &TermAct, NULL );
sigaction( SIGINT, &TermAct, NULL );
sigaction( SIGQUIT, &TermAct, NULL );
sigaction( SIGTERM, &TermAct, NULL );
sigaction( SIGTSTP, &TermAct, NULL );
// Signals for immediate termination
AbortAct.sa_handler = SignalAbort;
sigemptyset( &AbortAct.sa_mask );
AbortAct.sa_flags = 0;
sigaction( SIGABRT, &AbortAct, 0 );
sigaction( SIGFPE, &AbortAct, 0 );
sigaction( SIGILL, &AbortAct, 0 );
sigaction( SIGSEGV, &AbortAct, 0 );
sigaction( SIGABRT, &AbortAct, NULL );
sigaction( SIGFPE, &AbortAct, NULL );
sigaction( SIGILL, &AbortAct, NULL );
sigaction( SIGSEGV, &AbortAct, NULL );
}
//---------------------------------------------------------------------------

View File

@@ -12,6 +12,7 @@
#include <sys/time.h>
#include <time.h>
#include <limits.h>
#include <stdio.h>
// redA Libraries
/* none */
@@ -23,19 +24,22 @@ inline void SetInterval( timeval * Time, long MilliSeconds ) {
Time->tv_sec = MilliSeconds / 1000;
Time->tv_usec = (MilliSeconds % 1000) * 1000;
};
//---------------------------------------------------------------------------
// Mark start time
inline void SetStartTime( timeval *StartTime ) {
gettimeofday( StartTime, NULL );
};
//---------------------------------------------------------------------------
// Clear timer
inline void ClearStartTime( timeval * StartTime ) {
StartTime->tv_sec = 0;
StartTime->tv_usec = 0;
};
//---------------------------------------------------------------------------
// Time passed since start time
// Milli-seconds passed since start time
inline long TimePassed( timeval StartTime ) {
timeval CurrTime;
long Duration;
@@ -47,17 +51,54 @@ inline long TimePassed( timeval StartTime ) {
Duration = LONG_MAX;
return Duration;
};
//---------------------------------------------------------------------------
inline long SecondsPassed( timeval StartTime ) {
timeval CurrTime;
long Duration;
gettimeofday( &CurrTime, NULL );
Duration = CurrTime.tv_sec - StartTime.tv_sec;
return Duration;
};
//---------------------------------------------------------------------------
// Time remaining from Start time to given time out
inline long TimeLeft( timeval StartTime, long MilliSeconds ) {
return (MilliSeconds - TimePassed(StartTime));
};
//---------------------------------------------------------------------------
// Has give time expired after start time
inline bool Timeout( timeval StartTime, long MilliSeconds ) {
return ((TimePassed(StartTime) > MilliSeconds)? true : false);
};
//---------------------------------------------------------------------------
// Get Upcount in seconds from start time (with string output)
inline long GetUpCounter( timeval StartTime, char * TextStr ) {
long Duration;
int Days, Hours, Minutes, Seconds;
// Get duration
Duration = SecondsPassed( StartTime );
// Create string
if (TextStr) {
// Get Parts
Minutes = Duration / 60;
Hours = Minutes / 60;
Days = Hours / 24;
// Get modulus
Seconds = Duration % 60;
Minutes = Minutes % 60;
Hours = Hours % 24;
sprintf( TextStr, "%dd %02d:%02d:%02d", Days, Hours, Minutes, Seconds );
}
return Duration;
}
//---------------------------------------------------------------------------
#endif /* REDACORE_TIMINGCORE_H_ */

View File

@@ -40,7 +40,10 @@ char * BytesToSafeStr( const char * Bytes, const int Len, const bool NoCrLf, con
// Remove special char
for (int i=0; i<Len; i++) {
if (((Bytes[i] < 32) || (Bytes[i] > 126)) ||
if ((Bytes[i] == '\r') || (Bytes[i] == '\n')) {
*BufPos = (NoCrLf)? SpecChar : Bytes[i];
}
else if (((Bytes[i] < 32) || (Bytes[i] > 126)) ||
(NoCrLf && ((Bytes[i] == '\r') || (Bytes[i] == '\n')))) {
*BufPos = SpecChar;
}
@@ -75,7 +78,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator,
// Print Hex values of individual bytes
for (int i=0; i<Len; i++) {
sprintf( BufPos, "%s%02X", ((First)? "" : Separator), (unsigned char)Bytes[i] );
sprintf( BufPos, "%s%02X", ((First || !Separator)? "" : Separator), (unsigned char)Bytes[i] );
BufPos += (First)? 2 : 2+SepLen;
First = false;
}
@@ -105,7 +108,7 @@ char * BytesToBinStr( const char * Bytes, const int Len, const char * Separator,
// Print each byte as 8-bit binary
for (int i=0; i<Len; i++) {
sprintf( BufPos, "%s%c%c%c%c%c%c%c%c", ((First)? "" : Separator),
sprintf( BufPos, "%s%c%c%c%c%c%c%c%c", ((First || !Separator)? "" : Separator),
(Bytes[i] & 0x80)?'1':'0', (Bytes[i] & 0x40)?'1':'0', (Bytes[i] & 0x20)?'1':'0', (Bytes[i] & 0x10)?'1':'0',
(Bytes[i] & 0x08)?'1':'0', (Bytes[i] & 0x04)?'1':'0', (Bytes[i] & 0x02)?'1':'0', (Bytes[i] & 0x01)?'1':'0' );
BufPos += (First)? 8 : 8+SepLen;

View File

@@ -63,7 +63,7 @@ bool CWatchdogCore::Init( CDataMember * FunctionConfig )
return false;
// Set specific parameters
SetInterval( FunctionConfig->GetChInt( "Parameters/PingInterval", 500, true ));
SetInterval( Config->GetChInt( "PingInterval", 500, true ));
// Create handle and set reference, if not done
if (!(Ping = GetHandle( "Ping" )))