/* * DeviceCore.cpp * * Created on: 18 May 2016 * Author: wentzelc */ //--------------------------------------------------------------------------- // Standard C/C++ Libraries /* none */ // redA Libraries #include "ApplicationCore.h" #include "DeviceCore.h" #include "DateTimeCore.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 ) { // Polling SetStartTime( &PollWait ); // Data Structures ConfigTypes = new CDataMember(); ValueTree = new CDataMember(); EventData = new CDataMember(); JSONparse = new CJSONparse(); } //--------------------------------------------------------------------------- CDeviceCore::~CDeviceCore() { // Destroy Params while (FirstDevice) DestroyDevice( &FirstDevice ); while (FirstDeviceType) DestroyDevice( &FirstDeviceType ); if (JSONparse) delete JSONparse; if (ConfigTypes) delete ConfigTypes; if (ValueTree) delete ValueTree; if (EventData) delete EventData; } //--------------------------------------------------------------------------- bool CDeviceCore::Init( CDataMember * FunctionConfig ) { char * PersistFile = NULL; CDataMember * PollConfig = NULL; int IntVal1; int IntVal2; char * StrVal; // Call Previous load config if (!CFunctionCore::Init( FunctionConfig )) return false; // Add Channels if (!(CmdChannel = GetChannel( "Command" ))) CmdChannel = AddChannel( "Command", CH_ready ); else SetChannelInState( CmdChannel, CH_ready ); if (!(DeviceChannel = GetChannel( "Device" ))) DeviceChannel = AddChannel( "Device", CH_ready ); else SetChannelInState( DeviceChannel, CH_ready ); if (!(EventChannel = GetChannel( "Event" ))) EventChannel = AddChannel( "Event", CH_ready ); else SetChannelInState( EventChannel, CH_ready ); // 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, T/O:%d, Max:%d", ProcessName, Name, PollInterval, ReplyTimeout, MaxRetries ); // Load Value Tree from persistence file if ((PersistFile = (char*)Config->GetChStr( "PersistFile", NULL, true ))) { JSONparse->SetBase( ValueTree ); JSONparse->ReadFromFile( NULL, PersistFile ); Log->Message( LogLevel, dlMedium, "%s/%s: Persistence File '%s' loaded", ProcessName, Name, PersistFile ); } // Event Output StrVal = (char*)Config->GetChStr( "EventOutput", "None", true ); EventOutputType = GetEventType( StrVal ); Log->Message( LogLevel, dlMedium, "%s/%s: Event Output - Type:%s", ProcessName, Name, EventTypeName[EventOutputType] ); // Update Devices -- may want to do it from derived class intead if (DeviceInit) { InitDevices( FunctionConfig ); //JSONparse->SetBase( ValueTree ); //JSONparse->WriteToScreen( NULL, 2 ); } return true; } //--------------------------------------------------------------------------- bool CDeviceCore::InitDevices( CDataMember * FunctionConfig ) { CDataMember * DeviceConfig = NULL; TDevice * Device = NULL; char * Definition = NULL; char * DeviceName = NULL; int DeviceID = 0; char * DeviceAddr = NULL; char * DeviceType = NULL; char * DataPath = NULL; // Load Device Types DeviceConfig = Config->GetChFirstChild( "DeviceTypes", true ); while (DeviceConfig) { DeviceType = (char*)DeviceConfig->GetName(); if (!DeviceConfig->isObject()) { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Invalid device type config for '%s'", ProcessName, Name, DeviceType ); DeviceConfig = DeviceConfig->GetNextPeer(); continue; } DataPath = (char*)DeviceConfig->GetChStr( "DataPath", NULL ); Device = AddDeviceType( DeviceType, DataPath ); if (Device) { if ((Definition = (char*)DeviceConfig->GetChStr( "Definition", NULL, false ))) { JSONparse->SetBase( ConfigTypes ); if (JSONparse->ReadFromFile( DeviceType, Definition )) { // Contains file reference InitDeviceParams( Device, ConfigTypes->GetChild( DeviceType ), NULL ); JSONparse->SetBase( ConfigTypes ); JSONparse->WriteToFile( DeviceType, Definition ); } else { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Fail to load device type '%s' from file: '%s'", ProcessName, Name, DeviceType, DeviceConfig->GetStr() ); } } else { InitDeviceParams( Device, DeviceConfig, NULL ); // Contains definition } } DeviceConfig = DeviceConfig->GetNextPeer(); } // Load Actual Devices DeviceConfig = Config->GetChFirstChild( "Devices", true ); while (DeviceConfig) { DeviceName = (char*)DeviceConfig->GetName(); if (!DeviceConfig->isObject()) { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Invalid device config for '%s'", ProcessName, Name, DeviceName ); DeviceConfig = DeviceConfig->GetNextPeer(); continue; } DeviceID = DeviceConfig->GetChInt( "ID", 0 ); DeviceAddr = (char*)DeviceConfig->GetChStr( "Address", NULL ); DeviceType = (char*)DeviceConfig->GetChStr( "Type", NULL ); DataPath = (char*)DeviceConfig->GetChStr( "DataPath", NULL ); Device = AddDevice( DeviceName, DeviceType, DeviceID, DeviceAddr, DataPath ); if (Device) { InitDeviceParams( Device, DeviceConfig, Device->DataNode ); } DeviceConfig = DeviceConfig->GetNextPeer(); } return true; } //--------------------------------------------------------------------------- bool CDeviceCore::InitDeviceParams( TDevice * Device, CDataMember * DeviceConfig, CDataMember * ParentNode ) { CDataMember * ParamConfig; TDeviceParam * Template; bool isType = (Device->Name)? false : true; // Copy Template Params Template = (Device->Template)? Device->Template->FirstParam : NULL; while (Template) { CopyTemplateParam( Device, Template, ParentNode ); Template = Template->Next; } CopyTemplateParamGroups( Device ); // Read Device Params ParamConfig = DeviceConfig->GetChFirstChild( "Parameters", true ); while (ParamConfig) { InitDeviceParam( Device, ParamConfig, NULL, ((isType)? NULL : Device->DataPath), ParentNode, NULL ); ParamConfig = ParamConfig->GetNextPeer(); } return true; } //--------------------------------------------------------------------------- bool CDeviceCore::CopyTemplateParam( TDevice * Device, TDeviceParam * Template, CDataMember * ParentNode ) { TDeviceParam * Param = NULL; CDataMember * DataNode = NULL; char * DataPath = NULL; if ((Param = AddDeviceParam( Device, Template->Name, Template->DataType, Template->Len ))) { SetParamAccess( Param, Template->Read, Template->Write ); if (Template->DataPath) { DataPath = (char*)malloc( strlen(Device->DataPath) + strlen(Template->DataPath) + 2); sprintf( DataPath, "%s/%s", Device->DataPath, Template->DataPath ); DataNode = (Device->DataNode)? Device->DataNode->GetChild( Template->DataPath, true ) : NULL; SetDataPath( Param, DataPath, DataNode ); } if ((Template->DataType == dtBool) || (Template->DataType == dtUnsigned16) || (Template->DataType == dtUnsigned32_HL) || (Template->DataType == dtUnsigned32_LH)) { UpdateUnsignedValue( Param, *((u_int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) SetUnsignedValue( Param, *((u_int32_t*)Template->Value), true ); } else if ((Template->DataType == dtSigned16) || (Template->DataType == dtSigned32_HL) || (Template->DataType == dtSigned32_LH)) { UpdateSignedValue( Param, *((int32_t*)Template->Value), Template->Changed ); if (Template->SetChanged) SetSignedValue( Param, *((int32_t*)Template->Value), true ); } else if ((Template->DataType == dtFloat32_L) || (Template->DataType == dtFloat32_B)) { UpdateFloatValue( Param, *((float*)Template->Value), Template->Changed ); if (Template->SetChanged) SetFloatValue( Param, *((float*)Template->Value), true ); } else if (Template->DataType == dtString) { UpdateStringValue( Param, (char*)Template->Value, Template->Len, Template->Changed ); if (Template->SetChanged) SetStringValue( Param, (char*)Template->Value, Template->Len, true ); } SetParamEvent( Param, (Template->EventChannel)? Template->EventChannel->Name : NULL, Template->EventInterval ); } if (DataPath) free( DataPath ); return true; } //--------------------------------------------------------------------------- bool CDeviceCore::CopyTemplateParamGroups( TDevice * Device ) { TDeviceParamGroup * TemplateGroup; TDeviceParamItem * TemplateItem; TDeviceParamGroup * ParamGroup; TDeviceParam * Param; // Check if Template Groups exists if (!Device->Template || !(TemplateGroup = Device->Template->FirstParamGroup)) return false; while (TemplateGroup) { // Create group ParamGroup = AddParamGroup( Device, TemplateGroup->Name ); // Add Registers TemplateItem = TemplateGroup->FirstParam; while (TemplateItem) { if ((Param = GetDeviceParam( Device, TemplateItem->Param->Name ))) AddParamItem( ParamGroup, Param ); TemplateItem = TemplateItem->NextItem; } TemplateGroup = TemplateGroup->NextGroup; } return true; } //--------------------------------------------------------------------------- bool CDeviceCore::InitDeviceParam( TDevice * Device, CDataMember * ParamConfig, const char * ParentName, const char * ParentPath, CDataMember * ParentNode, TDeviceParamGroup * ParentParamGroup ) { char * NodeName; char * FullName; char * DataPath; CDataMember * DataNode; CDataMember * Children; CDataMember * ChildConfig; CDataMember * ChildMap; CDataMember * InitVal; TDeviceParam * Param; EDeviceDataType DataType; char * ParamGroupName; SDeviceParamGroup * ParamGroup; bool Read; bool Write; char * EventOut; int EventInt; // Create Node Name NodeName = (char*)ParamConfig->GetName(); if (ParentName && *ParentName) { FullName = (char*)malloc( strlen(ParentName) + strlen(NodeName) + 2 ); sprintf( FullName, "%s_%s", ParentName, NodeName ); } else { FullName = strdup( NodeName ); } // Create Node Path DataNode = (ParentNode)? ParentNode->GetChild( NodeName, true ) : NULL; if (ParentPath && *ParentPath) { DataPath = (char*)malloc( strlen(ParentPath) + strlen(NodeName) + 2 ); sprintf( DataPath, "%s/%s", ParentPath, NodeName ); } else { DataPath = strdup( NodeName ); } if ((Children = ParamConfig->GetChild( "Children", false ))) { // Data Branch if ((ParamGroupName = (char*)ParamConfig->GetChStr( "ParamGroup", NULL, false ))) { ParamGroup = AddParamGroup( Device, ParamGroupName ); } else { ParamGroup = ParentParamGroup; } if (Children->isString()) { // Load from file ChildMap = new CDataMember(); JSONparse->SetBase( ChildMap ); if (!JSONparse->ReadFromFile( NULL, Children->GetStr() )) { if (Log) Log->Message( LogLevel, dlLow, "%s/%s: Fail to load parameters from file: '%s'", ProcessName, Name, Children->GetStr() ); } else { ChildConfig = ChildMap->GetFirstChild(); while (ChildConfig) { InitDeviceParam( Device, ChildConfig, FullName, DataPath, DataNode, ParamGroup ); ChildConfig = ChildConfig->GetNextPeer(); } } delete ChildMap; } else { // Load children ChildConfig = Children->GetFirstChild(); while (ChildConfig) { InitDeviceParam( Device, ChildConfig, FullName, DataPath, DataNode, ParamGroup ); ChildConfig = ChildConfig->GetNextPeer(); } } } else { // Data Leaf DataType = GetDataType((char*)ParamConfig->GetChStr( "Type", "Unsigned16", true )); if ((Param = AddDeviceParam( Device, FullName, DataType, 1 ))) { // Leaf Read = ParamConfig->GetChBool( "Read", false, true ); Write = ParamConfig->GetChBool( "Write", false, true ); SetParamAccess( Param, Read, Write ); SetDataPath( Param, DataPath, DataNode ); if ((InitVal = ParamConfig->GetChild( "InitValue", false ))) { if ((DataType == dtBool) || (DataType == dtUnsigned16) || (DataType == dtUnsigned32_HL) || (DataType == dtUnsigned32_LH)) { UpdateUnsignedValue( Param, InitVal->GetInt(0), Read ); if (Write) SetUnsignedValue( Param, InitVal->GetInt(0), true ); } else if ((DataType == dtSigned16) || (DataType == dtSigned32_HL) || (DataType == dtSigned32_LH)) { UpdateSignedValue( Param, InitVal->GetInt(0), Read ); if (Write) SetSignedValue( Param, InitVal->GetInt(0), true ); } else if ((DataType == dtFloat32_L) || (DataType == dtFloat32_B)) { UpdateFloatValue( Param, InitVal->GetFloat(0), Read ); if (Write) SetFloatValue( Param, InitVal->GetFloat(0), true ); } else if (DataType == dtString) { UpdateStringValue( Param, InitVal->GetStr(""), InitVal->GetLen(), Read ); if (Write) SetStringValue( Param, InitVal->GetStr(""), InitVal->GetLen(), true ); } } if ((ParamGroupName = (char*)ParamConfig->GetChStr( "ParamGroup", NULL, false ))) { ParamGroup = AddParamGroup( Device, ParamGroupName ); } else { ParamGroup = ParentParamGroup; } if (ParamGroup) AddParamItem( ParamGroup, Param ); EventOut = (char*)ParamConfig->GetChStr( "EventChannel", NULL, false ); EventInt = ParamConfig->GetChInt( "EventInterval", 0, false ); SetParamEvent( Param, EventOut, EventInt ); } } if (FullName) free( FullName ); if (DataPath) free( DataPath ); return true; } //--------------------------------------------------------------------------- bool CDeviceCore::SetPollParam( int pPollInterval ) { PollInterval = pPollInterval; return true; } //--------------------------------------------------------------------------- bool CDeviceCore::SetReplyParam( int pReplyTimeout, int pMaxRetries ) { DefReplyTimeout = pReplyTimeout; 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, dlLow, "%s/%s: Device '%s' %s", ProcessName, Name, Device->Name, ((Online)? "online" : "offline") ); return true; } //--------------------------------------------------------------------------- void CDeviceCore::SetWaitForReply( int CustomTimeout ) { // Start timer SetStartTime( &PollWait ); // Set flag ReplyTimeout = (CustomTimeout >= 0)? CustomTimeout : DefReplyTimeout; WaitingForReply = true; InvalidReply = false; } //--------------------------------------------------------------------------- void CDeviceCore::ValidReplyReceived() { // Reset parameters for next command WaitingForReply = false; InvalidReply = false; PollRetry = 0; } //--------------------------------------------------------------------------- bool CDeviceCore::CheckReplyTimeout() { // Check for Reply timeout if (!WaitingForReply || !Timeout( PollWait, ReplyTimeout )) { // No timeout return false; } // Update flags WaitingForReply = false; InvalidReply = false; PollRetry++; // Handle No Reply / Retry if (PollRetry > MaxRetries) { if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Device '%s' %s - Max retries", ProcessName, Name, DeviceChannel->Name, ActiveDevice->Name, ((InvalidReply)? "invalid reply" : "timeout"), PollRetry ); // Set Device Offline DeviceOnline( ActiveDevice, false ); PollRetry = 0; return true; } // Try again if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Device '%s' %s, Retry %d/%d", ProcessName, Name, DeviceChannel->Name, ActiveDevice->Name, ((InvalidReply)? "invalid reply" : "timeout"), PollRetry, MaxRetries ); return false; } //--------------------------------------------------------------------------- TDevice * CDeviceCore::AddDeviceType( const char * DeviceTypeName, const char * DataPath ) { TDevice ** DeviceType = GetDeviceTypePtr( DeviceTypeName ); if (!DeviceType) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add device type '%s'", ProcessName, Name, ((DeviceTypeName)? DeviceTypeName : "[device type]") ); return NULL; } else if (*DeviceType) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Device type '%s' already exists", ProcessName, Name, DeviceTypeName ); } else { *DeviceType = new TDevice; (*DeviceType)->Type = strdup( DeviceTypeName ); (*DeviceType)->DataPath = strdup( DataPath ); if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Added device type '%s'", ProcessName, Name, DeviceTypeName ); } return *DeviceType; } //--------------------------------------------------------------------------- TDevice * CDeviceCore::AddDevice( const char * DeviceName, const char * DeviceType, const int DeviceID, const char * DeviceAddress, const char * DataPath ) { TDevice ** Device = &FirstDevice; if (!DeviceName || !*DeviceName || (DeviceAddress && !*DeviceAddress)) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add device '%s' - Invalid parameters, Tp:'%s' ID:%d, Addr:'%s'", ProcessName, Name, ((DeviceName)? DeviceName : "[no name]"), ((DeviceType)? DeviceType : "[none]"), DeviceID, ((DeviceAddress)? DeviceAddress : "[none]") ); return NULL; } // Find device matching by any parameter while (*Device && strcasecmp((*Device)->Name, DeviceName) && (!DeviceID || (*Device)->ID != DeviceID) && (!DeviceAddress || strcasecmp((*Device)->Address, DeviceAddress))) Device = &((*Device)->Next); if (*Device) { if (!strcasecmp((*Device)->Name, DeviceName)) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add device '%s' - Name already exists", ProcessName, Name, DeviceName ); } else if (DeviceID && ((*Device)->ID == DeviceID)) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add device '%s' - ID '%d' already exists", ProcessName, Name, DeviceName, DeviceID ); } else if (DeviceAddress && !strcasecmp((*Device)->Address, DeviceAddress)) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add device '%s' - Address '%s' already exists", ProcessName, Name, DeviceName, DeviceAddress ); } return NULL; } else { *Device = new TDevice; (*Device)->Name = strdup( DeviceName ); (*Device)->ID = DeviceID; if (DeviceAddress) { (*Device)->Address = strdup( DeviceAddress ); } if (DeviceType && *DeviceType) { (*Device)->Type = strdup( DeviceType ); (*Device)->Template = GetDeviceType( DeviceType ); if (DataPath && *DataPath) { (*Device)->DataPath = strdup( DataPath ); (*Device)->DataNode = ValueTree->GetChild( (*Device)->DataPath, true ); } else if ((*Device)->Template && (*Device)->Template->DataPath) { // Use Template path as prefix, then add device ID or address int PathLen = strlen((*Device)->Template->DataPath) + strlen(DeviceName) + 1; (*Device)->DataPath = (char*)malloc(PathLen +1); sprintf( (*Device)->DataPath, "%s/%s", (*Device)->Template->DataPath, DeviceName ); (*Device)->DataNode = ValueTree->GetChild( (*Device)->DataPath, true ); } } if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Added device '%s' - Tp:'%s'%s, ID:%d, Addr:'%s'", ProcessName, Name, DeviceName, ((DeviceType)? DeviceType : "[none]"), (((*Device)->Template)? "*" : ""), DeviceID, ((DeviceAddress)? DeviceAddress : "[none]") ); } 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)->Address) free( (*Device)->Address ); if ((*Device)->Type) free( (*Device)->Type ); if ((*Device)->DataPath) free( (*Device)->DataPath ); // Destroy parameters & groups while ((*Device)->FirstParam) { DestroyDeviceParam( &((*Device)->FirstParam) ); } while ((*Device)->FirstParamGroup) { DestroyParamGroup( &((*Device)->FirstParamGroup) ); } // Destroy Device delete *Device; // Remove from list *Device = NextDevice; // Device successfully destroyed return true; } //--------------------------------------------------------------------------- TDeviceParam * CDeviceCore::AddDeviceParam( TDevice * Device, const char * ParamName, EDeviceDataType DataType, int ParamLen ) { TDeviceParam ** Param = GetDeviceParamPtr( Device, ParamName ); if (!Param) { // Invalid device/param if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add Param '%s/%s' - Invalid parameters, Tp:'%s'", ProcessName, Name, ((!Device)? "[no name]" : (Device->Name)? Device->Name : Device->Type), ((!ParamName)? "[no name]" : ParamName), DataTypeName[DataType]); return NULL; } else if (*Param) { // Parameter already exists if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add Param '%s/%s' - Already exists", ProcessName, Name, ((Device->Name)? Device->Name : Device->Type), ParamName, DataTypeName[DataType]); return NULL; } else { // Create register *Param = new TDeviceParam; // Set Name (*Param)->Name = strdup( ParamName ); (*Param)->DataType = DataType; (*Param)->Device = Device; // Init values switch (DataType) { case dtBool : // Create Value pointer (*Param)->Value = (bool*)malloc( sizeof(bool) ); *((bool*)(*Param)->Value) = 0; (*Param)->Len = sizeof(bool); // Create Set Value pointer (*Param)->SetValue = (bool*)malloc( sizeof(bool) ); *((bool*)(*Param)->SetValue) = 0; (*Param)->SetLen = sizeof(bool); break; case dtUnsigned16 : // Create Value pointer (*Param)->Value = (u_int16_t*)malloc( sizeof(u_int16_t) ); *((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_HL : case dtUnsigned32_LH : // 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_HL : case dtSigned32_LH : // 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_L : case dtFloat32_B : // 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; } (*Param)->Changed = true; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Added param '%s/%s', Tp:'%s'", ProcessName, Name, ((Device->Name)? Device->Name : Device->Type), 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 ); if ((*Param)->DataPath) free( (*Param)->DataPath ); // Destroy Param delete *Param; // Remove from list *Param = NextParam; // Parameter successfully destroyed return true; } //--------------------------------------------------------------------------- TDeviceParamGroup * CDeviceCore::AddParamGroup( TDevice * Device, const char * GroupName ) { TDeviceParamGroup ** ParamGroup = GetParamGroupPtr( Device, GroupName ); if (!ParamGroup) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Could not add param group '%s'", ProcessName, Name, ((!Device)? "[device]" : (Device->Name)? Device->Name : Device->Type), ((GroupName)? GroupName : "[group]") ); return NULL; } else if (*ParamGroup) { if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Param group '%s/%s' already exists", ProcessName, Name, ((Device->Name)? Device->Name : Device->Type), GroupName ); } else { *ParamGroup = new TDeviceParamGroup; (*ParamGroup)->Name = strdup( GroupName ); (*ParamGroup)->Device = Device; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Added param group '%s/%s'", ProcessName, Name, ((Device->Name)? Device->Name : Device->Type), GroupName ); } return *ParamGroup; } //--------------------------------------------------------------------------- bool CDeviceCore::DestroyParamGroup( TDeviceParamGroup ** ParamGroup ) { TDeviceParamGroup * NextGroup = NULL; // Validate ParamGroup if (!ParamGroup || !*ParamGroup) return false; // Save reference to next Param Group NextGroup = (*ParamGroup)->NextGroup; // Destroy Param Group structure if ((*ParamGroup)->Name) free( (*ParamGroup)->Name ); // Destroy items while ((*ParamGroup)->FirstParam) { DestroyParamItem( &((*ParamGroup)->FirstParam) ); } // Destroy ParamGroup delete *ParamGroup; // Remove from list *ParamGroup = NextGroup; // ParamGroup successfully destroyed return true; } //--------------------------------------------------------------------------- TDeviceParamItem * CDeviceCore::AddParamItem( TDeviceParamGroup * Group, TDeviceParam * Param ) { TDeviceParamItem ** Item; if (!Param || !(Item = GetParamItemPtr( Group, Param->Name ))) { // Invalid group/param if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Param group item '%s/%s' cannot be created", ProcessName, Name, ((!Group)? "[group]" : Group->Name), ((!Param->Name)? "[param]" : Param->Name)); return NULL; } else if (*Item) { // Item already exists if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Param Group item '%s/%s' already exists", ProcessName, Name, Group->Name, Param->Name ); } else { *Item = new TDeviceParamItem; (*Item)->Param = Param; if (Param->Read) Group->Read = true; if (Param->Write) Group->Write = true; if (Log) Log->Message( LogLevel, dlMedium, "%s/%s: Added param group item '%s/%s/%s'", ProcessName, Name, ((Group->Device->Name)? Group->Device->Name : Group->Device->Type), Group->Name, Param->Name ); } return *Item; } //--------------------------------------------------------------------------- bool CDeviceCore::DestroyParamItem( TDeviceParamItem ** Item ) { TDeviceParamItem * NextParam = NULL; if (!Item || !*Item) return false; NextParam = (*Item)->NextItem; delete *Item; *Item = NextParam; return true; } //--------------------------------------------------------------------------- bool CDeviceCore::SetDataPath( TDeviceParam * Param, const char * DataPath, CDataMember * DataNode ) { if (!Param) return false; Param->DataPath = strdup( DataPath ); Param->DataNode = DataNode; if (Log) { char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; Log->Message( LogLevel, dlMedium, "%s/%s: Set param '%s/%s' data ref - P:%s, N:%s", ProcessName, Name, DeviceName, Param->Name, DataPath, ((DataNode)? DataNode->GetName() : "(none)") ); } return true; } //--------------------------------------------------------------------------- bool CDeviceCore::SetParamAccess( TDeviceParam * Param, bool Read, bool Write ) { if (!Param) return false; Param->Read = Read; Param->Write = Write; if (Log) { char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; Log->Message( LogLevel, dlMedium, "%s/%s: Set param '%s/%s' access - R:%d, W:%d", ProcessName, Name, DeviceName, Param->Name, Read, 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) ); } if (Log) { char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; Log->Message( LogLevel, dlMedium, "%s/%s: Set param '%s/%s' event - Ch:'%s', Int:%d", ProcessName, Name, DeviceName, Param->Name, ((ChannelName)? ChannelName : ""), pEventInterval ); } 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 dtBool : if (Init || (*((bool*)Param->Value) != Value)) { // Set new value & mark change *((bool*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((bool*)Param->Value) ); // Mark change & log event Changed = true; if (Log) { char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %u", ProcessName, Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); } } break; case dtUnsigned16 : if (Init || (*((u_int16_t*)Param->Value) != Value)) { // Set new value & mark change *((u_int16_t*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((u_int16_t*)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, *((u_int16_t*)Param->Value) ); } } break; case dtUnsigned32_HL : case dtUnsigned32_LH : if (Init || (*((u_int32_t*)Param->Value) != Value)) { // Set new value & mark change *((u_int32_t*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((u_int32_t*)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, *((u_int32_t*)Param->Value) ); } } break; case dtFloat32_L : case dtFloat32_B : // 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; if (Param->DataNode) Param->DataNode->SetInt( *((u_int32_t*)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' - %f", ProcessName, Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((float*)Param->Value) ); } } break; default : // Invalid Data Type return false; } // Generate Channel Event if (Changed) { Param->Changed = true; if (Param->Device->Name) EventOutput( Param, Changed ); // Only send event of actual device, not type/template } 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 dtBool : if (Init || (*((bool*)Param->Value) != Value)) { // Set new value & mark change *((bool*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((bool*)Param->Value) ); // Mark change & log event Changed = true; if (Log) { char * DeviceName = (Param->Device->Name)? Param->Device->Name : Param->Device->Type; Log->Message( LogLevel, dlLow, "%s/%s: %s param '%s/%s' - %d", ProcessName, Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((bool*)Param->Value) ); } } break; case dtSigned16 : if (Init || (*((int16_t*)Param->Value) != Value)) { // Set new value & mark change *((int16_t*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((int16_t*)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, *((int16_t*)Param->Value) ); } } break; case dtSigned32_HL : case dtSigned32_LH : if (Init || (*((int32_t*)Param->Value) != Value)) { // Set new value & mark change *((int32_t*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetInt( *((int32_t*)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, Param->Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((int32_t*)Param->Value) ); } } break; default : // Invalid Data Type return false; } // Generate Channel Event if (Changed) { Param->Changed = true; if (Param->Device->Name) EventOutput( Param, Changed ); // Only send event of actual device, not type/template } 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_L : case dtFloat32_B : if (Init || (*((float*)Param->Value) != Value)) { // Set new value & mark change *((float*)Param->Value) = Value; if (Param->DataNode) Param->DataNode->SetFloat( *((float*)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' - %f", ProcessName, Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, *((float*)Param->Value) ); } } break; default : // Invalid Data Type return false; } // Generate Channel Event if (Changed) { Param->Changed = true; if (Param->Device->Name) EventOutput( Param, Changed ); // Only send event of actual device, not type/template } 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 } if (Param->DataNode) Param->DataNode->SetStr( (char*)Param->Value ); // Mark Change 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' - '%s'", ProcessName, Name, ((Init)? "Init" : "Changed"), DeviceName, Param->Name, (char*)Param->Value ); } } break; default : // Invalid Data Type return false; } // Generate Channel Event if (Changed) { Param->Changed = true; if (Param->Device->Name) EventOutput( Param, Changed ); // Only send event of actual device, not type/template } return Changed; } //--------------------------------------------------------------------------- bool CDeviceCore::SetUnsignedValue( TDeviceParam * Param, const u_int32_t Value, bool Force ) { // Validate if (!Param) return false; switch (Param->DataType) { case dtBool : if (Force || (*((bool*)Param->SetValue) != Value)) { // Set new value *((bool*)Param->SetValue) = Value; // Mark change Param->SetChanged = true; } break; case dtUnsigned16 : if (Force || (*((u_int16_t*)Param->SetValue) != Value)) { // Set new value *((u_int16_t*)Param->SetValue) = Value; // Mark change Param->SetChanged = true; } break; case dtUnsigned32_HL : case dtUnsigned32_LH : 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 dtBool : if (Force || (*((bool*)Param->SetValue) != Value)) { // Set new value *((bool*)Param->SetValue) = Value; // Mark change Param->SetChanged = true; } break; case dtSigned16 : if (Force || (*((int16_t*)Param->SetValue) != Value)) { // Set new value *((int16_t*)Param->SetValue) = Value; // Mark change Param->SetChanged = true; } break; case dtSigned32_HL : case dtSigned32_LH : 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_L : case dtFloat32_B : 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 = strndup( Value, Len ); TempStr[Len] = 0; UseTempStr = true; } // Convert to correct type switch (Param->DataType) { case dtBool : case dtUnsigned16 : case dtUnsigned32_HL : case dtUnsigned32_LH : UnsignedVal = (u_int32_t)strtoul( ((UseTempStr)? TempStr : Value), NULL, 10 ); SetUnsignedValue( Param, UnsignedVal, Force ); break; case dtSigned16 : case dtSigned32_HL : case dtSigned32_LH : SignedVal = (u_int32_t)strtol( ((UseTempStr)? TempStr : Value), NULL, 10 ); SetUnsignedValue( Param, SignedVal, Force ); break; case dtFloat32_L : case dtFloat32_B : 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) { Value[0] = 0; return false; } // Check if return value longer than actual value switch (Param->DataType) { case dtBool : sprintf( Value, "%u", (*((bool*)Param->Value)) ); break; case dtUnsigned16 : sprintf( Value, "%u", (*((u_int16_t*)Param->Value)) ); break; case dtUnsigned32_HL : case dtUnsigned32_LH : sprintf( Value, "%u", (*((u_int32_t*)Param->Value)) ); break; case dtSigned16 : sprintf( Value, "%d", (*((int16_t*)Param->Value)) ); break; case dtSigned32_HL : case dtSigned32_LH : sprintf( Value, "%d", (*((int32_t*)Param->Value)) ); break; case dtFloat32_L : case dtFloat32_B : 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 : Value[0] = 0; 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::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 (!Start || !*Start) { Param[0] = 0; NextParam = NULL; return false; } else 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 * SourceRef, const char * Data, const int MaxLen ) { int Len; char Value[50]; char * NextParam = NULL; TDevice * Device = NULL; TDeviceParam * Param = NULL; char OutputStr[250]; bool Error = false; // Show accepted input Log->Output( LogLevel, dlHigh, loNormal, Data, MaxLen, "%s/%s: Channel '%s' - IN:", ProcessName, Name, ChannelName ); // Get command command GetCmdParam( Data, Value, &NextParam ); if (!strcasecmp( "get", Value )) { // Validate parameters if (!GetCmdParam( NextParam, Value, &NextParam)) { strcpy( OutputStr, "- Missing device name" ); Error = true; } else if (!(Device = GetDeviceByName( Value ))) { strcpy( OutputStr, "- Device not found"); Error = true; } else if (!GetCmdParam( NextParam, Value, &NextParam )) { strcpy( OutputStr, "- Missing parameter name" ); Error = true; } else if (!(Param = GetDeviceParam( Device, Value ))) { strcpy( OutputStr, "- Device parameter not found"); Error = true; } else if (NextParam) { strcpy( OutputStr, "- Too many parameters"); Error = true; } else { sprintf( OutputStr, "> %s,%s = ", Device->Name, Param->Name ); Len = MaxLen - strlen(OutputStr) - 1; if (!GetValue( (TDeviceParam*)Param, &OutputStr[ strlen(OutputStr) ], Len )) { strcpy( OutputStr, "- Error getting parameter"); Error = true; } else { strcat( OutputStr, "\n" ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } // Report error if (Error) { Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Get", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else if (!strcasecmp( "set", Value )) { // Validate parameters if (!GetCmdParam( NextParam, Value, &NextParam)) { strcpy( OutputStr, "- Missing device name" ); Error = true; } else if (!(Device = GetDeviceByName( Value ))) { strcpy( OutputStr, "- Device not found"); Error = true; } else if (!GetCmdParam( NextParam, Value, &NextParam )) { strcpy( OutputStr, "- Missing parameter name" ); Error = true; } else if (!(Param = GetDeviceParam( Device, Value ))) { strcpy( OutputStr, "- Device parameter not found"); Error = true; } else if (!GetCmdParam( NextParam, Value, &NextParam )) { strcpy( OutputStr, "- Missing set value"); Error = true; } else if (NextParam) { strcpy( OutputStr, "- Too many parameters"); Error = true; } else { if (!SetValue( Param, Value, strlen(Value), true )) { strcpy( OutputStr, "- Error seting parameter"); Error = true; } else { sprintf( OutputStr, "> set %s,%s = %s\n", Device->Name, Param->Name, Value ); Output( ChannelName, NULL, true, OutputStr ); } } // Report error if (Error) { Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Set", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else if (!strcasecmp( "status", Value )) { // Validate parameters if (!GetCmdParam( NextParam, Value, &NextParam)) { strcpy( OutputStr, "- Missing device name" ); Error = true; } else if (!(Device = GetDeviceByName( Value ))) { strcpy( OutputStr, "- Device not found"); Error = true; } else if (NextParam) { strcpy( OutputStr, "- Too many parameters"); Error = true; } else { sprintf( OutputStr, "> %s - %s\n", Device->Name, ((Device->Online)? "online" : "offline") ); Output( ChannelName, NULL, true, OutputStr ); } // Report error if (Error) { Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s' Status", ProcessName, Name, ChannelName, OutputStr ); strcat( OutputStr, "\n" ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } } else { // Unrecognised command strcpy( OutputStr, "- Unknown command"); Log->Message( LogLevel, dlMedium, "%s/%s: Channel '%s', %s%s", ProcessName, Name, ChannelName, Value, OutputStr ); strcat( OutputStr, " (comma separated values)\n" ); Output( ChannelName, NULL, true, OutputStr, strlen(OutputStr) ); } return MaxLen; } //--------------------------------------------------------------------------- // Generate Event output bool CDeviceCore::EventOutput( TDeviceParam * Param, bool Force ) { int EventLen = EventMsgLen; CDataMember * Path = NULL; // Validate if (!Param || !(Param->EventChannel)) return false; if (EventOutputType == et_None) return false; // Check Timer or force if (Force || (Param->EventInterval && Timeout( Param->EventTimeout, Param->EventInterval )) ) { // Create message // Post event if (true) { // JSON output EventData->Clear(); EventData->SetChStr( "Type", "ParamEvent" ); 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; case dtUnsigned32_HL : case dtUnsigned32_LH : EventData->SetChBool( "Value", *((u_int32_t*)Param->Value) ); break; case dtSigned16 : EventData->SetChBool( "Value", *((int16_t*)Param->Value) ); break; case dtSigned32_HL : case dtSigned32_LH : EventData->SetChBool( "Value", *((int32_t*)Param->Value) ); break; case dtFloat32_L : case dtFloat32_B : EventData->SetChBool( "Value", *((float*)Param->Value) ); break; case dtString : EventData->SetChBool( "Value", (char*)Param->Value ); break; default : EventData->SetChNull( "Value" ); break; } JSONparse->SetBase( EventData ); JSONparse->WriteToString( NULL, EventMsg, EventLen, 0 ); } else { switch (Param->DataType) { case dtBool : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((bool*)Param->Value) ); break; case dtUnsigned16 : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int16_t*)Param->Value) ); break; case dtUnsigned32_HL : case dtUnsigned32_LH : sprintf( EventMsg, "%s: %u\n", Param->DataPath, *((u_int32_t*)Param->Value) ); break; case dtSigned16 : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int16_t*)Param->Value) ); break; case dtSigned32_HL : case dtSigned32_LH : sprintf( EventMsg, "%s: %d\n", Param->DataPath, *((int32_t*)Param->Value) ); break; case dtFloat32_L : case dtFloat32_B : sprintf( EventMsg, "%s: %f\n", Param->DataPath, *((float*)Param->Value) ); break; case dtString : sprintf( EventMsg, "%s: %s\n", Param->DataPath, (char*)Param->Value ); break; default : sprintf( EventMsg, "%s:\n", Param->DataPath ); break; } } // Send event Output( Param->EventChannel, NULL, true, EventMsg, strlen(EventMsg) ); // Reset timer if (Param->EventInterval) { SetStartTime( &(Param->EventTimeout) ); } } return true; } //---------------------------------------------------------------------------