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

@@ -420,9 +420,9 @@ bool CApplication::Run( bool TerminateOnError )
{ {
ProcessTerminate = !FunctionItem->Function->Process(); ProcessTerminate = !FunctionItem->Function->Process();
if (TerminateOnError) { if (TerminateOnError) {
if (ProcessTerminate) if (ProcessTerminate) // Raise terminate flag for other processes
Terminate = true; Terminate = true;
if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) if (FunctionItem->Function->WaitToTerminate && !ProcessTerminate) // If needed, allow process to terminate cleanly
CleanTerminate = false; CleanTerminate = false;
} }
} }

View File

@@ -127,10 +127,8 @@ CDataMember * CDataMember::CreateChild( const char * Name, const int Len )
bool CDataMember::Clear() bool CDataMember::Clear()
{ {
// Clear value // Clear value
if (Value) { if (Value)
free( Value ); free( Value );
Value = NULL;
}
// Clear children // Clear children
while (FirstChild) { while (FirstChild) {
@@ -139,6 +137,8 @@ bool CDataMember::Clear()
// Reset value // Reset value
Type = jtNull; Type = jtNull;
Value = NULL;
Len = 0;
return true; 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 ) bool SetTime( unsigned char Hours, unsigned char Minutes, unsigned char Seconds )
{ {
struct tm NewTime; struct tm NewTime;
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
// Get current date and time // Get current Epoch (UTC)
gettimeofday( &tv, &tz); gettimeofday( &tv, &tz);
// Change to new time // Convert to local time
localtime_r( &tv.tv_sec, &NewTime ); localtime_r( &tv.tv_sec, &NewTime );
// Set new time (keep date as is)
NewTime.tm_hour = Hours; NewTime.tm_hour = Hours;
NewTime.tm_min = Minutes; NewTime.tm_min = Minutes;
NewTime.tm_sec = Seconds; NewTime.tm_sec = Seconds;
// Convert back // Convert back from local time to epoch time
tv.tv_sec = mktime( &NewTime ); tv.tv_sec = mktime( &NewTime );
tv.tv_usec = 0; 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 ) bool SetDate( unsigned char Day, unsigned char Month, unsigned Year )
{ {
struct tm NewDate; struct tm NewDate;
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
// Get current date and time // Get current Epoch (UTC)
gettimeofday( &tv, &tz ); gettimeofday( &tv, &tz );
// Change to new time // Convert to local time
localtime_r( &tv.tv_sec, &NewDate ); localtime_r( &tv.tv_sec, &NewDate );
// Set new date (keep time as is)
NewDate.tm_year = Year - 1900; NewDate.tm_year = Year - 1900;
NewDate.tm_mon = Month - 1; NewDate.tm_mon = Month - 1;
NewDate.tm_mday = Day; NewDate.tm_mday = Day;
// Convert back // Convert back from local time to epoch time
tv.tv_sec = mktime( &NewDate ); tv.tv_sec = mktime( &NewDate );
tv.tv_usec = 0; 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 ) bool GetDate( unsigned char &Day, unsigned char &Month, unsigned &Year )
{ {
struct tm CurrentDate; struct tm CurrentDate;
time_t UTC; time_t UTC;
// Get current date and time // Get current UTC date and time
time( &UTC ); time( &UTC );
// Convert to local time
localtime_r( &UTC, &CurrentDate ); localtime_r( &UTC, &CurrentDate );
// Extract date // Extract date only
Day = CurrentDate.tm_mday; Day = CurrentDate.tm_mday;
Month = CurrentDate.tm_mon + 1; Month = CurrentDate.tm_mon + 1;
Year = CurrentDate.tm_year + 1900; 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 ) char const * GetDateStr( const char * DateSeparator )
{ {
unsigned char Day; unsigned char Day;
@@ -172,12 +230,15 @@ char const * GetDateTimeStr( const char * DateSeparator, const char * TimeSepar
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Get current time from real-time clock // 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; struct tm CurrentTime;
// Get current date and time // Get current date and time
if (LocalTime)
localtime_r( &EpochTime, &CurrentTime ); localtime_r( &EpochTime, &CurrentTime );
else
gmtime_r( &EpochTime, &CurrentTime );
// Extract time // Extract time
Hours = CurrentTime.tm_hour; 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; struct tm CurrentDate;
// Get current date and time // Get current date and time
if (LocalTime)
localtime_r( &EpochTime, &CurrentDate ); localtime_r( &EpochTime, &CurrentDate );
else
gmtime_r( &EpochTime, &CurrentDate );
// Extract date // Extract date
Day = CurrentDate.tm_mday; 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 bool ReadDateTime( const time_t EpochTime, bool LocalTime, unsigned char &Day, unsigned char &Month, unsigned &Year,
char const * BuildDateStr( const time_t EpochTime, const char * DateSeparator ) unsigned char &Hours, unsigned char &Minutes, unsigned char &Seconds )
{ {
unsigned char Day; struct tm CurrentTime;
unsigned char Month;
unsigned int Year;
// Get Date // Get current date and time
ReadDate( EpochTime, Day, Month, Year ); 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 // Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d", sprintf( ReturnStr, "%04d%s%02d%s%02d",
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day ); 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 // Build String
sprintf( ReturnStr, "%02d%s%02d%s%02d", sprintf( ReturnStr, "%02d%s%02d%s%02d",
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds ); 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 Day;
unsigned char Month; unsigned char Month;
@@ -250,13 +467,8 @@ char const * BuildDateTimeStr( const time_t EpochTime, const char * DateSeparato
unsigned char Seconds; unsigned char Seconds;
// Get Date & Time // Get Date & Time
ReadDate( EpochTime, Day, Month, Year ); ReadDateTime( EpochTime, LocalTime, Day, Month, Year, Hours, Minutes, Seconds );
ReadTime( EpochTime, Hours, Minutes, Seconds );
// Build String // Build String
sprintf( ReturnStr, "%04d%s%02d%s%02d %02d%s%02d%s%02d", return BuildDateTimeStr( Day, Month, Year, Hours, Minutes, Seconds, DateSeparator, TimeSeparator );
Year, ((DateSeparator)? DateSeparator : ""), Month, ((DateSeparator)? DateSeparator : ""), Day,
Hours, ((TimeSeparator)? TimeSeparator : ""), Minutes, ((TimeSeparator)? TimeSeparator : ""), Seconds );
return (ReturnStr);
} }

View File

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

View File

@@ -18,14 +18,16 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Enumerated types // Enumerated types
typedef enum { dtNone = 0, dtUnsigned16 = 1, dtSigned16 = 2, dtUnsigned32_HL = 3, dtUnsigned32_LH = 4, typedef enum { dtNone = 0, dtBool = 1, dtUnsigned16 = 2, dtSigned16 = 3, dtUnsigned32_HL = 4, dtUnsigned32_LH = 5,
dtSigned32_HL = 5, dtSigned32_LH = 6, dtFloat32_L = 7, dtFloat32_B = 8, dtString = 9 } EDeviceDataType; dtSigned32_HL = 6, dtSigned32_LH = 7, dtFloat32_L = 8, dtFloat32_B = 9, dtString = 10 } EDeviceDataType;
// Constants
const char DataTypeCount = 10; 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" }; "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 // Structure prototypes
@@ -124,7 +126,7 @@ protected:
CDataMember * ConfigTypes = NULL; CDataMember * ConfigTypes = NULL;
CDataMember * ValueTree = NULL; CDataMember * ValueTree = NULL;
CJSONparse * JSONparse = NULL; CJSONparse * JSONparse = NULL;
bool DeviceInit = false; bool DeviceInit = false; // Initialise device on start
// Devices & Type // Devices & Type
TDevice * FirstDeviceType = NULL; TDevice * FirstDeviceType = NULL;
@@ -137,19 +139,26 @@ protected:
TChannel * EventChannel = NULL; TChannel * EventChannel = NULL;
// Poll // Poll
int PollCycle; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown int PollCycle = 0; // Device Polling state, e.g. Init, Connect, Run, Disonnect, Shutdown
int PollStep; // Position in polling sequence int PollStep = 0; // Position in polling sequence
timeval PollWait; // Time at which last poll was done timeval PollWait = {0,0}; // Time at which last poll was done
long PollInterval; // Minimum delay between polls long PollInterval = 250; // Minimum delay between polls
// Reply // Reply
bool WaitingForReply; // Command sent, waiting for reply bool WaitingForReply = false; // Command sent, waiting for reply
bool InvalidReply; // Invalid reply received bool InvalidReply = false; // Invalid reply received
long ReplyTimeout; // Max waiting time for reply long DefReplyTimeout = 500; // Default Max waiting time for reply
long ReplyTimeout = 500; // Max waiting time for reply
// Retry // Retry
int PollRetry; // No of polling retries that has timed out int PollRetry = 0; // No of polling retries that has timed out
int MaxRetries; // Max allowed retries 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 // Manage Devices
bool DestroyDevice( TDevice ** Device ); bool DestroyDevice( TDevice ** Device );
@@ -231,11 +240,7 @@ protected:
Param = &((*Param)->Next); Param = &((*Param)->Next);
return Param; 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 ) { inline TDeviceParam * GetNextReadParam( TDevice * Device, TDeviceParam * LastParam = NULL ) {
if (!Device) return NULL; if (!Device) return NULL;
TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam; TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam;
@@ -275,6 +280,12 @@ protected:
return Group; 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 // Find Param Groups Items
inline TDeviceParamItem * GetParamItem( TDeviceParamGroup * Group, const char * ParamName ) { inline TDeviceParamItem * GetParamItem( TDeviceParamGroup * Group, const char * ParamName ) {
TDeviceParamItem ** Item = GetParamItemPtr( Group, ParamName ); TDeviceParamItem ** Item = GetParamItemPtr( Group, ParamName );
@@ -295,6 +306,12 @@ protected:
if (!strcasecmp( TypeName, DataTypeName[Type])) break; if (!strcasecmp( TypeName, DataTypeName[Type])) break;
return (Type == DataTypeCount)? dtNone : (EDeviceDataType)Type; 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 ); 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 ); virtual bool DeviceOnline( TDevice * Device, bool Online );
// Handle Reply Timing // Handle Reply Timing
virtual void SetWaitForReply(); virtual void SetWaitForReply( int CustomTimeout = -1 );
virtual void ValidReplyReceived(); virtual void ValidReplyReceived();
virtual bool CheckReplyTimeout(); virtual bool CheckReplyTimeout();
@@ -386,7 +403,7 @@ public:
// Handle Interface Commands // Handle Interface Commands
bool GetCmdParam( const char * Start, char * Param, char ** NextParam ); 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 // Command Text Interfaces
bool SetValue( TDeviceParam * Param, const char * Value, const int Len, bool Force ); 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 // Create Channel if necessary
if (CreateChannel) { if (CreateChannel) {
AddChannel( Name ); AddChannel( Name, CH_ready );
} }
// Set Parameters // Set Parameters
@@ -260,7 +260,7 @@ int CFileCore::WriteToFD( int FD, const char * Data, int Len )
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Manual Data Input/Output // 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; TFileHandle * FileHandle = NULL;
int BytesWritten = 0; int BytesWritten = 0;

View File

@@ -73,7 +73,7 @@ public:
virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout ); virtual bool SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout );
// Data Input // 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 // Processing data
virtual bool Process(); 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 ) CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( pType )
{ {
// Set name // Set name
if (pName) { if (pName)
Name = strdup( pName ); Name = strdup( pName );
}
// Logging // Logging
Log = Application->Log; Log = Application->Log;
@@ -44,35 +43,19 @@ CFunctionCore::CFunctionCore( const char * pName, const char * pType ) : Type( p
CFunctionCore::~CFunctionCore() CFunctionCore::~CFunctionCore()
{ {
TChannel * NextChannel = NULL; TChannel * NextChannel = NULL;
TChannelLink * NextLinkedChannel = NULL;
// Destroy Channels // Destroy Channels
while (FirstChannel) while (FirstChannel)
{ {
// Destroy Linked Channels
while (FirstChannel->FirstLink)
UnlinkChannel( FirstChannel->Name, FirstChannel->FirstLink->Function->Name, FirstChannel->FirstLink->Channel->Name );
// Destroy Parameters // Destroy Parameters
if (FirstChannel->Name) { if (FirstChannel->Name)
free( FirstChannel->Name ); free( FirstChannel->Name );
} if (FirstChannel->Ref)
free( FirstChannel->Ref );
// 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;
}
// Destroy Channel // Destroy Channel
NextChannel = FirstChannel->Next; NextChannel = FirstChannel->Next;
@@ -101,6 +84,9 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
if (!FunctionConfig ) if (!FunctionConfig )
return false; return false;
// Set Type
FunctionConfig->SetChStr( "Type", Type );
// Configure Logging/Debugging // Configure Logging/Debugging
LogConfig = FunctionConfig->GetChild( "Log", true ); LogConfig = FunctionConfig->GetChild( "Log", true );
pLogLevel = Log->ReadLogLevel( LogConfig ); pLogLevel = Log->ReadLogLevel( LogConfig );
@@ -109,13 +95,8 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
// Load Channels // Load Channels
ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true ); ChannelConfig = FunctionConfig->GetChFirstChild( "Channels", true );
while (ChannelConfig) while (ChannelConfig) {
{ AddChannel( ChannelConfig->GetName(), CH_off );
if (ChannelConfig->GetName()) {
AddChannel( ChannelConfig->GetName(),
ChannelConfig->GetChBool( "InputEnabled", true, true ),
ChannelConfig->GetChBool( "OutputEnabled", false, true ));
}
ChannelConfig = ChannelConfig->GetNextPeer(); ChannelConfig = ChannelConfig->GetNextPeer();
} }
@@ -124,7 +105,6 @@ bool CFunctionCore::Init( CDataMember * FunctionConfig )
ConfigName = (char*)FunctionConfig->GetChStr( "Config" ); ConfigName = (char*)FunctionConfig->GetChStr( "Config" );
Config = Application->Config->GetChild( ConfigName, true ); Config = Application->Config->GetChild( ConfigName, true );
} }
if (Config->isNull()) Config->SetObject();
return true; return true;
} }
@@ -150,10 +130,11 @@ bool CFunctionCore::InitChannelLinks( CDataMember * LinkConfig )
while (FunctionMember) while (FunctionMember)
{ {
// Get Parameters // Get Parameters
LinkOutputChannel( Channel->Name, LinkChannel( Channel->Name,
FunctionMember->GetChStr( "Function" ), FunctionMember->GetChStr( "Function", NULL, true ),
FunctionMember->GetChStr( "Channel" ), FunctionMember->GetChStr( "Channel", NULL, true ),
FunctionMember->GetChBool( "Bidirectional" ) ); FunctionMember->GetChBool( "Input", false, true ),
FunctionMember->GetChBool( "Output", false, true ) );
FunctionMember = FunctionMember->GetNextPeer(); 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; TChannel ** Channel = NULL;
@@ -203,166 +184,263 @@ TChannel * CFunctionCore::AddChannel( const char * ChannelName, const bool pInpu
// Set Name // Set Name
(*Channel)->Name = strdup( ChannelName ); (*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 // Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created", if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Channel '%s' - Created, Ref:'%s', In:%s, Out:%s",
ProcessName, Name, ChannelName ); ProcessName, Name, ChannelName, (*Channel)->Ref,
ChannelStateName[(*Channel)->InState], ChannelStateName[(*Channel)->OutState]);
} }
// Set parameters
(*Channel)->InputEnabled = pInputEnable;
(*Channel)->OutputEnabled = pOutputEnable;
return *Channel; return *Channel;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Automated Data Input/Output bool CFunctionCore::SetChannelInState( TChannel * Channel, const EChannelState State )
bool CFunctionCore::LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional )
{ {
CFunctionCore * OutFunction = NULL; EChannelState OldState = Channel->InState;
TChannel * Channel = NULL; TChannelLink * LinkChannel;
TChannelLink ** LinkedChannel = NULL;
// Get Channel // Validate
if (!(OutFunction = Application->GetFunction( OutFunctionName )) || !(Channel = GetChannel( ChannelName ))) { if (!Channel)
return false; return false;
}
// Check if linked Channel exists // Update state
LinkedChannel = &(Channel->FirstInput); Channel->InState = State;
while (*LinkedChannel && (((*LinkedChannel)->Function != OutFunction) || strcmp( (*LinkedChannel)->Name, OutChannelName ) )) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Channel '%s' - In:%s",
LinkedChannel = &((*LinkedChannel)->Next); ProcessName, Name, Channel->Ref, ChannelStateName[State] );
}
// Create if not found // Update linked channels
if (!*LinkedChannel) LinkChannel = Channel->FirstLink;
{ while (LinkChannel) {
// Create if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Update Link Channel '%s'-->'%s' - In:%s",
*LinkedChannel = new TChannelLink; ProcessName, Name, Channel->Ref, LinkChannel->Channel->Ref, ChannelStateName[State] );
// Set Parameters // Trigger Linked Channel Events
(*LinkedChannel)->Function = OutFunction; LinkChannel->Function->UpdateChannelOutState( LinkChannel->Channel );
(*LinkedChannel)->Name = strdup( OutChannelName ); LinkChannel->Function->ChannelStateEvent( LinkChannel->Channel, Channel->Ref, OldState, State );
// Log Event LinkChannel = LinkChannel->Next;
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 );
} }
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CFunctionCore::LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ) bool CFunctionCore::UpdateChannelOutState( TChannel * Channel )
{ {
TChannel * OutChannel = NULL; TChannelLink * LinkChannel;
CFunctionCore * InFunction = NULL; EChannelState OutState;
TChannel * InChannel = NULL;
// 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; TChannelLink ** LinkedChannel = NULL;
// Check if Channels & Function exist // Check if Channels & Function exist
if (!(OutChannel = GetChannel( ChannelName )) || if (!(Channel = GetChannel( ChannelName )) ||
!(InFunction = Application->GetFunction( InFunctionName )) || !(LinkFunction = Application->GetFunction( LinkFunctionName )) ||
!(InChannel = InFunction->GetChannel( InChannelName )) ) { !(LinkChannel = LinkFunction->GetChannel( LinkChannelName )) ) {
return false; return false;
} }
// Check if linked Channel exists // Check if linked Channel exists
LinkedChannel = &(OutChannel->FirstOutput); LinkedChannel = &(Channel->FirstLink);
while (*LinkedChannel && (((*LinkedChannel)->Function != InFunction) || strcmp( (*LinkedChannel)->Name, InChannelName ) )) { while (*LinkedChannel && ((*LinkedChannel)->Channel != LinkChannel))
LinkedChannel = &((*LinkedChannel)->Next); LinkedChannel = &((*LinkedChannel)->Next);
}
// Create if not found
if (!*LinkedChannel) if (!*LinkedChannel)
{
// Create
*LinkedChannel = new TChannelLink; *LinkedChannel = new TChannelLink;
// Set Parameters // Set Parameters
(*LinkedChannel)->Function = InFunction; (*LinkedChannel)->Function = LinkFunction;
(*LinkedChannel)->Name = strdup( InChannelName ); (*LinkedChannel)->Channel = LinkChannel;
(*LinkedChannel)->Input = Input;
(*LinkedChannel)->Output = Output;
// Log Event // Log Event
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Output Linked - '%s'/'%s' --> '%s'/'%s'", if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Forward Channel Linked - '%s'-->'%s' - In:%s, Out:%s",
ProcessName, Name, Name, ChannelName, InFunction->GetName(), InChannelName ); ProcessName, Name, Channel->Ref, (*LinkedChannel)->Channel->Ref, ((Input)? "Yes" : "No"), ((Output)? "Yes" : "No") );
}
// Link return direction as well // Find Linked channel on remote function
if (Bidirectional) { LinkedChannel = &(LinkChannel->FirstLink);
return InFunction->LinkOutputChannel( InChannelName, Name, ChannelName, false ); 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; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Manual Data Input/Output bool CFunctionCore::UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName )
int CFunctionCore::Input( const char * ChannelName, const char * Data, int Len ) {
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; TChannel * Channel = NULL;
// Validate // Validate
if (!ChannelName || !Data) { if (!ChannelName || !*ChannelName || !Data) {
return 0; return 0;
} }
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found // Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
else if (!Channel->InputEnabled) { else if (!Channel->InState) {
// Channel disabled if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel %s",
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName, ChannelStateName[Channel->InState] );
ProcessName, Name, ChannelName );
return 0; return 0;
} }
else {
// Return processed bytes // Return processed bytes
if (Len == -1) { if (Len == -1) {
Len = strlen( Data ); Len = strlen( Data );
} }
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:", if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return Len; 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; TChannel * Channel = NULL;
// Validate // Validate
if (!ChannelName) { if (!ChannelName || !*ChannelName) {
return 0; return 0;
} }
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Output rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Output rejected, Output Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ChannelName, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
return 0; return 0;
} }
else { else {
// Return processed bytes // 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 TempLen = 0;
int OutLen = 0; int OutLen = 0;
@@ -371,123 +449,23 @@ int CFunctionCore::Output( const TChannel * Channel, const char * Data, int Len,
return 0; 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 // Log event
if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s' - OUT:", if (Log) Log->Output( LogLevel, dlHigh, ((!OutputFormat)? LogOutput : OutputFormat), Data, Len, "%s/%s: Channel '%s'->'%s' - OUT:",
ProcessName, Name, Channel->Name ); ProcessName, Name, Channel->Name, ((TargetRef && *TargetRef)? TargetRef : "(All)") );
// Pass output to all linked inputs // Pass output to all linked inputs
if (Len == -1) { if (Len == -1)
Len = strlen( Data ); Len = strlen( Data );
} LinkChannel = Channel->FirstLink;
OutChannel = Channel->FirstOutput; while (LinkChannel) {
while (OutChannel) { if (!TargetRef || !*TargetRef || !strcasecmp( TargetRef, LinkChannel->Channel->Ref )) {
TempLen = OutChannel->Function->Input( OutChannel->Name, Data, Len ); TempLen = LinkChannel->Function->Input( LinkChannel->Channel->Name, ((SourceRef)? Channel->Ref : NULL), Data, Len );
OutLen = (TempLen > OutLen)? TempLen : OutLen; OutLen = (TempLen > OutLen)? TempLen : OutLen;
OutChannel = OutChannel->Next; }
LinkChannel = LinkChannel->Next;
} }
// Return processed bytes // Return processed bytes
return OutLen; 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 // Preview
typedef struct SChannel TChannel; typedef struct SChannel TChannel;
typedef struct SChannelLink TChannelLink; typedef struct SChannelLink TChannelLink;
@@ -28,12 +34,12 @@ class CFunctionCore;
struct SChannel struct SChannel
{ {
char * Name = NULL; char * Name = NULL;
char * Ref = NULL;
TChannelLink * FirstInput = NULL; TChannelLink * FirstLink = NULL; // List of channels linked for input/output
TChannelLink * FirstOutput = NULL;
bool InputEnabled = NULL; EChannelState InState = CH_off; // Channel ready to receive input (determined by parent function)
bool OutputEnabled = NULL; EChannelState OutState = CH_off; // Channel ready to send output (determined by InStates of linked channels)
TChannel * Next = NULL; TChannel * Next = NULL;
}; };
@@ -42,7 +48,10 @@ struct SChannel
struct SChannelLink struct SChannelLink
{ {
CFunctionCore * Function = NULL; CFunctionCore * Function = NULL;
char * Name = NULL; TChannel * Channel = NULL;
bool Input = false;
bool Output = false;
SChannelLink * Next = NULL; SChannelLink * Next = NULL;
}; };
@@ -73,10 +82,6 @@ protected:
EDebugLevel LogLevel = dlNone; EDebugLevel LogLevel = dlNone;
int LogOutput = loNone; int LogOutput = loNone;
// Stored Output
char * StoredOutput = NULL;
int StoredOutputLen = 0;
// Manage Channel // Manage Channel
inline TChannel * GetChannel( const char * pName ) { inline TChannel * GetChannel( const char * pName ) {
if (!pName) return NULL; if (!pName) return NULL;
@@ -85,10 +90,16 @@ protected:
Channel = Channel->Next; Channel = Channel->Next;
return Channel; 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 // Data Input/Output
virtual int Output( const TChannel * Channel, const char * Data, int Len, int OutputFormat = loNone ); virtual int Output( const TChannel * Channel, const char * TargetRef, const bool SourceRef, const char * Data, int Len, int OutputFormat = loNone );
virtual bool PullInput( TChannel * Channel );
public: public:
// Life cycle // Life cycle
@@ -108,39 +119,20 @@ public:
inline const char * GetType() { return Type; }; inline const char * GetType() { return Type; };
// Manage Channels // Manage Channels
virtual TChannel * AddChannel( const char * ChannelName, const bool pInputEnable = true, const bool pOutputEnabled = true ); virtual TChannel * AddChannel( const char * ChannelName, const EChannelState State );
inline bool SetChannelOutEnable( const char * ChannelName, const bool pOutputEnable ) {
TChannel * Channel = GetChannel( ChannelName ); virtual bool SetChannelInState( TChannel * Channel, const EChannelState State );
if (!Channel) return false; virtual bool ChannelStateEvent( TChannel * Channel, const char * SourceRef, const EChannelState OldState, const EChannelState NewState ) { return true; };
Channel->OutputEnabled = pOutputEnable; virtual bool UpdateChannelOutState( TChannel * Channel );
return true; virtual EChannelState GetChannelOutState( TChannel * Channel, const char * TargetRef );
}
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 // Pushing Data Output -> Input
virtual int Output( const char * ChannelName, const char * Data, int Len = -1 ); 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 * Data, int Len = -1 ); virtual int Input( const char * ChannelName, const char * SourceRef, 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 );
// Automated Data Input/Output // Automated Data Input/Output
virtual bool LinkInputChannel( const char * ChannelName, const char * OutFunctionName, const char * OutChannelName, bool Bidirectional ); virtual bool LinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName, bool Input, bool Output );
virtual bool LinkOutputChannel( const char * ChannelName, const char * InFunctionName, const char * InChannelName, bool Bidirectional ); virtual bool UnlinkChannel( const char * ChannelName, const char * LinkFunctionName, const char * LinkChannelName );
virtual bool Process() = 0; virtual bool Process() = 0;
friend class CApplication; friend class CApplication;

View File

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

View File

@@ -17,7 +17,7 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Global vars // 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" }; 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 // Quick access
Selector = Application->Selector; Selector = Application->Selector;
// Handles
FirstHandle = NULL;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -97,7 +94,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
if (!*Handle) if (!*Handle)
{ {
// Create File handle at end of list // Create File handle at end of list
*Handle = (THandle*)calloc( 1, sizeof(THandle) ); *Handle = new THandle;
// Set name // Set name
if (HandleName) { if (HandleName) {
@@ -106,6 +103,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
} }
// Set File Descriptor // Set File Descriptor
(*Handle)->Function = this;
(*Handle)->FD = -1; (*Handle)->FD = -1;
// Log event // Log event
@@ -115,7 +113,7 @@ THandle * CSelectableBare::CreateHandle( const char * HandleName, bool CreateCh
// Create Matching Channel // Create Matching Channel
if (CreateChannel) { if (CreateChannel) {
(*Handle)->Channel = AddChannel( HandleName ); (*Handle)->Channel = AddChannel( HandleName, CH_off );
} }
return *Handle; return *Handle;
@@ -162,61 +160,41 @@ bool CSelectableBare::DestroyHandle( THandle * Handle )
free( Handle->Name ); free( Handle->Name );
if (Handle->Path) if (Handle->Path)
free( 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 // Destroy Pointer
free( Handle ); delete Handle;
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool CSelectableBare::ClearHandle( THandle * Handle ) bool CSelectableBare::HandleState( THandle * Handle, EConnectState State )
{ {
EChannelState ChannelState = CH_off;
// Validate // Validate
if (!Handle) { if (!Handle || (Handle->State == State))
return false; return false;
}
// Reset Type related parameters // Execute call back for state
if (Handle->Path) { if (Handle->StateCallback[ (int)State ])
free( Handle->Path ); (Handle->StateCallback[ (int)State ])( this, Handle, State );
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;
}
// Reset Parameters // Change state
Handle->Type = ctNone; Handle->State = State;
// Log event // Update Channel
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - Set as None", if (Handle->Channel) {
ProcessName, Name, Handle->Name ); 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; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -322,9 +300,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs // Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len ); Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else { } else {
Output( Handle->Channel, Data, Len ); Output( Handle->Channel, NULL, true, Data, Len );
} }
// Clear processed bytes from buffer // Clear processed bytes from buffer
@@ -342,9 +320,9 @@ bool CSelectableBare::ProcessInputBuffer( THandle * Handle, bool Force )
// Write buffer to Outputs // Write buffer to Outputs
if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) { if ((Handle->Type == ctTCPremote) || (Handle->Type == ctUNIXremote)) {
Output( Handle->Parent->Channel, Data, Len ); Output( Handle->Parent->Channel, NULL, true, Data, Len );
} else { } else {
Output( Handle->Channel, Data, Len ); Output( Handle->Channel, NULL, true, Data, Len );
} }
// Clear processed bytes from buffer // 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; THandle * NewHandle = NULL;
// Validate // Validate
if (!Handle || (Handle->Type == ctNone)) { if (!Handle || (Handle->Type == ctNone)) {
return -1; return -1;
@@ -394,11 +373,11 @@ int CSelectableBare::Open( THandle * Handle, bool DelayResolve )
Selector->Add( Handle->FD, true, false, Handle, this ); Selector->Add( Handle->FD, true, false, Handle, this );
} }
// Set state
ChangeState( Handle, csOpen );
// Set timer (for re-open or auto-close) // Set timer (for re-open or auto-close)
SetStartTime( &Handle->LastAction ); SetStartTime( &Handle->LastAction );
// Set state
HandleState( Handle, csOpen );
return (NewHandle)? NewHandle->FD : -1; return (NewHandle)? NewHandle->FD : -1;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -414,7 +393,16 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
// Close Handle // Close Handle
Fail = (close( Handle->FD ))? true : false; 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) // Start timer (for re-open)
if (QuickReopen) if (QuickReopen)
@@ -426,15 +414,8 @@ bool CSelectableBare::Close( THandle * Handle, bool QuickReopen )
if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s", if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Handle '%s' - %s",
ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") ); ProcessName, Name, Handle->Name, ((Fail)? "failed" : "closed") );
// Remove from Select List // Set State
if (!Fail && Selector) { HandleState( Handle, ((Fail)? csFailed : csClosed) );
if (Handle->Type != ctUDPremote) {
Selector->Remove( Handle->FD, true, true );
}
}
// Reset FD
Handle->FD = ((Fail)? Handle->FD : -1);
return true; return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@@ -534,7 +515,7 @@ bool CSelectableBare::Write( THandle * Handle )
else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Attempt to re-open port // 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; TChannel * Channel = NULL;
THandle * Handle = NULL; THandle * Handle = NULL;
@@ -694,20 +675,20 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
// Get Channel // Get Channel
if (!(Channel = GetChannel( ChannelName ))) { if (!(Channel = GetChannel( ChannelName ))) {
// Channel not found // Channel not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel not found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
else if (!Channel->InputEnabled) { else if (Channel->InState == CH_off) {
// Channel disabled // Channel disabled
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel input disabled", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, Channel off",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
// Log event // Log event
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:", if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s'->'%s' - IN:",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
// Find Linked handle // Find Linked handle
Handle = FirstHandle; Handle = FirstHandle;
@@ -725,8 +706,8 @@ int CSelectableBare::Input( const char * ChannelName, const char * Data, int Len
if (!HandleCount) { if (!HandleCount) {
// Handle not found // Handle not found
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, No Handles found", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s'->'%s' - Input rejected, No Handles found",
ProcessName, Name, ChannelName ); ProcessName, Name, ((SourceRef && *SourceRef)? SourceRef : "(Any)"), ChannelName );
return 0; return 0;
} }
@@ -752,11 +733,11 @@ int CSelectableBare::OutputHandle( THandle * Handle, const char * Data, int Len
else if (Timeout( Handle->LastAction, Handle->ReopenDelay )) else if (Timeout( Handle->LastAction, Handle->ReopenDelay ))
{ {
// Complete opening process // Complete opening process
Open( Handle, true ); Open( Handle );
// Check if Handle is open // Check if Handle is open
if (Handle->State == csOpenRequest) { if ((Handle->State == csPreparing) || (Handle->State == csPrepared)) {
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Request to resolve (auto-managed) Handle", if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Handle '%s' - Input rejected, Preparing (auto-managed) Handle",
ProcessName, Name, Handle->Name ); ProcessName, Name, Handle->Name );
return 0; return 0;
} }
@@ -833,27 +814,25 @@ bool CSelectableBare::Process()
while (Handle) while (Handle)
{ {
// Auto manage handles // Auto manage handles
if ((Handle->State == csOpenRequest)) if (Handle->State == csPrepared) {
{ // Proceed to open
// Resolve then open socket Open( Handle );
if (Timeout( Handle->LastAction, Handle->ResolveDelay )) {
Open( Handle, false );
} }
} 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 // Try to re-open port after delay
if (Timeout( Handle->LastAction, Handle->ReopenDelay )) { 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 // Check Input buffers
if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) if (Handle->InBuffer && (Handle->InBuffer->Len() > 0)) {
{
// Check duration since last PortIn // Check duration since last PortIn
if (Timeout( Handle->InStart, Handle->InTimeout )) if (Timeout( Handle->InStart, Handle->InTimeout )) {
{
// Process Input // Process Input
ProcessInputBuffer( Handle, true ); ProcessInputBuffer( Handle, true );
@@ -863,95 +842,14 @@ bool CSelectableBare::Process()
} }
// Check for auto close (but not on servers) // 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 // Close port after timeout
if (Timeout( Handle->LastAction, Handle->CloseTimeout )) { if (Timeout( Handle->LastAction, Handle->CloseTimeout )) {
Close( Handle, true ); Close( Handle, true );
} }
} }
Handle = Handle->Next; Handle = Handle->Next;
} }
return true; 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 // Standard C/C++ Libraries
#include <ctype.h> #include <ctype.h>
#include <signal.h>
#include <netdb.h>
// redA Libraries // redA Libraries
#include "FunctionCore.h" #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", 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" }; "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; typedef enum { csNone = 0, csPreparing = 1, csPrepared = 2, csWaitingtoOpen = 3, csOpen = 4, csDataWaiting = 5, csClosed = 6, csFailed = 7 } EConnectState;
const char ConnectStateName[][15] = { "None", "OpenRequest", "WaitingToOpen", "Open", "DataWaiting", "Closed", "Failed" }; 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 // Previews
typedef struct SSelectHandle TSelectHandle; typedef struct SSelectHandle TSelectHandle;
typedef struct SHandle THandle; typedef struct SHandle THandle;
typedef struct SResolveReq TResolveReq;
class CSelect; class CSelect;
class CSelectableBare; class CSelectableBare;
class CSelectableCore; class CSelectableCore;
// Callback function for handle events // 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 // List
TSelectHandle * Next = NULL; TSelectHandle * Next = NULL;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// List or Handles for Selectable Function Object // List or Handles for Selectable Function Object
@@ -76,6 +78,7 @@ struct SHandle {
// Description // Description
char * Name = NULL; char * Name = NULL;
EConnectType Type = ctNone; EConnectType Type = ctNone;
CSelectableBare * Function = NULL;
// State // State
int FD = -1; int FD = -1;
@@ -88,7 +91,7 @@ struct SHandle {
long CloseTimeout = 1000; // millisecs of no traffic before closing socket long CloseTimeout = 1000; // millisecs of no traffic before closing socket
// Callback functions // 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 // Type specific parameters
char * Path = NULL; // Port (file)name or Exec path char * Path = NULL; // Port (file)name or Exec path
@@ -103,7 +106,8 @@ struct SHandle {
struct addrinfo * AddressInfo = NULL; // Current selected IP Address struct addrinfo * AddressInfo = NULL; // Current selected IP Address
bool AddressFailed = false; // Indicate failure to connect to address bool AddressFailed = false; // Indicate failure to connect to address
short Queue = 2; // Max waiting connections short Queue = 2; // Max waiting connections
long ResolveDelay = 0; // Delay before resolving hostname via DNS
TResolveReq * ResolveReq = NULL; // DNS resolve request
// Serial Port config // Serial Port config
bool SerialConfig = false; bool SerialConfig = false;
@@ -132,6 +136,16 @@ struct SHandle {
THandle * Parent = NULL; THandle * Parent = NULL;
THandle * Next = 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; CSelect * Selector = NULL;
// Managing File Handles // Managing File Handles
bool RemoveHandle( THandle * Handle ); virtual bool RemoveHandle( THandle * Handle );
bool DestroyHandle( THandle * Handle ); virtual bool DestroyHandle( THandle * Handle );
virtual bool HandleState( THandle * Handle, EConnectState State );
// Get Parameters // Get Parameters
inline int GetFD( const char * HandleName ) { inline int GetFD( const char * HandleName ) {
@@ -201,15 +216,6 @@ protected:
return ((Handle)? Handle->FD : -1); 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 // Mutual Operations
int ReadFromFD( int FD, char * Data, int MaxLen ); int ReadFromFD( int FD, char * Data, int MaxLen );
int WriteToFD( int FD, const char * Data, int Len, bool Force ); int WriteToFD( int FD, const char * Data, int Len, bool Force );
@@ -217,9 +223,6 @@ protected:
// Buffer operations // Buffer operations
virtual bool ProcessInputBuffer( THandle * Handle, bool Force ); virtual bool ProcessInputBuffer( THandle * Handle, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
// Convert string to lower case // Convert string to lower case
inline char * strlcase( char * Str ) { inline char * strlcase( char * Str ) {
for (char * Ch = Str; *Ch; Ch++ ) for (char * Ch = Str; *Ch; Ch++ )
@@ -236,16 +239,14 @@ public:
virtual bool Init( CDataMember * FunctionConfig ) = 0; virtual bool Init( CDataMember * FunctionConfig ) = 0;
// Finding Handles // Finding Handles
inline THandle * GetHandle( const char * HandleName ) inline THandle * GetHandle( const char * HandleName ) {
{
if (!HandleName) return NULL; if (!HandleName) return NULL;
THandle * Handle = FirstHandle; THandle * Handle = FirstHandle;
while ( Handle && strcmp( HandleName, Handle->Name )) while ( Handle && strcmp( HandleName, Handle->Name ))
Handle = Handle->Next; Handle = Handle->Next;
return Handle; return Handle;
} }
inline THandle * GetHandle( int FD ) inline THandle * GetHandle( int FD ) {
{
if (FD < 0) return NULL; if (FD < 0) return NULL;
THandle * Handle = FirstHandle; THandle * Handle = FirstHandle;
while ( Handle && (FD != Handle->FD)) while ( Handle && (FD != Handle->FD))
@@ -254,7 +255,7 @@ public:
} }
// General port parameters // 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 ); virtual CDataMember * GetHandleAddress( THandle * Handle, const char * HandleRef );
bool SetCallback( THandle * Handle, EConnectState pState, FHandleCallback pCallback ); 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 SetInBuffer( THandle * Handle, int InBufSize, int InTimeout, const char * InMarker, int InMarkerLen );
bool SetOutBuffer( THandle * Handle, int OutBufSize ); bool SetOutBuffer( THandle * Handle, int OutBufSize );
// Specific port parameters
bool ClearHandle( THandle * Handle );
// FD Operations // 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 Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle ); virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle ); virtual bool Write( THandle * Handle );
// FD operations // 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( const char * HandleName, bool QuickReopen ) { return (Close( GetHandle( HandleName ), QuickReopen )); };
inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); }; inline virtual bool Close( int FD, bool QuickReopen ) { return (Close( GetHandle( FD ), QuickReopen )); };
@@ -294,8 +292,8 @@ public:
}; };
// Function Interface // Function Interface
virtual int Input( const char * ChannelName, const char * Buffer, int BufLen = -1 ); virtual int Input( const char * ChannelName, const char * SourceRef, const char * Data, int Len = -1 );
int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process(); virtual bool Process();
}; };
@@ -304,6 +302,8 @@ public:
class CSelectableCore : public CSelectableBare class CSelectableCore : public CSelectableBare
{ {
protected: protected:
struct sigaction ResolveAct;
// Port Operations // Port Operations
THandle * OpenSerialPort( THandle * Handle ); THandle * OpenSerialPort( THandle * Handle );
bool WriteSerialConfig( THandle * Handle ); bool WriteSerialConfig( THandle * Handle );
@@ -318,18 +318,27 @@ protected:
THandle * OpenUNIXremoteSocket( THandle * Handle ); THandle * OpenUNIXremoteSocket( THandle * Handle );
// Socket Operations // Socket Operations
bool ResolveAddress( THandle * Handle, bool DelayResolve ); bool ResolveAddress( THandle * Handle );
THandle * OpenUDPserverSocket( THandle * Handle, bool DelayResolve ); 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 * OpenUDPremoteSocket( THandle * Handle, char * RemoteAddr, char * RemotePort );
THandle * OpenUDPclientSocket( THandle * Handle, bool DelayResolve ); THandle * OpenUDPclientSocket( THandle * Handle );
THandle * OpenTCPserverSocket( THandle * Handle, bool DelayResolve ); THandle * OpenTCPserverSocket( THandle * Handle );
THandle * OpenTCPremoteSocket( THandle * Handle ); THandle * OpenTCPremoteSocket( THandle * Handle );
THandle * OpenTCPclientSocket( THandle * Handle, bool DelayResolve ); THandle * OpenTCPclientSocket( THandle * Handle );
// Mutual Operations // Mutual Operations
int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen ); int ReadFromUDP( THandle * Handle, char * RemoteAddr, char * RemotePort, char * Data, int MaxLen );
int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force ); int WriteToUDP( THandle * Handle, const char * Data, int Len, bool Force );
// Specific operations
bool BuildArgs( const char * ExecPath, int &Count, char * Args[] );
public: public:
// Life Cycle // Life Cycle
CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE ); CSelectableCore( const char * Name, const char * Type = TYPE_SELECTABLE );
@@ -339,22 +348,25 @@ public:
virtual bool Init( CDataMember * FunctionConfig ); virtual bool Init( CDataMember * FunctionConfig );
// Specific port parameters // Specific port parameters
bool ClearHandle( THandle * Handle );
bool SetSerialHandle( THandle * Handle, const char * FileName ); bool SetSerialHandle( THandle * Handle, const char * FileName );
bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait ); bool SetSerialHandleConfig( THandle * Handle, int Baudrate, short DataBits, short Parity, short StopBits, short FlowCtrl, int DataWait );
bool SetLinePrinterHandle( THandle * Handle, const char * FileName ); bool SetLinePrinterHandle( THandle * Handle, const char * FileName );
bool SetForkPipeHandle( THandle * Handle, const char * ExecPath ); bool SetForkPipeHandle( THandle * Handle, const char * ExecPath );
bool SetUnixHandle( THandle * Handle, EConnectType Type, const char * FileName, short Queue ); 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 // FD Operations
virtual int Open( THandle * Handle, bool DelayResolve = false ); virtual int Open( THandle * Handle );
virtual bool Close( THandle * Handle, bool QuickReopen ); virtual bool Close( THandle * Handle, bool QuickReopen );
virtual bool Read( THandle * Handle ); virtual bool Read( THandle * Handle );
virtual bool Write( THandle * Handle ); virtual bool Write( THandle * Handle );
// Function Interface // Function Interface
int OutputHandle( THandle * Handle, const char * Data, int Len ); virtual int OutputHandle( THandle * Handle, const char * Data, int Len );
virtual bool Process();
friend void ResolveHandler( int Signal, siginfo_t * SignalInfo, void * Context );
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

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

View File

@@ -12,6 +12,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <limits.h> #include <limits.h>
#include <stdio.h>
// redA Libraries // redA Libraries
/* none */ /* none */
@@ -23,19 +24,22 @@ inline void SetInterval( timeval * Time, long MilliSeconds ) {
Time->tv_sec = MilliSeconds / 1000; Time->tv_sec = MilliSeconds / 1000;
Time->tv_usec = (MilliSeconds % 1000) * 1000; Time->tv_usec = (MilliSeconds % 1000) * 1000;
}; };
//---------------------------------------------------------------------------
// Mark start time // Mark start time
inline void SetStartTime( timeval *StartTime ) { inline void SetStartTime( timeval *StartTime ) {
gettimeofday( StartTime, NULL ); gettimeofday( StartTime, NULL );
}; };
//---------------------------------------------------------------------------
// Clear timer // Clear timer
inline void ClearStartTime( timeval * StartTime ) { inline void ClearStartTime( timeval * StartTime ) {
StartTime->tv_sec = 0; StartTime->tv_sec = 0;
StartTime->tv_usec = 0; StartTime->tv_usec = 0;
}; };
//---------------------------------------------------------------------------
// Time passed since start time // Milli-seconds passed since start time
inline long TimePassed( timeval StartTime ) { inline long TimePassed( timeval StartTime ) {
timeval CurrTime; timeval CurrTime;
long Duration; long Duration;
@@ -47,17 +51,54 @@ inline long TimePassed( timeval StartTime ) {
Duration = LONG_MAX; Duration = LONG_MAX;
return Duration; 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 // Time remaining from Start time to given time out
inline long TimeLeft( timeval StartTime, long MilliSeconds ) { inline long TimeLeft( timeval StartTime, long MilliSeconds ) {
return (MilliSeconds - TimePassed(StartTime)); return (MilliSeconds - TimePassed(StartTime));
}; };
//---------------------------------------------------------------------------
// Has give time expired after start time // Has give time expired after start time
inline bool Timeout( timeval StartTime, long MilliSeconds ) { inline bool Timeout( timeval StartTime, long MilliSeconds ) {
return ((TimePassed(StartTime) > MilliSeconds)? true : false); 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_ */ #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 // Remove special char
for (int i=0; i<Len; i++) { 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')))) { (NoCrLf && ((Bytes[i] == '\r') || (Bytes[i] == '\n')))) {
*BufPos = SpecChar; *BufPos = SpecChar;
} }
@@ -75,7 +78,7 @@ char * BytesToHexStr( const char * Bytes, const int Len, const char * Separator,
// Print Hex values of individual bytes // Print Hex values of individual bytes
for (int i=0; i<Len; i++) { 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; BufPos += (First)? 2 : 2+SepLen;
First = false; First = false;
} }
@@ -105,7 +108,7 @@ char * BytesToBinStr( const char * Bytes, const int Len, const char * Separator,
// Print each byte as 8-bit binary // Print each byte as 8-bit binary
for (int i=0; i<Len; i++) { 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] & 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' ); (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; BufPos += (First)? 8 : 8+SepLen;

View File

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