1229 lines
38 KiB
C++
1229 lines
38 KiB
C++
/*
|
|
* DeviceCore.cpp
|
|
*
|
|
* Created on: 18 May 2016
|
|
* Author: wentzelc
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Standard C/C++ Libraries
|
|
/* none */
|
|
|
|
// redA Libraries
|
|
#include "ApplicationCore.h"
|
|
#include "DeviceCore.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Global Vars
|
|
extern char * ProcessName;
|
|
extern CApplication * Application;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//CFunctionCore * NewDeviceCore( const char * Name ) {
|
|
// return (CFunctionCore*) new CDeviceCore( Name );
|
|
//}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CDeviceCore::CDeviceCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
|
|
{
|
|
// Clear Parameters
|
|
FirstDevice = NULL;
|
|
ActiveDevice = NULL;
|
|
|
|
// Standard channels
|
|
DeviceChannel = NULL;
|
|
CmdChannel = NULL;
|
|
EventChannel = NULL;
|
|
|
|
// Polling
|
|
PollStep = 0;
|
|
PollInterval = 250;
|
|
SetStartTime( &PollWait );
|
|
|
|
WaitingForReply = false;
|
|
ReplyTimeout = 200;
|
|
|
|
PollRetry = 0;
|
|
MaxRetries = 3;
|
|
|
|
// Data Structures
|
|
Config = NULL;
|
|
DeviceInit = true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CDeviceCore::~CDeviceCore()
|
|
{
|
|
// Destroy Params
|
|
while (FirstDevice)
|
|
DestroyDevice( &FirstDevice );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::Init( CDataMember * FunctionConfig )
|
|
{
|
|
char * ConfigName = NULL;
|
|
CDataMember * PollConfig = NULL;
|
|
int IntVal1;
|
|
int IntVal2;
|
|
|
|
// Call Previous load config
|
|
if (!CFunctionCore::Init( FunctionConfig ))
|
|
return false;
|
|
|
|
// Add Channels
|
|
if (!(CmdChannel = GetChannel( "Command" )))
|
|
CmdChannel = AddChannel( "Command", true, true );
|
|
if (!(DeviceChannel = GetChannel( "Device" )))
|
|
DeviceChannel = AddChannel( "Device", true, true );
|
|
if (!(DeviceChannel = GetChannel( "Event" )))
|
|
DeviceChannel = AddChannel( "Event", true, true );
|
|
|
|
// Get configuration
|
|
if ((Config = FunctionConfig->GetChild( "Config", true )) && Config->isString()) {
|
|
ConfigName = (char*)FunctionConfig->GetChStr( "Config" );
|
|
Config = Application->Config->GetChild( ConfigName, true );
|
|
}
|
|
if (Config->isNull()) Config->SetObject();
|
|
|
|
// Load Polling configuration
|
|
PollConfig = Config->GetChild( "Polling", true );
|
|
if (PollConfig->isNull()) PollConfig->SetObject();
|
|
|
|
IntVal1 = PollConfig->GetChInt( "PollInterval", 500, true );
|
|
SetPollParam( IntVal1 );
|
|
|
|
IntVal1 = PollConfig->GetChInt( "ReplyTimeout", 250, true );
|
|
IntVal2 = PollConfig->GetChInt( "MaxRetries", 3, true );
|
|
SetReplyParam( IntVal1, IntVal2 );
|
|
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Set Polling param - Int:%d, TO:%d, Max:%d, Up:%d",
|
|
ProcessName, Name, PollInterval, ReplyTimeout, MaxRetries );
|
|
|
|
// Update Devices -- may want to do it from derived class intead
|
|
if (DeviceInit) {
|
|
InitDevices( FunctionConfig );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::InitDevices( CDataMember * FunctionConfig )
|
|
{
|
|
CDataMember * DeviceData;
|
|
CDataMember * ParamData;
|
|
CDataMember * InitVal;
|
|
TDevice * Device;
|
|
TDeviceParam * Param;
|
|
|
|
EDeviceDataType DataType;
|
|
|
|
bool Read;
|
|
bool Write;
|
|
char * EventOut;
|
|
int EventInt;
|
|
|
|
// Add Devices
|
|
DeviceData = Config->GetChFirstChild( "Devices", true );
|
|
while (DeviceData)
|
|
{
|
|
// Add device
|
|
Device = AddDevice( DeviceData->GetName() );
|
|
Param = NULL;
|
|
|
|
// Add Parameters
|
|
ParamData = DeviceData->GetChFirstChild( "Parameters", true );
|
|
while (ParamData)
|
|
{
|
|
DataType = GetDataType((char*)ParamData->GetChStr( "Type", "Unsigned16", true ));
|
|
if (!(Param = AddDeviceParam( Device, ParamData->GetName(), DataType, 1 )))
|
|
continue;
|
|
|
|
Read = ParamData->GetChBool( "Read", false, true );
|
|
Write = ParamData->GetChBool( "Write", false, true );
|
|
SetParamAccess( Param, Read, Write );
|
|
|
|
if ((InitVal = ParamData->GetChild( "InitValue", false ))) {
|
|
if (InitVal->isInt() && ((DataType == dtUnsigned16) || (DataType == dtUnsigned32))) {
|
|
UpdateUnsignedValue( Param, InitVal->GetInt(0), Read );
|
|
if (Write)
|
|
SetUnsignedValue( Param, InitVal->GetInt(0), true );
|
|
}
|
|
else if (InitVal->isInt() && ((DataType == dtSigned16) || (DataType == dtSigned32))) {
|
|
UpdateSignedValue( Param, InitVal->GetInt(0), Read );
|
|
if (Write)
|
|
SetSignedValue( Param, InitVal->GetInt(0), true );
|
|
}
|
|
else if (InitVal->isFloat() && (DataType == dtFloat32)) {
|
|
UpdateFloatValue( Param, InitVal->GetFloat(0), Read );
|
|
if (Write)
|
|
SetFloatValue( Param, InitVal->GetFloat(0), true );
|
|
}
|
|
else if (InitVal->isString() && (DataType == dtString)) {
|
|
UpdateStringValue( Param, InitVal->GetStr(""), InitVal->GetLen(), Read );
|
|
if (Write)
|
|
SetStringValue( Param, InitVal->GetStr(""), InitVal->GetLen(), true );
|
|
}
|
|
}
|
|
|
|
EventOut = (char*)ParamData->GetChStr( "EventChannel", NULL, false );
|
|
EventInt = ParamData->GetChInt( "EventInterval", 0, false );
|
|
SetParamEvent( Param, EventOut, EventInt );
|
|
|
|
// Read + Event Out
|
|
ParamData = ParamData->GetNextPeer();
|
|
}
|
|
DeviceData = DeviceData->GetNextPeer();
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetPollParam( int pPollInterval )
|
|
{
|
|
PollInterval = pPollInterval;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries )
|
|
{
|
|
ReplyTimeout = pReplyTimeout;
|
|
MaxRetries = pMaxRetries;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::DeviceOnline( TDevice * Device, bool Online )
|
|
{
|
|
// Validate
|
|
if (!Device)
|
|
return false;
|
|
|
|
// Check if change of state
|
|
if (Device->Online == Online)
|
|
return true;
|
|
|
|
// Log Event
|
|
Device->Online = Online;
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Device '%s' %s",
|
|
ProcessName, Name, Device->Name, ((Online)? "online" : "offline") );
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CDeviceCore::SetWaitForReply()
|
|
{
|
|
// Start timer
|
|
SetStartTime( &PollWait );
|
|
|
|
// Set flag
|
|
WaitingForReply = true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::CheckReplyTimeout( int TimeoutPollStep )
|
|
{
|
|
// Check for Reply timeout
|
|
if (WaitingForReply && Timeout( PollWait, ReplyTimeout ))
|
|
{
|
|
// Increment retries
|
|
PollRetry++;
|
|
|
|
// Handle No Reply / Retry
|
|
if (PollRetry < MaxRetries) {
|
|
// Log Event
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - %s timeout, retry [%d]",
|
|
ProcessName, Name, DeviceChannel->Name, ActiveDevice->Name, PollRetry );
|
|
}
|
|
else {
|
|
// Log Event
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - %s timeout, max [%d]",
|
|
ProcessName, Name, DeviceChannel->Name, ActiveDevice->Name, PollRetry );
|
|
|
|
// Set Device Offline
|
|
DeviceOnline( ActiveDevice, false );
|
|
PollStep = TimeoutPollStep;
|
|
}
|
|
|
|
// Reset flag - retry
|
|
WaitingForReply = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Reset retries
|
|
PollRetry = 0;
|
|
return false;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
TDevice * CDeviceCore::AddDevice( const char * DeviceName, const char * Type )
|
|
{
|
|
TDevice ** Device = &FirstDevice;
|
|
|
|
if (!DeviceName || !*DeviceName) return NULL;
|
|
|
|
while (*Device && strcmp( DeviceName, (*Device)->Name ))
|
|
Device = &((*Device)->Next);
|
|
|
|
// Create if not found
|
|
if (!*Device)
|
|
{
|
|
*Device = (TDevice*)malloc( sizeof(TDevice) );
|
|
memset( *Device, 0x0, sizeof(TDevice) );
|
|
|
|
(*Device)->Name = (char *)malloc( strlen( DeviceName )+1 );
|
|
strcpy( (*Device)->Name, DeviceName );
|
|
|
|
if (Type && *Type) {
|
|
(*Device)->Type = (char *)malloc( strlen( Type )+1 );
|
|
strcpy( (*Device)->Type, Type );
|
|
}
|
|
}
|
|
|
|
// Report creation
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Device added - '%s' (%s)",
|
|
ProcessName, Name, DeviceName, (Type)? Type : "no type" );
|
|
|
|
return *Device;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::DestroyDevice( TDevice ** Device )
|
|
{
|
|
TDevice * NextDevice = NULL;
|
|
|
|
// Validate Device
|
|
if (!Device || !*Device)
|
|
return false;
|
|
|
|
// Save reference to next Device
|
|
NextDevice = (*Device)->Next;
|
|
|
|
// Destroy Device structure
|
|
if ((*Device)->Name)
|
|
free( (*Device)->Name );
|
|
if ((*Device)->Type)
|
|
free( (*Device)->Type );
|
|
|
|
// Destroy paramters
|
|
while ((*Device)->FirstParam) {
|
|
DestroyDeviceParam( &((*Device)->FirstParam) );
|
|
}
|
|
|
|
// Destroy Device
|
|
free( *Device );
|
|
|
|
// Remove from list
|
|
*Device = NextDevice;
|
|
|
|
// Device successfully destroyed
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * ParamName, EDeviceDataType DataType, int ParamLen )
|
|
{
|
|
// Get register or end of list
|
|
TDeviceParam ** Param = &Device->FirstParam;
|
|
while (*Param && strcmp( ParamName, (*Param)->Name ))
|
|
Param = &((*Param)->Next);
|
|
|
|
// Create if not found
|
|
if (!*Param) {
|
|
// Create register
|
|
*Param = (TDeviceParam*)malloc( sizeof(TDeviceParam) );
|
|
memset( *Param, 0x0, sizeof(TDeviceParam) );
|
|
|
|
// Set Name
|
|
(*Param)->Name = (char *)malloc( strlen( ParamName )+1 );
|
|
strcpy( (*Param)->Name, ParamName );
|
|
(*Param)->DataType = DataType;
|
|
|
|
// Init values
|
|
switch (DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
// Create Value pointer
|
|
(*Param)->Value = (u_int16_t*)malloc( sizeof(u_int16_t) );
|
|
*((u_int16_t*)(*Param)->Value) = 0;
|
|
(*Param)->Len = sizeof(u_int16_t);
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetValue = (u_int16_t*)malloc( sizeof(u_int16_t) );
|
|
*((u_int16_t*)(*Param)->SetValue) = 0;
|
|
(*Param)->SetLen = sizeof(u_int16_t);
|
|
break;
|
|
|
|
case dtSigned16 :
|
|
// Create Value pointer
|
|
(*Param)->Value = (int16_t*)malloc( sizeof(int16_t) );
|
|
*((int16_t*)(*Param)->Value) = 0;
|
|
(*Param)->Len = sizeof(int16_t);
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetValue = (int16_t*)malloc( sizeof(int16_t) );
|
|
*((int16_t*)(*Param)->SetValue) = 0;
|
|
(*Param)->SetLen = sizeof(int16_t);
|
|
break;
|
|
|
|
case dtUnsigned32 :
|
|
// Create Value pointer
|
|
(*Param)->Value = (u_int32_t*)malloc( sizeof(u_int32_t) );
|
|
*((u_int32_t*)(*Param)->Value) = 0;
|
|
(*Param)->Len = sizeof(u_int32_t);
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetValue = (u_int32_t*)malloc( sizeof(u_int32_t) );
|
|
*((u_int32_t*)(*Param)->SetValue) = 0;
|
|
(*Param)->SetLen = sizeof(u_int32_t);
|
|
break;
|
|
|
|
case dtSigned32 :
|
|
// Create Value pointer
|
|
(*Param)->Value = (int32_t*)malloc( sizeof(int32_t) );
|
|
*((int32_t*)(*Param)->Value) = 0;
|
|
(*Param)->Len = sizeof(int32_t);
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetValue = (int32_t*)malloc( sizeof(int32_t) );
|
|
*((int32_t*)(*Param)->SetValue) = 0;
|
|
(*Param)->SetLen = sizeof(int32_t);
|
|
break;
|
|
|
|
case dtFloat32 :
|
|
// Create Value pointer
|
|
(*Param)->Value = (float*)malloc( sizeof(float) );
|
|
*((float*)(*Param)->Value) = 0.0;
|
|
(*Param)->Len = sizeof(float);
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetValue = (float*)malloc( sizeof(float) );
|
|
*((float*)(*Param)->SetValue) = 0.0;
|
|
(*Param)->SetLen = sizeof(float);
|
|
break;
|
|
|
|
case dtString :
|
|
// Create Value pointer
|
|
(*Param)->Len = ParamLen;
|
|
(*Param)->Value = (char*)malloc( ParamLen + 1 );
|
|
memset( (*Param)->Value, 0x0, (*Param)->Len+1 );
|
|
|
|
// Create Set Value pointer
|
|
(*Param)->SetLen = ParamLen;
|
|
(*Param)->SetValue = (char*)malloc( ParamLen + 1 );
|
|
memset( (*Param)->SetValue, 0x0, (*Param)->SetLen+1 );
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Mark as updated
|
|
(*Param)->Changed = true;
|
|
|
|
// Report creation
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Param added - '%s' (%s)",
|
|
ProcessName, Name, ParamName, DataTypeName[DataType] );
|
|
|
|
return *Param;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::DestroyDeviceParam( TDeviceParam ** Param )
|
|
{
|
|
TDeviceParam * NextParam = NULL;
|
|
|
|
// Validate param
|
|
if (!Param || !*Param)
|
|
return false;
|
|
|
|
// Save reference to next Param
|
|
NextParam = (*Param)->Next;
|
|
|
|
// Destroy Param structure
|
|
if ((*Param)->Name)
|
|
free( (*Param)->Name );
|
|
if ((*Param)->Value)
|
|
free( (*Param)->Value );
|
|
if ((*Param)->SetValue)
|
|
free( (*Param)->SetValue );
|
|
|
|
// Destroy Param
|
|
free( *Param );
|
|
|
|
// Remove from list
|
|
*Param = NextParam;
|
|
|
|
// Parameter successfully destroyed
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::UpdateUnsignedValue( TDeviceParam * Param, const u_int32_t Value, bool Init )
|
|
{
|
|
bool Changed = false;
|
|
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
if (Init || (*((u_int16_t*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((u_int16_t*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %u", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), *((u_int16_t*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
case dtUnsigned32 :
|
|
if (Init || (*((u_int32_t*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((u_int32_t*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %u", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), *((u_int32_t*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
case dtFloat32 : // Special case, where float value is stored in Integer memory (e.g. modbus register)
|
|
if (Init || (*((u_int32_t*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((u_int32_t*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %f", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), *((float*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid Data Type
|
|
return false;
|
|
}
|
|
// Generate Channel Event
|
|
if (Changed) {
|
|
Param->Changed = true;
|
|
EventOutput( Param, Changed );
|
|
}
|
|
return Changed;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::UpdateSignedValue( TDeviceParam * Param, const int32_t Value, bool Init )
|
|
{
|
|
bool Changed = false;
|
|
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtSigned16 :
|
|
if (Init || (*((int16_t*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((int16_t*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %d", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), *((int16_t*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
case dtSigned32 :
|
|
if (Init || (*((int32_t*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((int32_t*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %d", ProcessName, Name, Param->Name,
|
|
((Init)? "initialised" : "changed"), *((int32_t*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid Data Type
|
|
return false;
|
|
}
|
|
// Generate Channel Event
|
|
if (Changed) {
|
|
Param->Changed = true;
|
|
EventOutput( Param, Changed );
|
|
}
|
|
return Changed;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::UpdateFloatValue( TDeviceParam * Param, const float Value, bool Init )
|
|
{
|
|
bool Changed = false;
|
|
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtFloat32 :
|
|
if (Init || (*((float*)Param->Value) != Value))
|
|
{
|
|
// Set new value & mark change
|
|
*((float*)Param->Value) = Value;
|
|
|
|
// Mark change & log event
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %f", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), *((float*)Param->Value) );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid Data Type
|
|
return false;
|
|
}
|
|
// Generate Channel Event
|
|
if (Changed) {
|
|
Param->Changed = true;
|
|
EventOutput( Param, Changed );
|
|
}
|
|
return Changed;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::UpdateStringValue( TDeviceParam * Param, const char * Value, const int Len, bool Init )
|
|
{
|
|
bool Changed = false;
|
|
|
|
// Validate
|
|
if (!Param || (Param->DataType != dtString))
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtString :
|
|
// Update register
|
|
if (Init || !CompareParamString( (char*)Param->Value, Param->Len, Value, Len))
|
|
{
|
|
if (Len >= Param->Len) {
|
|
// Copy full register length (ignore additional bytes)
|
|
memcpy( Param->Value, Value, Param->Len );
|
|
((char*)Param->Value)[ Param->Len ] = 0; // null terminate
|
|
}
|
|
else {
|
|
// Copy new value
|
|
memcpy( Param->Value, Value, Len );
|
|
// Zero pad remaining
|
|
memset( &((char*)Param->Value)[Len], 0x0, (Param->Len - Len + 1) ); // Add null teriminate
|
|
}
|
|
|
|
// Mark Change
|
|
Changed = true;
|
|
if (Log) Log->Message( LogLevel, dlLow, "%s/%s: '%s' %s - %s", ProcessName, Name,
|
|
Param->Name, ((Init)? "initialised" : "changed"), (char*)Param->Value );
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid Data Type
|
|
return false;
|
|
}
|
|
// Generate Channel Event
|
|
if (Changed) {
|
|
Param->Changed = true;
|
|
EventOutput( Param, Changed );
|
|
}
|
|
return Changed;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value, bool Force )
|
|
{
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
if (Force || (*((u_int16_t*)Param->SetValue) != Value))
|
|
{
|
|
// Set new value
|
|
*((u_int16_t*)Param->SetValue) = Value;
|
|
|
|
// Mark change
|
|
Param->SetChanged = true;
|
|
}
|
|
break;
|
|
|
|
case dtUnsigned32 :
|
|
if (Force || (*((u_int32_t*)Param->SetValue) != Value))
|
|
{
|
|
// Set new value
|
|
*((u_int32_t*)Param->SetValue) = Value;
|
|
|
|
// Mark change
|
|
Param->SetChanged = true;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid data
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetSignedValue( TDeviceParam * Param, const int32_t Value, bool Force )
|
|
{
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtSigned16 :
|
|
if (Force || (*((int16_t*)Param->SetValue) != Value))
|
|
{
|
|
// Set new value
|
|
*((int16_t*)Param->SetValue) = Value;
|
|
|
|
// Mark change
|
|
Param->SetChanged = true;
|
|
}
|
|
break;
|
|
|
|
case dtSigned32 :
|
|
if (Force || (*((int32_t*)Param->SetValue) != Value))
|
|
{
|
|
// Set new value
|
|
*((int32_t*)Param->SetValue) = Value;
|
|
|
|
// Mark change
|
|
Param->SetChanged = true;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid data
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetFloatValue( TDeviceParam * Param, const float Value, bool Force )
|
|
{
|
|
// Validate
|
|
if (!Param)
|
|
return false;
|
|
|
|
switch (Param->DataType)
|
|
{
|
|
case dtFloat32 :
|
|
if (Force || (*((float*)Param->SetValue) != Value))
|
|
{
|
|
// Set new value
|
|
*((float*)Param->SetValue) = Value;
|
|
|
|
// Mark change
|
|
Param->SetChanged = true;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// Invalid data
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetStringValue( TDeviceParam * Param, const char * Value, const int Len, bool Force )
|
|
{
|
|
// Validate
|
|
if (!Param || (Param->DataType != dtString) || (Len > Param->Len))
|
|
return false;
|
|
|
|
// Update register
|
|
if (Force || !CompareParamString( (char*)Param->Value, Param->Len, Value, Len))
|
|
{
|
|
if (Len >= Param->SetLen) {
|
|
// Copy full register length (ignore additional bytes)
|
|
memcpy( Param->SetValue, Value, Param->SetLen );
|
|
((char*)Param->SetValue)[ Param->SetLen ] = 0; // null terminate
|
|
}
|
|
else {
|
|
// Copy new value
|
|
memcpy( Param->SetValue, Value, Len );
|
|
// Zero pad remaining
|
|
memset( &((char*)Param->SetValue)[Len], 0x0, (Param->SetLen - Len + 1) ); // null terminate
|
|
}
|
|
|
|
// Mark Change
|
|
Param->SetChanged = true;
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetValue( TDeviceParam * Param, const char * Value, const int Len, bool Force )
|
|
{
|
|
u_int32_t UnsignedVal;
|
|
int32_t SignedVal;
|
|
float FloatVal;
|
|
|
|
char * TempStr;
|
|
bool UseTempStr = false;
|
|
|
|
// Validate
|
|
if (!Param || !Value || !Len)
|
|
return false;
|
|
|
|
// Check if string
|
|
if (Param->DataType == dtString)
|
|
{
|
|
// Simply set string
|
|
SetStringValue( Param, Value, Len, Force );
|
|
}
|
|
else
|
|
{
|
|
// Ensure string is zero terminated
|
|
if (Value[Len] != 0) {
|
|
TempStr = (char *)malloc( Len+1 );
|
|
memcpy( TempStr, Value, Len );
|
|
TempStr[Len] = 0;
|
|
UseTempStr = true;
|
|
}
|
|
|
|
// Convert to correct type
|
|
switch (Param->DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
case dtUnsigned32 :
|
|
UnsignedVal = (u_int32_t)strtoul( ((UseTempStr)? TempStr : Value), NULL, 10 );
|
|
SetUnsignedValue( Param, UnsignedVal, Force );
|
|
break;
|
|
|
|
case dtSigned16 :
|
|
case dtSigned32 :
|
|
SignedVal = (u_int32_t)strtol( ((UseTempStr)? TempStr : Value), NULL, 10 );
|
|
SetUnsignedValue( Param, SignedVal, Force );
|
|
break;
|
|
|
|
case dtFloat32 :
|
|
FloatVal = (u_int32_t) strtof( ((UseTempStr)? TempStr : Value), NULL );
|
|
SetUnsignedValue( Param, FloatVal, Force );
|
|
break;
|
|
|
|
default :
|
|
return false;
|
|
}
|
|
|
|
// Clear memory
|
|
if (UseTempStr) {
|
|
free( TempStr );
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::GetValue( TDeviceParam * Param, char * Value, int &Len )
|
|
{
|
|
// Validate
|
|
if (!Param || !Value)
|
|
return false;
|
|
|
|
// Check if return value longer than actual value
|
|
switch (Param->DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
sprintf( Value, "%u", (*((u_int16_t*)Param->Value)) );
|
|
break;
|
|
|
|
case dtUnsigned32 :
|
|
sprintf( Value, "%u", (*((u_int32_t*)Param->Value)) );
|
|
break;
|
|
|
|
case dtSigned16 :
|
|
sprintf( Value, "%d", (*((int16_t*)Param->Value)) );
|
|
break;
|
|
|
|
case dtSigned32 :
|
|
sprintf( Value, "%d", (*((int32_t*)Param->Value)) );
|
|
break;
|
|
|
|
case dtFloat32 :
|
|
sprintf( Value, "%f", (*((float*)Param->Value)) );
|
|
break;
|
|
|
|
case dtString :
|
|
if (Len < Param->Len)
|
|
{
|
|
// Only copy requested no of chars
|
|
memcpy( Value, Param->Value, Len );
|
|
Value[ Len ] = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy( Value, Param->Value, Param->Len );
|
|
Value[ Param->Len ] = 0;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::CompareParamString( const char * ParamValue, const int ParamLen, const char * Value, const int Len )
|
|
{
|
|
bool Match = true;
|
|
char * Pos = NULL;
|
|
|
|
// Compare Value against current value
|
|
if (Len >= ParamLen) {
|
|
// Compare full register length (ignore additional bytes)
|
|
if (memcmp( Value, ParamValue, ParamLen)) {
|
|
Match = false;
|
|
}
|
|
}
|
|
else {
|
|
// Compare length of new value only
|
|
if (memcmp( ParamValue, Value, Len)) {
|
|
Match = false;
|
|
}
|
|
// Remaining bytes must be null
|
|
else {
|
|
for (Pos = (char*)ParamValue; Pos < (char*)ParamValue + ParamLen; Pos++) {
|
|
if (*Pos != 0) {
|
|
Match = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return result
|
|
return Match;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetParamAccess( TDeviceParam * Param, bool Read, bool Write )
|
|
{
|
|
if (!Param)
|
|
return false;
|
|
|
|
Param->Read = Read;
|
|
Param->Write = Write;
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::SetParamEvent( TDeviceParam * Param, const char * ChannelName, long pEventInterval )
|
|
{
|
|
if (!Param)
|
|
return false;
|
|
|
|
Param->EventChannel = GetChannel( ChannelName );
|
|
if (pEventInterval) {
|
|
Param->EventInterval = pEventInterval;
|
|
SetStartTime( &(Param->EventTimeout) );
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::TimedParamEvents()
|
|
{
|
|
TDevice * Device = NULL;
|
|
TDeviceParam * Param = NULL;
|
|
|
|
// Loop through all devices
|
|
Device = FirstDevice;
|
|
while (Device)
|
|
{
|
|
// Loop through all Read parameters
|
|
while ((Param = GetNextReadParam( Device, Param ))) {
|
|
EventOutput( Param, false );
|
|
}
|
|
Device = Device->Next;
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CDeviceCore::GetCmdParam( const char * Start, char * Param, char ** NextParam )
|
|
{
|
|
char * NextDelimeter;
|
|
int ParamLen;
|
|
|
|
// Get length of param
|
|
if ((NextDelimeter = strchr( (char*)Start, ',' ))) {
|
|
ParamLen = NextDelimeter - Start;
|
|
*NextParam = NextDelimeter + 1;
|
|
}
|
|
else {
|
|
// remove \r\n if necessary
|
|
ParamLen = strlen( Start );
|
|
if (Start[ParamLen-1] == '\n')
|
|
ParamLen--;
|
|
if (Start[ParamLen-1] == '\r')
|
|
ParamLen--;
|
|
*NextParam = NULL;
|
|
}
|
|
|
|
// Copy param
|
|
strncpy( Param, Start, ParamLen );
|
|
Param[ParamLen] = 0;
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CDeviceCore::HandleCommand( const char *ChannelName, const char * Data, const int MaxLen )
|
|
{
|
|
int Len;
|
|
char ParamName[50];
|
|
char * NextParam = NULL;
|
|
TDevice * Device = NULL;
|
|
TDeviceParam * Param = NULL;
|
|
char OutputStr[250];
|
|
|
|
// Show accepted input
|
|
Log->Output( LogLevel, dlHigh, loNormal, Data, MaxLen, "%s/%s: Channel '%s' - IN:",
|
|
ProcessName, Name, ChannelName );
|
|
|
|
// Get command command
|
|
GetCmdParam( Data, ParamName, &NextParam );
|
|
if (!strcasecmp( "get", ParamName ))
|
|
{
|
|
// Check for additional parameters
|
|
if (!NextParam) {
|
|
// No Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Missing parameters for 'Get'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get device name
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (!(Device = GetDevice( ParamName ))) {
|
|
// Unknown Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unknown Device: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get parameter name
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (!(Param = GetDeviceParam( Device, ParamName ))) {
|
|
// Unknown Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unknown Param: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Check for additional parameters
|
|
if (NextParam) {
|
|
// Unused Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unnecessary parameters for 'Get'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Build reply
|
|
sprintf( OutputStr, "get,%s,", Param->Name );
|
|
Len = MaxLen - strlen(OutputStr);
|
|
|
|
// Insert value
|
|
if (!GetValue( (TDeviceParam*)Param, &OutputStr[ strlen(OutputStr) ], Len ))
|
|
return false;
|
|
|
|
// Send reply
|
|
strcat( OutputStr, "\n" );
|
|
Output( ChannelName, OutputStr, strlen(OutputStr) );
|
|
return true;
|
|
}
|
|
else if (!strcasecmp( "set", ParamName ))
|
|
{
|
|
// Check for additional parameters
|
|
if (!NextParam) {
|
|
// No Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Missing parameters for 'Set'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get Device name
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (!(Device = GetDevice( ParamName ))) {
|
|
// Unknown Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unknown Device: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get parameter name
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (!(Param = GetDeviceParam( Device, ParamName ))) {
|
|
// Unknown Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unknown Param: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get parameter value
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (strlen(ParamName) == 0) {
|
|
// No Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - No value parameter for 'Set'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Check for additional parameters
|
|
if (NextParam) {
|
|
// Unused Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unnecessary parameters for 'Get'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Set value
|
|
Len = MaxLen;
|
|
if (!SetValue( Param, ParamName, Len, true ))
|
|
return false;
|
|
|
|
// Build & send reply
|
|
sprintf( OutputStr, "set,%s,%s\n", Param->Name, ParamName );
|
|
Output( ChannelName, OutputStr );
|
|
return true;
|
|
}
|
|
else if (!strcasecmp( "status", ParamName ))
|
|
{
|
|
// Check for additional parameters
|
|
if (!NextParam) {
|
|
// No Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Missing parameters for 'Set'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Get Device name
|
|
GetCmdParam( NextParam, ParamName, &NextParam );
|
|
if (!(Device = GetDevice( ParamName ))) {
|
|
// Unknown Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unknown Device: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Check for additional parameters
|
|
if (NextParam) {
|
|
// Unused Parameters
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unnecessary parameters for 'Status'",
|
|
ProcessName, Name, ChannelName );
|
|
return MaxLen;
|
|
}
|
|
|
|
// Build & send reply
|
|
sprintf( OutputStr, "status,%s,%d\n", Device->Name, Device->Online );
|
|
Output( ChannelName, OutputStr );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// Unrecognised command
|
|
Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' - Unrecognized command: '%s'",
|
|
ProcessName, Name, ChannelName, ParamName );
|
|
return MaxLen;
|
|
}
|
|
|
|
return MaxLen;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Generate Event output
|
|
bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force )
|
|
{
|
|
// Validate
|
|
if (!Param || !(Param->EventChannel))
|
|
return false;
|
|
|
|
// Check Timer or force
|
|
if (Force ||
|
|
(Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) )
|
|
{
|
|
// Post event
|
|
char Message[200];
|
|
switch (Param->DataType)
|
|
{
|
|
case dtUnsigned16 :
|
|
sprintf( Message, "%s: %u\n", Param->Name, *((u_int16_t*)Param->Value) );
|
|
break;
|
|
|
|
case dtUnsigned32 :
|
|
sprintf( Message, "%s: %u\n", Param->Name, *((u_int32_t*)Param->Value) );
|
|
break;
|
|
|
|
case dtSigned16 :
|
|
sprintf( Message, "%s: %d\n", Param->Name, *((int16_t*)Param->Value) );
|
|
break;
|
|
|
|
case dtSigned32 :
|
|
sprintf( Message, "%s: %d\n", Param->Name, *((int32_t*)Param->Value) );
|
|
break;
|
|
|
|
case dtFloat32 :
|
|
sprintf( Message, "%s: %f\n", Param->Name, *((float*)Param->Value) );
|
|
break;
|
|
|
|
case dtString :
|
|
sprintf( Message, "%s: %s\n", Param->Name, (char*)Param->Value );
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
Output( Param->EventChannel, Message, strlen(Message) );
|
|
|
|
// Reset timer
|
|
if (Param->EventInterval) {
|
|
SetStartTime( &(Param->EventTimeout) );
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|