SILECS C++ Code Snippets

- General -

Specific Init

In order to make the generated silecs-code work, you need to initialize it in the specifc-init of your class (usually in RealTime/ RTDeviceClass.cpp)

// Repalce "MyClass" with the name of your class

// include the silecs header
#include <MyClass/Common/MyClass.h>
...
RTDeviceClass::~RTDeviceClass()
{
   MyClass::cleanup();
}

void RTDeviceClass::specificInit()
{
   MyClass::setup(this->MyClassServiceLocator_);
}

- Access of PLC-blocks -

Working with READ-ONLY blocks

Best read the PLC-values periodically in the RT-Action:
// include the silecs header
#include <MyClass/Common/MyClass.h>
...
// Repalce "MyClass" with the name of your class
// Repalce "MyBlock" with the name of the block you want to read
std::vector<Device*> devCol = this->MyClassServiceLocator_->getDeviceCollection();
std::vector<Device*>::iterator device;
for(device=devCol.begin();device!=devCol.end();++device)
{
   MyClass::MyBlock.getOneDevice((*device),true,pEvt->getMultiplexingContext());
}

If the Block is connected to a FESA-Property, you can read the PLC value in the FESA Get-Server-Action of that Property instead. In order to do so, set the FESA field-attribute "shared" to "false". Please note that in this case, the FESA-field will not be available on the FESA RT-side.

<field name="myRegister" multiplexed="false" persistent="false" shared="false">
   <scalar type="int16_t" />
</field>
#include <MyClass/Common/MyClass.h>
...
void getMyBlock::execute(fesa::RequestEvent* pEvt, Device* pDev, myBlockPropertyData& data)
{
    MyClass::MyBlock.getOneDevice(pDev,true,pEvt->getMultiplexingContext());
}

Working with WRITE-ONLY blocks

TODO: Actually a WRITE-ONLY block should generate a FESA-command property ... currently a setting property is generated: See bugzilla bug

So currently, if the Silecs-block is connected to a FESA property, best change the type of the property to "command-property", or create a fresh command-property and copy the needed value-items to there. If preferred you instead can throw an exception when the Get-Server-Action is triggered.

The plc-value of WRITE-ONLY blocks can be written for all devices in a FESA RT-Action:
// include the silecs header
#include <MyClass/Common/MyClass.h>
...
// Repalce "MyClass" with the name of your class
// Repalce "MyBlock" with the name of the block you want to write
std::vector<Device*> devCol = this->MyClassServiceLocator_->getDeviceCollection();
std::vector<Device*>::iterator device;
for(device=devCol.begin();device!=devCol.end();++device)
{
   MyClass::MyBlock.setOneDevice((*device),true,pEvt->getMultiplexingContext());
}

Or for a specific device in a Set-Server-Action:
#include <MyClass/Common/MyClass.h>
...
void setMyBlock::execute(fesa::RequestEvent* pEvt, Device* pDev, myBlockPropertyData& data)
{
    pDev->myRegister.set(data.getMyRegisterSet(),pEvt->getMultiplexingContext()); // first update the FESA-field with the incoming values
    MyClass::MyBlock.setOneDevice(pDev,true,pEvt->getMultiplexingContext());
}

For WRITE-ONLY fields there should be no need to set the field-attribute "shared" to false.

Working with READ-WRITE blocks

In order to use the different Silecs-Methods, you currently need to add the attribute @data-consistent=false to each FESA-field which refers to a RW-register. Caution: Only use this attribute together with @shared=false in order to dont have the risk of concurrent access. On the server-side, use custom-server-actions in order to get/set the PLC-register.

For reading a READ-WRITE block, please refer to the the documentation of READ-ONLY blocks

For writing a READ-WRITE block, please refer to the the documentation of WRITE-ONLY blocks

Reading out the current PLC run-state

//currently it is required to decode the returned status-integer by hand. For Siemens PLC's the following codes are used by step7:
#define S7CpuStatusUnknown  0x00
#define S7CpuStatusRun      0x08
#define S7CpuStatusStop     0x04

....

// Repalce "MyClass" with the name of your class
std::vector<Device*> devCol = this->MyClassServiceLocator_->getDeviceCollection();
std::vector<Device*>::iterator device;
for(device=devCol.begin();device!=devCol.end();++device)
{
   Silecs::Cluster* cluster = SIS100InjKicker::theCluster();
   Silecs::PLC* pPLC = cluster->getPLC((*deviceMaster)->plcHostName.get(),(*deviceMaster)->parameterFile.get());
   Silecs::UnitStatusType statusStruct;
   pPLC->recvUnitStatus(statusStruct); // will throw exception on fail
   switch (statusStruct.status)
   {
      case S7CpuStatusRun : std::cout << "PLC Status is:  RUN" << std::endl; break;
      case S7CpuStatusStop: std::cout << "PLC Status is:  STOP" << std::endl; break;
      default             : std::cout << "PLC Status is:  UNKNOWN" << std::endl); break;
   }
}

Reading out global plc information

Like the PLC run-state, as well the other plc parameters can be obtained. Here the available methods on plc level:
...
Silecs::UnitCodeType unitCodeStruct;
int ret = pPLC->recvUnitCode(unitCodeStruct);

Silecs::CPUInfoType cpuInfoStruct;
int ret = pPLC->recvCPUInfo(cpuInfoStruct);

Silecs::CPInfoType cpInfoStruct;
int ret = pPLC->recvCPInfo(cpInfoStruct);

...

for a full List of all available actions on plc-level, check: https://sourceforge.net/p/silecs/git/ci/gsi/tree/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h

Get a specific PLC-register

The silecs internal class "SilecsRegister" provides many options which can be used. Here just one example.

To see all provided methods, check: https://sourceforge.net/p/silecs/git/ci/gsi/tree/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h
// Repalce "MyClass" with the name of your class
// Replace "MyClass" with the name of your class
// Replace "myRegisterName" with the name of your register
// Replace "MySettingBlock" with the name of your block
for(device=devCol.begin();device!=devCol.end();++device)
{
   Silecs::PLC* pPLC = cluster->getPLC((*deviceMaster)->plcHostName.get(),(*deviceMaster)->parameterFile.get());
   Silecs::Device* plcDevice = pPLC->getDevice((*deviceMaster)->plcDeviceLabel.get());
   Silecs::Register* plcRegister = plcDevice->getRegister("myRegisterName");

   // BYTE values internally are stored as uchar ... check the conversion List on SilecsRegister.h to see what is the correct data-type to use here
   plcDevice->recv("MySettingBlock");//update local block-data
   int value = (int)plcRegister->getValUChar();
   std::cout << " old value: " << (int)value << std::endl;
   plcRegister->setValUChar((unsigned char)(value + 1)); // set new value in silecs
   plcDevice->send("MySettingBlock");//send data to PLC for a specific block
   plcDevice->recv("MySettingBlock");//update data from PLC for a specific block
   std::cout << " new value: " << (int)plcRegister->getValUChar() << std::endl;
   //oder auch:
   plcRegister->printVal();
}
Topic revision: r8 - 23 May 2017, AlexanderSchwinn
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback