Major Updated:
- Added new CDeviceCore Class - Methods and structures moved from CModbusInterface - Keep track of Devices and DeviceParameters - Provides methods & parameters related to polling process - Provides parameter events
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
PROJECT(lib_redAcore)
|
PROJECT(lib_redAcore)
|
||||||
|
|
||||||
ADD_LIBRARY(redAcore TimingCore.cpp LogCore.cpp SignalCore.cpp BufferCore.cpp FunctionCore.cpp FileCore.cpp SelectCore.cpp SelectableCore.cpp)
|
ADD_LIBRARY(redAcore TimingCore.cpp LogCore.cpp SignalCore.cpp BufferCore.cpp FunctionCore.cpp DeviceCore.cpp FileCore.cpp SelectCore.cpp SelectableCore.cpp)
|
||||||
|
|||||||
805
DeviceCore.cpp
Normal file
805
DeviceCore.cpp
Normal file
@@ -0,0 +1,805 @@
|
|||||||
|
/*
|
||||||
|
* FunctionCore.cpp
|
||||||
|
*
|
||||||
|
* Created on: 18 May 2016
|
||||||
|
* Author: wentzelc
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Standard C/C++ Libraries
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// redA Libraries
|
||||||
|
#include "DeviceCore.h"
|
||||||
|
#include "FunctionCore.h"
|
||||||
|
#include "TimingCore.h"
|
||||||
|
#include "LogCore.h"
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CDeviceCore::CDeviceCore( const char * Name, CLogCore * pLog, EDebugLevel DebugLevel, int pOutputDisplay ) :
|
||||||
|
CFunctionCore( Name, pLog, DebugLevel, pOutputDisplay )
|
||||||
|
{
|
||||||
|
// Clear Parameters
|
||||||
|
FirstDevice = NULL;
|
||||||
|
ActiveDevice = NULL;
|
||||||
|
|
||||||
|
// Standard channels
|
||||||
|
DeviceChannel = NULL;
|
||||||
|
CmdChannel = NULL;
|
||||||
|
|
||||||
|
// Polling
|
||||||
|
PollStep = 0;
|
||||||
|
PollInterval = 250;
|
||||||
|
SetStartTime( &PollWait );
|
||||||
|
|
||||||
|
WaitingForReply = false;
|
||||||
|
ReplyTimeout = 200;
|
||||||
|
|
||||||
|
PollRetry = 0;
|
||||||
|
MaxRetries = 3;
|
||||||
|
|
||||||
|
// Update Timer
|
||||||
|
SetUpdate( 0 );
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CDeviceCore::~CDeviceCore()
|
||||||
|
{
|
||||||
|
// Destroy Params
|
||||||
|
while (FirstDevice)
|
||||||
|
DestroyDevice( &FirstDevice );
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::SetPollParam( int pPollInterval )
|
||||||
|
{
|
||||||
|
PollInterval = pPollInterval;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries )
|
||||||
|
{
|
||||||
|
ReplyTimeout = pReplyTimeout;
|
||||||
|
MaxRetries = pMaxRetries;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Generate events
|
||||||
|
bool CDeviceCore::SetUpdate( int pUpdateInterval )
|
||||||
|
{
|
||||||
|
UpdateInterval = pUpdateInterval;
|
||||||
|
SetStartTime( &UpdateTimeout );
|
||||||
|
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;
|
||||||
|
Log->Message( DebugLevel, dlHigh, "%s: Device '%s' %s", 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
|
||||||
|
Log->Message( DebugLevel, dlHigh, "%s: Channel '%s' - %s timeout, retry [%d]", Name, DeviceChannel->Name, ActiveDevice->Name, PollRetry );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Log Event
|
||||||
|
Log->Message( DebugLevel, dlHigh, "%s: Channel '%s' - %s timeout, max [%d]", 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 )
|
||||||
|
{
|
||||||
|
// Get register or end of list
|
||||||
|
TDevice ** Device = &FirstDevice;
|
||||||
|
while (*Device && strcmp( DeviceName, (*Device)->Name ))
|
||||||
|
Device = &((*Device)->Next);
|
||||||
|
|
||||||
|
// Create if not found
|
||||||
|
if (!*Device) {
|
||||||
|
// Create register
|
||||||
|
*Device = (TDevice*)malloc( sizeof(TDevice) );
|
||||||
|
memset( *Device, 0x0, sizeof(TDevice) );
|
||||||
|
|
||||||
|
// Set Name
|
||||||
|
(*Device)->Name = (char *)malloc( strlen( DeviceName )+1 );
|
||||||
|
strcpy( (*Device)->Name, DeviceName );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report creation
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: Device added - '%s'", Name, DeviceName );
|
||||||
|
|
||||||
|
return *Device;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::DestroyDevice( const char * DeviceName )
|
||||||
|
{
|
||||||
|
TDevice ** Device = NULL;
|
||||||
|
|
||||||
|
// Find device
|
||||||
|
if (!(Device = GetDevicePtr(DeviceName)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Destroy Device
|
||||||
|
if (!DestroyDevice( Device ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Device destroyed
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::DestroyDevice( TDevice ** Device )
|
||||||
|
{
|
||||||
|
TDevice * NextDevice = NULL;
|
||||||
|
|
||||||
|
// Validate param
|
||||||
|
if (!Device || !*Device)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Save reference to next Device
|
||||||
|
NextDevice = (*Device)->Next;
|
||||||
|
|
||||||
|
// Destroy Device structure
|
||||||
|
if ((*Device)->Name)
|
||||||
|
free( (*Device)->Name );
|
||||||
|
|
||||||
|
// Destroy paramters
|
||||||
|
while ((*Device)->FirstParam) {
|
||||||
|
DestroyDeviceParam( &((*Device)->FirstParam) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destory Device
|
||||||
|
free( *Device );
|
||||||
|
|
||||||
|
// Remove from list
|
||||||
|
*Device = NextDevice;
|
||||||
|
|
||||||
|
// Device successfully destroyed
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * ParamName, EDataType 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as updated
|
||||||
|
(*Param)->Changed = true;
|
||||||
|
|
||||||
|
// Report creation
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: Param added - '%s' (%s)", Name, ParamName, DataTypeName[DataType] );
|
||||||
|
|
||||||
|
return *Param;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::DestroyDeviceParam( TDevice * Device, const char * ParamName )
|
||||||
|
{
|
||||||
|
TDeviceParam ** Param = NULL;
|
||||||
|
|
||||||
|
// Find param
|
||||||
|
if (!(Param = GetDeviceParamPtr( Device, ParamName )))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Destroy Param
|
||||||
|
if (!DestroyDeviceParam( Param ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Parameter destroyed
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %u", 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %u", 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %f", 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %u", 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %u", 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %f", 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
Log->Message( DebugLevel, dlLow, "%s: '%s' %s - %s", Name, Param->Name, ((Init)? "initialised" : "changed"), (char*)Param->Value );
|
||||||
|
}
|
||||||
|
// 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::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::SetParamScan( TDeviceParam * Param, bool Scan, const char * ChannelName, long pUpdateInterval )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Param)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Set scan parameters
|
||||||
|
Param->Scan = Scan;
|
||||||
|
Param->EventChannel = GetChannel( ChannelName );
|
||||||
|
|
||||||
|
// Configure Update timer
|
||||||
|
if (pUpdateInterval) {
|
||||||
|
Param->UpdateInterval = pUpdateInterval;
|
||||||
|
SetStartTime( &(Param->UpdateTimeout) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool CDeviceCore::TimedParamEvents()
|
||||||
|
{
|
||||||
|
TDevice * Device = NULL;
|
||||||
|
TDeviceParam * Param = NULL;
|
||||||
|
|
||||||
|
// Loop through all devices
|
||||||
|
Device = FirstDevice;
|
||||||
|
while (Device)
|
||||||
|
{
|
||||||
|
// Loop through all scan parameters
|
||||||
|
while ((Param = GetNextScanParam( Device, Param )))
|
||||||
|
{
|
||||||
|
// Generate timed events
|
||||||
|
EventOutput( Param, false );
|
||||||
|
}
|
||||||
|
Device = Device->Next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Generate Event output
|
||||||
|
bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force )
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (!Param || !(Param->EventChannel))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check Timer or force
|
||||||
|
if (Force ||
|
||||||
|
(Param->UpdateInterval && Timeout( Param->UpdateTimeout, Param->UpdateInterval )) )
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
Output( Param->EventChannel, Message, strlen(Message) );
|
||||||
|
|
||||||
|
// Reset timer
|
||||||
|
if (Param->UpdateInterval) {
|
||||||
|
SetStartTime( &(Param->UpdateTimeout) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
202
DeviceCore.h
Normal file
202
DeviceCore.h
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* FunctionCore.h
|
||||||
|
*
|
||||||
|
* Created on: 18 May 2016
|
||||||
|
* Author: wentzelc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REDACORE_DEVICECORE_H_
|
||||||
|
#define REDACORE_DEVICECORE_H_
|
||||||
|
|
||||||
|
// redA Libraries
|
||||||
|
#include "FunctionCore.h"
|
||||||
|
|
||||||
|
// Standard C/C++ Libraries
|
||||||
|
/* no additional */
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Enumerated types
|
||||||
|
typedef enum { dtUnsigned16 = 0, dtSigned16 = 1, dtUnsigned32 = 2, dtSigned32 = 3, dtFloat32 = 4, dtString = 5 } EDataType;
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const char DataTypeName[][20] = { "Unsigned16", "Signed16", "Unsigned32", "Signed32", "Float32", "String" };
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Structure prototypes
|
||||||
|
typedef struct SDevice TDevice;
|
||||||
|
typedef struct SDeviceParam TDeviceParam;
|
||||||
|
|
||||||
|
// Devices with are polled
|
||||||
|
struct SDevice {
|
||||||
|
char * Name;
|
||||||
|
bool Online;
|
||||||
|
|
||||||
|
TDeviceParam * FirstParam;
|
||||||
|
|
||||||
|
TDevice * Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data parameters of devices
|
||||||
|
struct SDeviceParam {
|
||||||
|
char * Name;
|
||||||
|
EDataType DataType;
|
||||||
|
|
||||||
|
bool Scan;
|
||||||
|
TChannel * EventChannel;
|
||||||
|
long UpdateInterval;
|
||||||
|
timeval UpdateTimeout;
|
||||||
|
|
||||||
|
void * Value;
|
||||||
|
int Len;
|
||||||
|
bool Changed;
|
||||||
|
|
||||||
|
void * SetValue;
|
||||||
|
int SetLen;
|
||||||
|
bool SetChanged;
|
||||||
|
|
||||||
|
TDeviceParam * Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CDeviceCore : public CFunctionCore
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// Update
|
||||||
|
int UpdateInterval;
|
||||||
|
timeval UpdateTimeout;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
TDevice * FirstDevice;
|
||||||
|
TDevice * ActiveDevice;
|
||||||
|
|
||||||
|
// Standard channels
|
||||||
|
TChannel * DeviceChannel;
|
||||||
|
TChannel * CmdChannel;
|
||||||
|
|
||||||
|
// Poll
|
||||||
|
int PollStep; // Position in polling sequence
|
||||||
|
timeval PollWait; // Time at which last poll was done
|
||||||
|
long PollInterval; // Minimum delay between polls
|
||||||
|
|
||||||
|
// Reply
|
||||||
|
bool WaitingForReply; // Command sent, waiting for reply
|
||||||
|
long ReplyTimeout; // Max waiting time for reply
|
||||||
|
|
||||||
|
// Retry
|
||||||
|
int PollRetry; // No of polling retries that has timed out
|
||||||
|
int MaxRetries; // Max allowed retries
|
||||||
|
|
||||||
|
// Manage Devices
|
||||||
|
bool DestroyDevice( TDevice ** Device );
|
||||||
|
|
||||||
|
// Find Devices
|
||||||
|
inline TDevice * GetDevice( const char * Name ) {
|
||||||
|
TDevice * Device = FirstDevice;
|
||||||
|
while (Device && strcmp( Device->Name, Name ))
|
||||||
|
Device = Device->Next;
|
||||||
|
return Device;
|
||||||
|
}
|
||||||
|
inline TDevice ** GetDevicePtr( const char * Name ) {
|
||||||
|
TDevice ** Device = &FirstDevice;
|
||||||
|
while (*Device && strcmp( (*Device)->Name, Name ))
|
||||||
|
Device = &((*Device)->Next);
|
||||||
|
return Device;
|
||||||
|
}
|
||||||
|
inline TDevice * GetNextOnlineDevice( TDevice * LastDevice ) {
|
||||||
|
TDevice * Device = LastDevice;
|
||||||
|
while (Device && !Device->Online)
|
||||||
|
Device = Device->Next;
|
||||||
|
return Device;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage Params
|
||||||
|
bool DestroyDeviceParam( TDeviceParam ** Param );
|
||||||
|
|
||||||
|
// Find Params
|
||||||
|
inline TDeviceParam * GetDeviceParam( TDevice * Device, const char * Name ) {
|
||||||
|
if (!Device) return NULL;
|
||||||
|
TDeviceParam * Param = Device->FirstParam;
|
||||||
|
while (Param && strcmp( Param->Name, Name ))
|
||||||
|
Param = Param->Next;
|
||||||
|
return Param;
|
||||||
|
}
|
||||||
|
inline TDeviceParam ** GetDeviceParamPtr( TDevice * Device, const char * Name ) {
|
||||||
|
if (!Device) return NULL;
|
||||||
|
TDeviceParam ** Param = &Device->FirstParam;
|
||||||
|
while (*Param && strcmp( (*Param)->Name, Name ))
|
||||||
|
Param = &((*Param)->Next);
|
||||||
|
return Param;
|
||||||
|
}
|
||||||
|
inline TDeviceParam * GetNextScanParam( TDevice * Device, TDeviceParam * LastParam = NULL ) {
|
||||||
|
if (!Device) return NULL;
|
||||||
|
TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam;
|
||||||
|
while (Param && (!Param->Scan))
|
||||||
|
Param = Param->Next;
|
||||||
|
return Param;
|
||||||
|
}
|
||||||
|
inline TDeviceParam * GetNextChangedParam( TDevice * Device, TDeviceParam * LastParam = NULL ) {
|
||||||
|
if (!Device) return NULL;
|
||||||
|
TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam;
|
||||||
|
while (Param && (!Param->Changed))
|
||||||
|
Param = Param->Next;
|
||||||
|
return Param;
|
||||||
|
}
|
||||||
|
inline TDeviceParam * GetNextSetChangedParam( TDevice * Device, TDeviceParam * LastParam = NULL ) {
|
||||||
|
if (!Device) return NULL;
|
||||||
|
TDeviceParam * Param = (LastParam)? LastParam->Next : Device->FirstParam;
|
||||||
|
while (Param && (!Param->SetChanged))
|
||||||
|
Param = Param->Next;
|
||||||
|
return Param;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tools
|
||||||
|
bool CompareParamString( const char * ParamValue, const int ParamLen, const char * Value, const int Len );
|
||||||
|
|
||||||
|
// Generate events
|
||||||
|
bool EventOutput( TDeviceParam * Param, bool Force );
|
||||||
|
bool TimedParamEvents();
|
||||||
|
|
||||||
|
// Manage device
|
||||||
|
virtual bool DeviceOnline( TDevice * Device, bool Online );
|
||||||
|
|
||||||
|
// Handle Reply Timing
|
||||||
|
virtual void SetWaitForReply();
|
||||||
|
virtual bool CheckReplyTimeout( int TimeoutPollStep );
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Life cycle
|
||||||
|
CDeviceCore( const char * Name, CLogCore * pLog, EDebugLevel DebugLevel, int pOuputDisplay );
|
||||||
|
~CDeviceCore();
|
||||||
|
|
||||||
|
// Generate events
|
||||||
|
bool SetPollParam( int pPollInterval );
|
||||||
|
bool SetReplyParam( int pReplyTimeout, int pMaxRetries );
|
||||||
|
bool SetUpdate( int pUpdateInterval );
|
||||||
|
bool SetParamScan( TDeviceParam * Param, bool Scan, const char * ChannelName, long pUpdateInterval );
|
||||||
|
|
||||||
|
// Manage Devices
|
||||||
|
TDevice * AddDevice( const char * DeviceName );
|
||||||
|
bool DestroyDevice( const char * DeviceName );
|
||||||
|
|
||||||
|
// Manage Params
|
||||||
|
TDeviceParam * AddDeviceParam( TDevice * Device, const char * ParamName, EDataType DataType, int ParamLen = 1 );
|
||||||
|
bool DestroyDeviceParam( TDevice * Device, const char * ParamName );
|
||||||
|
|
||||||
|
// Update/Init Param values
|
||||||
|
bool UpdateUnsignedValue( TDeviceParam * Param, const u_int32_t Value, bool Init );
|
||||||
|
bool UpdateSignedValue( TDeviceParam * Param, const int32_t Value, bool Init );
|
||||||
|
bool UpdateFloatValue( TDeviceParam * Param, const float Value, bool Init );
|
||||||
|
bool UpdateStringValue( TDeviceParam * Param, const char * Value, const int Len, bool Init );
|
||||||
|
|
||||||
|
// Change Param Update instruction
|
||||||
|
bool SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value, bool Force );
|
||||||
|
bool SetSignedValue( TDeviceParam * Param, const int32_t Value, bool Force );
|
||||||
|
bool SetFloatValue( TDeviceParam * Param, const float Value, bool Force );
|
||||||
|
bool SetStringValue( TDeviceParam * Param, const char * Value, const int Len, bool Force );
|
||||||
|
};
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif /* REDACORE_DEVICECORE_H_ */
|
||||||
@@ -74,7 +74,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Life cycle
|
// Life cycle
|
||||||
CFunctionCore( const char * ObjectName, CLogCore * pLog, EDebugLevel pDebugLevel, int pOuputDisplay );
|
CFunctionCore( const char * FunctionName, CLogCore * pLog, EDebugLevel pDebugLevel, int pOuputDisplay );
|
||||||
virtual ~CFunctionCore();
|
virtual ~CFunctionCore();
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
|||||||
Reference in New Issue
Block a user