From 98ce9856efefa250bfccce9bbbaaee46ab9335a4 Mon Sep 17 00:00:00 2001 From: "m.marn" <matic.marn@cosylab.com> Date: Wed, 27 Sep 2023 07:52:22 +0200 Subject: [PATCH] Refactor lower level classes. From PLC down without changing the interfaces too much. --- .../src/silecs-cli-client/main.cpp | 19 +- .../src/xml/fesa/fesa_3_0_0/fesaTemplates.py | 33 +- .../xml/test/generated_correct/AllTypes.cpp | 232 +++--- .../src/xml/test/generated_correct/AllTypes.h | 1 + .../interface/communication/MBConnection.cpp | 4 +- .../communication/SNAP7Connection.cpp | 2 +- .../communication/SilecsConnection.h | 3 +- .../interface/core/Context.cpp | 34 - .../interface/core/Context.h | 64 -- .../interface/core/SilecsService.h | 4 +- .../interface/equipment/PLCBlock.cpp | 780 ++++-------------- .../interface/equipment/PLCBlock.h | 29 +- .../interface/equipment/PLCRegister.cpp | 62 +- .../interface/equipment/PLCRegister.h | 14 +- .../interface/equipment/SilecsBlock.cpp | 55 +- .../interface/equipment/SilecsBlock.h | 56 +- .../interface/equipment/SilecsCluster.cpp | 51 +- .../interface/equipment/SilecsCluster.h | 6 - .../interface/equipment/SilecsDevice.cpp | 207 ++--- .../interface/equipment/SilecsDevice.h | 113 ++- .../interface/equipment/SilecsPLC.cpp | 612 +++++++------- .../interface/equipment/SilecsPLC.h | 361 +------- .../interface/equipment/SilecsParamConfig.h | 43 + .../interface/equipment/SilecsRegister.cpp | 21 +- .../interface/equipment/SilecsRegister.h | 38 +- .../interface/utility/Definitions.h | 106 +++ .../interface/utility/StringUtilities.h | 1 - .../diagnostictoolmainview.cpp | 4 +- .../diagnostictoolmainview.h | 2 + .../src/silecs-diagnostic/silecsmodule.cpp | 10 +- .../src/silecs-diagnostic/utils.cpp | 43 +- 31 files changed, 1167 insertions(+), 1843 deletions(-) delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp delete mode 100644 silecs-communication-cpp/src/silecs-communication/interface/core/Context.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h create mode 100644 silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h diff --git a/silecs-cli-client/src/silecs-cli-client/main.cpp b/silecs-cli-client/src/silecs-cli-client/main.cpp index 7aa8763..4945c0e 100755 --- a/silecs-cli-client/src/silecs-cli-client/main.cpp +++ b/silecs-cli-client/src/silecs-cli-client/main.cpp @@ -27,6 +27,7 @@ #include <silecs-communication/interface/equipment/SilecsCluster.h> #include <silecs-communication/interface/equipment/SilecsDevice.h> #include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> const std::string startbold = "\e[1m"; const std::string endbold = "\e[0m"; @@ -256,13 +257,12 @@ void printRegister(Silecs::Device *device, Silecs::Register *reg) void printBlock(Silecs::Device *device, std::string blockName, Silecs::XMLParser ¶mParser) { device->recv(blockName); - std::vector<Silecs::Register*> regCol = device->getRegisterCollection(blockName); - std::vector<Silecs::Register*>::iterator reg; - for (reg = regCol.begin(); reg != regCol.end(); reg++) + auto& regCol = device->getRegisterCollection(blockName); + for (auto reg = regCol.begin(); reg != regCol.end(); reg++) { if (isRegisterInBlock( (*reg)->getName(), blockName, paramParser)) { - printRegister(device, *reg); + printRegister(device, (*reg).get()); } } } @@ -274,11 +274,10 @@ void printDevice(Silecs::Device *device, Silecs::XMLParser ¶mParser) for (blockName = blockNames.begin(); blockName != blockNames.end(); blockName++) { device->recv(*blockName); - std::vector<Silecs::Register*> regCol = device->getRegisterCollection(*blockName); - std::vector<Silecs::Register*>::iterator reg; - for (reg = regCol.begin(); reg != regCol.end(); reg++) + auto& regCol = device->getRegisterCollection(*blockName); + for (auto reg = regCol.begin(); reg != regCol.end(); reg++) { - printRegister(device, *reg); + printRegister(device, (*reg).get()); } } } @@ -353,7 +352,7 @@ int connectInteractive(Silecs::Service *service, Silecs::XMLParser ¶mParser) if (index == -1) break; arg_registerName = registers[index]; - reg = device->getRegister(arg_registerName); + reg = device->getRegister(arg_registerName).get(); break; } case 3: @@ -433,7 +432,7 @@ int connectNonInteractive(Silecs::Service *service, Silecs::XMLParser ¶mPars Silecs::Register *reg = NULL; if (!arg_registerName.empty()) { - reg = device->getRegister(arg_registerName); + reg = device->getRegister(arg_registerName).get(); arg_blockName = getSilecsBlockNamebyRegisterName(arg_registerName, paramParser); } diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py index 972516c..0a23fa1 100644 --- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py +++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py @@ -108,6 +108,7 @@ htop = string.Template("""/* #define ${className}_${className}_H_ #include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> #include <fesa-core/Synchronization/MultiplexingContext.h> #include <${className}/GeneratedCode/ServiceLocator.h> """) @@ -471,14 +472,14 @@ cRecv = """ if (recvNow) pPLCDevice -> recv(blockName_); cGetStringReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); pDevice->${fesaFieldName}.set(pRegister->getVal<std::string>().c_str(), pContext); } """) cGetStringArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); const std::string** stdStringArray = pRegister->getRefArray<const std::string*>(dim1); for (unsigned int i=0; i<dim1; i++) @@ -493,14 +494,14 @@ cGetScalarReg = string.Template(""" cGetArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); pDevice->${fesaFieldName}.set(pRegister->getRefArray<${regType}>(dim1), dim1, pContext); } """) cGetArray2DReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->${fesaFieldName}.set(pRegister->getRefArray2D<${regType}>(dim1, dim2), dim1, dim2, pContext); @@ -508,7 +509,7 @@ cGetArray2DReg = string.Template(""" """) cGetUnsignedArray2DReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1; uint32_t dim2; ${regType}* data = pRegister->getRefArray2D<${regType}>(dim1, dim2); @@ -519,7 +520,7 @@ cGetUnsignedArray2DReg = string.Template(""" cGetUnsignedArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1; ${regType}* data = pRegister->getRefArray<${regType}>(dim1); std::vector<${fesaType}> ${regName}(data, data + dim1); @@ -555,7 +556,7 @@ cSetStringReg = string.Template(""" cSetStringArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); std::string stdStringArray[dim1]; uint32_t fesaDim1; @@ -570,7 +571,7 @@ cSetScalarReg = string.Template(""" cSetArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<${regType}>(pDevice->${fesaFieldName}.get(fesaDim1${context}), dim1); @@ -579,7 +580,7 @@ cSetArrayReg = string.Template(""" cSetUnsignedArrayReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t fesaDim1; const ${fesaType}* ${regName} = pDevice->${fesaFieldName}.get(fesaDim1${context}); uint32_t dim1 = pRegister->getDimension1(); @@ -590,7 +591,7 @@ cSetUnsignedArrayReg = string.Template(""" cSetArray2DReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -600,7 +601,7 @@ cSetArray2DReg = string.Template(""" cSetUnsignedArray2DReg = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -616,7 +617,7 @@ cSetStringRegData = string.Template(""" cSetStringArrayRegData = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); std::string stdStringArray[dim1]; uint32_t fesaDim1; @@ -631,7 +632,7 @@ cSetScalarRegData = string.Template(""" pPLCDevice->getRegister("${regName}")->setVal<${regType}>( ${cCast}pDevice->${fesaFieldName}.get(${context}));""") cSetArrayRegData = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.is${fesaFieldName_upper}Available()) ? pRegister->setValArray<${regType}>( data.${fesaFieldName}.get(fesaDim1), dim1) : @@ -641,7 +642,7 @@ cSetArrayRegData = string.Template(""" cSetUnsignedArrayRegData = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const ${fesaType}* ${regName}; @@ -654,7 +655,7 @@ cSetUnsignedArrayRegData = string.Template(""" cSetArray2DRegData = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -665,7 +666,7 @@ cSetArray2DRegData = string.Template(""" cSetUnsignedArray2DRegData = string.Template(""" { - Silecs::Register* pRegister = pPLCDevice->getRegister("${regName}"); + auto& pRegister = pPLCDevice->getRegister("${regName}"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp index 491da01..a73c35e 100644 --- a/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp +++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.cpp @@ -213,7 +213,7 @@ namespace AllTypes pDevice->RO_uint32_fesa.set( pPLCDevice->getRegister("RO_uint32")->getVal<uint32_t>(), pContext); pDevice->RO_float32_fesa.set( pPLCDevice->getRegister("RO_float32")->getVal<float>(), pContext); { - Silecs::Register* pRegister = pPLCDevice->getRegister("RO_string"); + auto& pRegister = pPLCDevice->getRegister("RO_string"); pDevice->RO_string_fesa.set(pRegister->getVal<std::string>().c_str(), pContext); } @@ -244,7 +244,7 @@ namespace AllTypes pDevice->RW_uint32_fesa.set( pPLCDevice->getRegister("RW_uint32")->getVal<uint32_t>(), pContext); pDevice->RW_float32_fesa.set( pPLCDevice->getRegister("RW_float32")->getVal<float>(), pContext); { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW_string"); + auto& pRegister = pPLCDevice->getRegister("RW_string"); pDevice->RW_string_fesa.set(pRegister->getVal<std::string>().c_str(), pContext); } @@ -258,14 +258,14 @@ namespace AllTypes pDevice->RW_real_fesa.set( pPLCDevice->getRegister("RW_real")->getVal<float>(), pContext); pDevice->RW_dt_fesa.set( pPLCDevice->getRegister("RW_dt")->getVal<double>(), pContext); { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8"); + auto& pRegister = pPLCDevice->getRegister("RW2_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_int8.set(pRegister->getRefArray2D<int8_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint8"); uint32_t dim1; uint32_t dim2; uint8_t* data = pRegister->getRefArray2D<uint8_t>(dim1, dim2); @@ -274,14 +274,14 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16"); + auto& pRegister = pPLCDevice->getRegister("RW2_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_int16_fesa.set(pRegister->getRefArray2D<int16_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint16"); uint32_t dim1; uint32_t dim2; uint16_t* data = pRegister->getRefArray2D<uint16_t>(dim1, dim2); @@ -290,14 +290,14 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32"); + auto& pRegister = pPLCDevice->getRegister("RW2_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_int32_fesa.set(pRegister->getRefArray2D<int32_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint32"); uint32_t dim1; uint32_t dim2; uint32_t* data = pRegister->getRefArray2D<uint32_t>(dim1, dim2); @@ -306,28 +306,28 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32"); + auto& pRegister = pPLCDevice->getRegister("RW2_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_float32_fesa.set(pRegister->getRefArray2D<float>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date"); + auto& pRegister = pPLCDevice->getRegister("RW2_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_date_fesa.set(pRegister->getRefArray2D<double>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char"); + auto& pRegister = pPLCDevice->getRegister("RW2_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_char_fesa.set(pRegister->getRefArray2D<int8_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte"); + auto& pRegister = pPLCDevice->getRegister("RW2_byte"); uint32_t dim1; uint32_t dim2; uint8_t* data = pRegister->getRefArray2D<uint8_t>(dim1, dim2); @@ -336,7 +336,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word"); + auto& pRegister = pPLCDevice->getRegister("RW2_word"); uint32_t dim1; uint32_t dim2; uint16_t* data = pRegister->getRefArray2D<uint16_t>(dim1, dim2); @@ -345,7 +345,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword"); + auto& pRegister = pPLCDevice->getRegister("RW2_dword"); uint32_t dim1; uint32_t dim2; uint32_t* data = pRegister->getRefArray2D<uint32_t>(dim1, dim2); @@ -354,28 +354,28 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int"); + auto& pRegister = pPLCDevice->getRegister("RW2_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_int_fesa.set(pRegister->getRefArray2D<int16_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint"); + auto& pRegister = pPLCDevice->getRegister("RW2_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_dint_fesa.set(pRegister->getRefArray2D<int32_t>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real"); + auto& pRegister = pPLCDevice->getRegister("RW2_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_real_fesa.set(pRegister->getRefArray2D<float>(dim1, dim2), dim1, dim2, pContext); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt"); + auto& pRegister = pPLCDevice->getRegister("RW2_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); pDevice->RW2_dt_fesa.set(pRegister->getRefArray2D<double>(dim1, dim2), dim1, dim2, pContext); @@ -408,7 +408,7 @@ namespace AllTypes pPLCDevice->getRegister("RW_real")->setVal<float>( pDevice->RW_real_fesa.get(pContext)); pPLCDevice->getRegister("RW_dt")->setVal<double>( pDevice->RW_dt_fesa.get(pContext)); { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8"); + auto& pRegister = pPLCDevice->getRegister("RW2_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -416,7 +416,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -426,7 +426,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16"); + auto& pRegister = pPLCDevice->getRegister("RW2_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -434,7 +434,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -444,7 +444,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32"); + auto& pRegister = pPLCDevice->getRegister("RW2_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -452,7 +452,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -462,7 +462,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32"); + auto& pRegister = pPLCDevice->getRegister("RW2_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -470,7 +470,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date"); + auto& pRegister = pPLCDevice->getRegister("RW2_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -478,7 +478,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char"); + auto& pRegister = pPLCDevice->getRegister("RW2_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -486,7 +486,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte"); + auto& pRegister = pPLCDevice->getRegister("RW2_byte"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -496,7 +496,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word"); + auto& pRegister = pPLCDevice->getRegister("RW2_word"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -506,7 +506,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword"); + auto& pRegister = pPLCDevice->getRegister("RW2_dword"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -516,7 +516,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int"); + auto& pRegister = pPLCDevice->getRegister("RW2_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -524,7 +524,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint"); + auto& pRegister = pPLCDevice->getRegister("RW2_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -532,7 +532,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real"); + auto& pRegister = pPLCDevice->getRegister("RW2_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -540,7 +540,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt"); + auto& pRegister = pPLCDevice->getRegister("RW2_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -591,7 +591,7 @@ namespace AllTypes (data.isRW_dt_fesaAvailable()) ? pPLCDevice->getRegister("RW_dt")->setVal<double>( data.RW_dt_fesa.get()) : pPLCDevice->getRegister("RW_dt")->setVal<double>( pDevice->RW_dt_fesa.get(pContext)); { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int8"); + auto& pRegister = pPLCDevice->getRegister("RW2_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -600,7 +600,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint8"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -612,7 +612,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int16"); + auto& pRegister = pPLCDevice->getRegister("RW2_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -621,7 +621,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint16"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -633,7 +633,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int32"); + auto& pRegister = pPLCDevice->getRegister("RW2_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -642,7 +642,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_uint32"); + auto& pRegister = pPLCDevice->getRegister("RW2_uint32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -654,7 +654,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_float32"); + auto& pRegister = pPLCDevice->getRegister("RW2_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -663,7 +663,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_date"); + auto& pRegister = pPLCDevice->getRegister("RW2_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -672,7 +672,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_char"); + auto& pRegister = pPLCDevice->getRegister("RW2_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -681,7 +681,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_byte"); + auto& pRegister = pPLCDevice->getRegister("RW2_byte"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -693,7 +693,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_word"); + auto& pRegister = pPLCDevice->getRegister("RW2_word"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -705,7 +705,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dword"); + auto& pRegister = pPLCDevice->getRegister("RW2_dword"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -717,7 +717,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_int"); + auto& pRegister = pPLCDevice->getRegister("RW2_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -726,7 +726,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dint"); + auto& pRegister = pPLCDevice->getRegister("RW2_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -735,7 +735,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_real"); + auto& pRegister = pPLCDevice->getRegister("RW2_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -744,7 +744,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("RW2_dt"); + auto& pRegister = pPLCDevice->getRegister("RW2_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -763,14 +763,14 @@ namespace AllTypes Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int8"); + auto& pRegister = pPLCDevice->getRegister("WO_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int8_t>(pDevice->WO_int8.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint8"); + auto& pRegister = pPLCDevice->getRegister("WO_uint8"); uint32_t fesaDim1; const int16_t* WO_uint8 = pDevice->WO_uint8_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -779,14 +779,14 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int16"); + auto& pRegister = pPLCDevice->getRegister("WO_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int16_t>(pDevice->WO_int16_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint16"); + auto& pRegister = pPLCDevice->getRegister("WO_uint16"); uint32_t fesaDim1; const int32_t* WO_uint16 = pDevice->WO_uint16_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -795,14 +795,14 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int32"); + auto& pRegister = pPLCDevice->getRegister("WO_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int32_t>(pDevice->WO_int32_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint32"); + auto& pRegister = pPLCDevice->getRegister("WO_uint32"); uint32_t fesaDim1; const int64_t* WO_uint32 = pDevice->WO_uint32_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -811,14 +811,14 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_float32"); + auto& pRegister = pPLCDevice->getRegister("WO_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<float>(pDevice->WO_float32_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_string"); + auto& pRegister = pPLCDevice->getRegister("WO_string"); uint32_t dim1 = pRegister->getDimension1(); std::string stdStringArray[dim1]; uint32_t fesaDim1; @@ -828,21 +828,21 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_date"); + auto& pRegister = pPLCDevice->getRegister("WO_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<double>(pDevice->WO_date_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_char"); + auto& pRegister = pPLCDevice->getRegister("WO_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int8_t>(pDevice->WO_char_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_byte"); + auto& pRegister = pPLCDevice->getRegister("WO_byte"); uint32_t fesaDim1; const int16_t* WO_byte = pDevice->WO_byte_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -851,7 +851,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_word"); + auto& pRegister = pPLCDevice->getRegister("WO_word"); uint32_t fesaDim1; const int32_t* WO_word = pDevice->WO_word_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -860,7 +860,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dword"); + auto& pRegister = pPLCDevice->getRegister("WO_dword"); uint32_t fesaDim1; const int64_t* WO_dword = pDevice->WO_dword_fesa.get(fesaDim1, pContext); uint32_t dim1 = pRegister->getDimension1(); @@ -869,28 +869,28 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int"); + auto& pRegister = pPLCDevice->getRegister("WO_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int16_t>(pDevice->WO_int_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dint"); + auto& pRegister = pPLCDevice->getRegister("WO_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<int32_t>(pDevice->WO_dint_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_real"); + auto& pRegister = pPLCDevice->getRegister("WO_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<float>(pDevice->WO_real_fesa.get(fesaDim1, pContext), dim1); } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dt"); + auto& pRegister = pPLCDevice->getRegister("WO_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; pRegister->setValArray<double>(pDevice->WO_dt_fesa.get(fesaDim1, pContext), dim1); @@ -906,7 +906,7 @@ namespace AllTypes Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int8"); + auto& pRegister = pPLCDevice->getRegister("WO_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_int8Available()) ? pRegister->setValArray<int8_t>( data.WO_int8.get(fesaDim1), dim1) : @@ -914,7 +914,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint8"); + auto& pRegister = pPLCDevice->getRegister("WO_uint8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int16_t* WO_uint8; @@ -925,7 +925,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int16"); + auto& pRegister = pPLCDevice->getRegister("WO_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_int16_fesaAvailable()) ? pRegister->setValArray<int16_t>( data.WO_int16_fesa.get(fesaDim1), dim1) : @@ -933,7 +933,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint16"); + auto& pRegister = pPLCDevice->getRegister("WO_uint16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int32_t* WO_uint16; @@ -944,7 +944,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int32"); + auto& pRegister = pPLCDevice->getRegister("WO_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_int32_fesaAvailable()) ? pRegister->setValArray<int32_t>( data.WO_int32_fesa.get(fesaDim1), dim1) : @@ -952,7 +952,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_uint32"); + auto& pRegister = pPLCDevice->getRegister("WO_uint32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int64_t* WO_uint32; @@ -963,7 +963,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_float32"); + auto& pRegister = pPLCDevice->getRegister("WO_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_float32_fesaAvailable()) ? pRegister->setValArray<float>( data.WO_float32_fesa.get(fesaDim1), dim1) : @@ -971,7 +971,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_string"); + auto& pRegister = pPLCDevice->getRegister("WO_string"); uint32_t dim1 = pRegister->getDimension1(); std::string stdStringArray[dim1]; uint32_t fesaDim1; @@ -981,7 +981,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_date"); + auto& pRegister = pPLCDevice->getRegister("WO_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_date_fesaAvailable()) ? pRegister->setValArray<double>( data.WO_date_fesa.get(fesaDim1), dim1) : @@ -989,7 +989,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_char"); + auto& pRegister = pPLCDevice->getRegister("WO_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_char_fesaAvailable()) ? pRegister->setValArray<int8_t>( data.WO_char_fesa.get(fesaDim1), dim1) : @@ -997,7 +997,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_byte"); + auto& pRegister = pPLCDevice->getRegister("WO_byte"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int16_t* WO_byte; @@ -1008,7 +1008,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_word"); + auto& pRegister = pPLCDevice->getRegister("WO_word"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int32_t* WO_word; @@ -1019,7 +1019,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dword"); + auto& pRegister = pPLCDevice->getRegister("WO_dword"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; const int64_t* WO_dword; @@ -1030,7 +1030,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_int"); + auto& pRegister = pPLCDevice->getRegister("WO_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_int_fesaAvailable()) ? pRegister->setValArray<int16_t>( data.WO_int_fesa.get(fesaDim1), dim1) : @@ -1038,7 +1038,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dint"); + auto& pRegister = pPLCDevice->getRegister("WO_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_dint_fesaAvailable()) ? pRegister->setValArray<int32_t>( data.WO_dint_fesa.get(fesaDim1), dim1) : @@ -1046,7 +1046,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_real"); + auto& pRegister = pPLCDevice->getRegister("WO_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_real_fesaAvailable()) ? pRegister->setValArray<float>( data.WO_real_fesa.get(fesaDim1), dim1) : @@ -1054,7 +1054,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("WO_dt"); + auto& pRegister = pPLCDevice->getRegister("WO_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t fesaDim1; (data.isWO_dt_fesaAvailable()) ? pRegister->setValArray<double>( data.WO_dt_fesa.get(fesaDim1), dim1) : @@ -1072,7 +1072,7 @@ namespace AllTypes Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int8"); + auto& pRegister = pPLCDevice->getRegister("C_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1080,7 +1080,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint8"); + auto& pRegister = pPLCDevice->getRegister("C_uint8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1090,7 +1090,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int16"); + auto& pRegister = pPLCDevice->getRegister("C_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1098,7 +1098,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint16"); + auto& pRegister = pPLCDevice->getRegister("C_uint16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1108,7 +1108,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int32"); + auto& pRegister = pPLCDevice->getRegister("C_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1116,7 +1116,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint32"); + auto& pRegister = pPLCDevice->getRegister("C_uint32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1126,7 +1126,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_float32"); + auto& pRegister = pPLCDevice->getRegister("C_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1134,7 +1134,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_date"); + auto& pRegister = pPLCDevice->getRegister("C_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1142,7 +1142,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_char"); + auto& pRegister = pPLCDevice->getRegister("C_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1150,7 +1150,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_byte"); + auto& pRegister = pPLCDevice->getRegister("C_byte"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1160,7 +1160,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_word"); + auto& pRegister = pPLCDevice->getRegister("C_word"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1170,7 +1170,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dword"); + auto& pRegister = pPLCDevice->getRegister("C_dword"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1180,7 +1180,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int"); + auto& pRegister = pPLCDevice->getRegister("C_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1188,7 +1188,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dint"); + auto& pRegister = pPLCDevice->getRegister("C_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1196,7 +1196,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_real"); + auto& pRegister = pPLCDevice->getRegister("C_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1204,7 +1204,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dt"); + auto& pRegister = pPLCDevice->getRegister("C_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1221,7 +1221,7 @@ namespace AllTypes Silecs::Device* pPLCDevice = pPLC->getDevice(pDevice->plcDeviceLabel.get()); { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int8"); + auto& pRegister = pPLCDevice->getRegister("C_int8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1230,7 +1230,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint8"); + auto& pRegister = pPLCDevice->getRegister("C_uint8"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1242,7 +1242,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int16"); + auto& pRegister = pPLCDevice->getRegister("C_int16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1251,7 +1251,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint16"); + auto& pRegister = pPLCDevice->getRegister("C_uint16"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1263,7 +1263,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int32"); + auto& pRegister = pPLCDevice->getRegister("C_int32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1272,7 +1272,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_uint32"); + auto& pRegister = pPLCDevice->getRegister("C_uint32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1284,7 +1284,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_float32"); + auto& pRegister = pPLCDevice->getRegister("C_float32"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1293,7 +1293,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_date"); + auto& pRegister = pPLCDevice->getRegister("C_date"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1302,7 +1302,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_char"); + auto& pRegister = pPLCDevice->getRegister("C_char"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1311,7 +1311,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_byte"); + auto& pRegister = pPLCDevice->getRegister("C_byte"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1323,7 +1323,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_word"); + auto& pRegister = pPLCDevice->getRegister("C_word"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1335,7 +1335,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dword"); + auto& pRegister = pPLCDevice->getRegister("C_dword"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1347,7 +1347,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_int"); + auto& pRegister = pPLCDevice->getRegister("C_int"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1356,7 +1356,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dint"); + auto& pRegister = pPLCDevice->getRegister("C_dint"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1365,7 +1365,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_real"); + auto& pRegister = pPLCDevice->getRegister("C_real"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; @@ -1374,7 +1374,7 @@ namespace AllTypes } { - Silecs::Register* pRegister = pPLCDevice->getRegister("C_dt"); + auto& pRegister = pPLCDevice->getRegister("C_dt"); uint32_t dim1 = pRegister->getDimension1(); uint32_t dim2 = pRegister->getDimension2(); uint32_t fesaDim1,fesaDim2; diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypes.h b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h index f7dc771..a3afcef 100644 --- a/silecs-codegen/src/xml/test/generated_correct/AllTypes.h +++ b/silecs-codegen/src/xml/test/generated_correct/AllTypes.h @@ -8,6 +8,7 @@ #define AllTypes_AllTypes_H_ #include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> #include <fesa-core/Synchronization/MultiplexingContext.h> #include <AllTypes/GeneratedCode/ServiceLocator.h> diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp index 8804a66..ddc7c7f 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/MBConnection.cpp @@ -292,7 +292,7 @@ int MBConnection::readBits(long address, unsigned long offset, unsigned long siz // connection is established then acquire data // addr is a byte address, therefore we don't need to convert to a word address // However, we need to calculate the coil address from the register address - long addr = (address - thePLC_->getDIBaseAddress()) + offset; + long addr = (address - thePLC_->getParamConfig().baseDIAddr) + offset; // Coils address is a bit address, but in our case we only address the first bit of the byte // addr should me a multiple of 8 @@ -318,7 +318,7 @@ int MBConnection::writeBits(long address, unsigned long offset, unsigned long si // connection is established then send data // addr is a byte address, therefore we don't need to convert to a word address // However, we need to calculate the coil address from the register address - long addr = (address - thePLC_->getDOBaseAddress()) + offset; + long addr = (address - thePLC_->getParamConfig().baseDOAddr) + offset; // Coils address is a bit address, but in our case we only address the first bit of the byte // addr should me a multiple of 8 diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp index 9675b40..ce365d8 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SNAP7Connection.cpp @@ -53,7 +53,7 @@ bool SNAP7Connection::open() int slotsDefault[4] = {2, 3, 4, 1}; //slot scan - most common layout S7-other (S7-300, ET200S) int nbMaxSlot = ( (slotNb_ == -1) ? 4 : 1); //slots scan only the first time (slotNb_ == -1) - switch (thePLC_->getModelID()) + switch (thePLC_->getParamConfig().modelID) { case S7400: slotsScan = slotsS7400; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h index 2b33aef..da8dde6 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/communication/SilecsConnection.h @@ -16,7 +16,8 @@ Contributors: #include <mutex> -#include <silecs-communication/interface/equipment/PLCRegister.h> +#include <silecs-communication/interface/utility/Definitions.h> +#include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/TimeStamp.h> namespace Silecs diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp deleted file mode 100644 index e09e683..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#include <silecs-communication/interface/core/SilecsService.h> -#include <silecs-communication/interface/core/Context.h> -#include <silecs-communication/interface/equipment/SilecsDevice.h> -#include <silecs-communication/interface/utility/SilecsLog.h> - -namespace Silecs -{ -Context::Context(Device* pDev, bool isForSynchronization) : - pDevice_(pDev), - isForSynchro_(isForSynchronization) -{ - //LOG(ALLOC) << "Context (create) for Device: " << pDevice_->getLabel() << ", isForSynchronization: " << (isForSynchro_ ? "yes" : "no"); -} - -Context::~Context() -{ - //LOG(ALLOC) << "Context (delete) for Device: " << pDevice_->getLabel() << ", isForSynchronization: " << (isForSynchro_ ? "yes" : "no"); -} - -} // namespace - diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h b/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h deleted file mode 100644 index 2c0582f..0000000 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/Context.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright (c) 2017 European Organization for Nuclear Research (CERN). -All rights reserved. This program and the accompanying materials -are made available under the terms of the GNU Public License v3.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/gpl.html - -Contributors: - .European Organization for Nuclear Research (CERN) - initial API and implementation - .GSI Helmholtzzentrum für Schwerionenforschung (GSI) - features and bugfixes -*/ - - -#ifndef _CONTEXT_H_ -#define _CONTEXT_H_ - -namespace Silecs -{ -class Device; - -/*! - * \class Context - * \brief This class defines the context of the Silecs Transaction. - * A transaction can be done from Cluster or PLC levels for all-devices - * and from Device level for a particular device. - * A transaction can be executed by the client process (normal transaction) or - * can be executed at the Cluster set-up for retentive registers synchronization. - */ -class Context -{ -public: - Context(Device* pDev, bool isForSynchronization); - virtual ~Context(); - - inline bool isForAllDevices() - { - return pDevice_ == NULL; - } - inline bool isForOneDevice() - { - return pDevice_ != NULL; - } - inline Device* getDevice() - { - return pDevice_; - } - - inline bool isForSynchronization() - { - return isForSynchro_; - } - -private: - /// Device reference used for Device context - Device* pDevice_; - - /// true for synchronization transaction. - /// In this case only retentive registers will be updated (Master & Slave). - bool isForSynchro_; -}; - -} // namespace - -#endif // _USER_CONTEXT_H_ diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h index b82230f..f90f2f9 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h @@ -44,9 +44,7 @@ enum class AccessArea } #include <silecs-communication/interface/equipment/SilecsCluster.h> -#include <silecs-communication/interface/equipment/SilecsPLC.h> -#include <silecs-communication/interface/equipment/SilecsDevice.h> -#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <string> namespace Silecs { diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp index b76832a..c6271e1 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.cpp @@ -21,22 +21,59 @@ Contributors: #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/StringUtilities.h> #include <silecs-communication/interface/equipment/PLCBlock.h> -#include <silecs-communication/interface/core/Context.h> #include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/PLCRegister.h> namespace Silecs { -PLCBlock::PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) : - Block(thePLC, blockNode, accessType) +PLCBlock::PLCBlock(const ElementXML& blockNode, const std::vector<ElementXML>& registerNodes, AccessType accessType, long deviceInputAddress, long deviceOutputAddress, Connection& plcConnection_, const SilecsParamConfig& paramConfig) : + Block(blockNode, accessType, plcConnection_), + deviceInputAddress_(deviceInputAddress), + deviceOutputAddress_(deviceOutputAddress), + paramConfig_(paramConfig) { + for (auto registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++) + { + std::string registerName = registerIter->getAttribute("name"); + std::unique_ptr<Register> reg; + switch (paramConfig.brandID) + { + // SIEMENS PLCs use Motorola memory convention (BigEndianRegister) + case Siemens: + reg = std::unique_ptr<Register>(new S7Register(*registerIter, paramConfig)); + break; + // SCHNEIDER PLCs use Intel memory convention (LittleEndianRegister) + // RABBIT microcontrollers use Intel memory convention (LittleEndianRegister) + case Schneider: + case Digi: + reg = std::unique_ptr<Register>(new UnityRegister(*registerIter, paramConfig)); + break; + // BECKHOFF PLCs use different memory convention depending on PLC type: + // . CX model: same convention than Unity + // . BC model: special convention for 64 bits data (float, ..): swap only the two 16bits words together (no bytes swap). + case Beckhoff: + reg = std::unique_ptr<Register>(new TwinCATRegister(*registerIter, paramConfig)); + break; + default: + throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, paramConfig.brand); + + } + + AccessArea accessArea = AccessArea::Memory; + if (blockNode.hasAttribute("ioType")) // only IO-Blocks have this attribute + { + accessArea = Block::whichAccessArea(blockNode.getAttribute("ioType")); + } + + reg->setAccessArea(accessArea); + reg->setAccessType(accessType); + reg->setBlockName(blockNode.getAttribute("name")); + registers_.emplace_back(std::move(reg)); + } + // Create buffer for the block exchanges bufferSize_ = memSize_; //size of one block type (including alignements) - if (thePLC_->getProtocolModeID() == BlockMode) - { //BlockMode ==> access all devices in once - unsigned int devicesWithBlock = getPLC()->getNrDevicesWithBlock(blockNode.getAttribute("name")); - bufferSize_ *= devicesWithBlock; - } pBuffer_ = (unsigned char*)calloc(bufferSize_, sizeof(unsigned char)); } @@ -48,712 +85,203 @@ PLCBlock::~PLCBlock() pBuffer_ = NULL; } -int PLCBlock::recvBlockMode(Context* context) +int PLCBlock::recvBlockMode() { - timeval tod; //Time-of-day for register time-stamping - int errorCode = 0; - - Connection* pConn = thePLC_->getConnection(); - AccessArea area = accessArea_; + unsigned long usedAddress = address_; + unsigned long usedSize = memSize_; + unsigned long usedDeviceOffset = deviceInputAddress_ * usedSize; - try + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) { - //if transaction is for one device only, context contains its reference - if (context->isForOneDevice()) - { - //Device context: get block of one device only ==================================== - Device* pDev = context->getDevice(); - - //Base attributes of the device within the complete data block containing all devices. - unsigned long usedAddress = address_; - unsigned long usedSize = memSize_; - unsigned long usedDeviceOffset = pDev->getInputAddress(area) * usedSize; - unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (withCustomAttributes() == true) - { - usedAddress = customAddress_; - usedSize = customSize_; - usedDeviceOffset = customOffset_; - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << ", device: " << pDev->getLabel() << ", block: " << name_; - } - } - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (accessArea_) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Get one device-block only - pBuffer //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //Device context: Extract all the device registers from that block - pDev->importRegisters(this, pBuffer, tod, context); - - LOG_DELAY(RECV) << "done for block: " << name_; - } - //end critical section - } - else - { - //Dynamic resizing of the block is not possible in BLOCK_MODE - if (withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = thePLC_->getDeviceMap(); - - //Cluster/PLC context: get block of all devices in one go ========================= - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ BlockMode): " << name_ << ", " << deviceCol.size() << " device(s)"; - } - } + usedAddress = customAddress_; + usedSize = customSize_; + usedDeviceOffset = customOffset_; + } - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } + return readBlock(usedAddress, usedDeviceOffset, usedSize, (unsigned char*)pBuffer_); +} - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(address_, //Base address (or DBn) of the block - 0, //Get all devices from the first one - bufferSize_, //Get blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(address_, //Base address (or DBn) of the block - 0, //Get all devices from the first one - bufferSize_, //Get blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(address_, //Base address (or DBn) of the block - 0, //Get all devices from the first one - bufferSize_, //Get blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer to store the data (full buffer) - ); - break; - } - } +int PLCBlock::recvDeviceMode() +{ + unsigned long usedDeviceAddress = deviceInputAddress_; + unsigned long usedBlockAddress = address_; + unsigned long usedSize = memSize_; - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //PLC context: Extract all registers value of all devices of the PLC from that block - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - - // Only extract if this device actually contains this block, otherwise skip it. - if (!pDev->hasBlock(name_)) - { - continue; - } - unsigned long deviceOffset = pDev->getInputAddress(area) * memSize_; - unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset; - pDev->importRegisters(this, pBuffer, tod, context); - } - - LOG_DELAY(RECV) << "done for block: " << name_; - } - } - } - catch(const SilecsException& ex) + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ BlockMode) for block " << name_ << " has failed."; - return ex.getCode(); + usedDeviceAddress = customAddress_; + usedBlockAddress = customOffset_; + usedSize = customSize_; } - return 0; + return readBlock(usedDeviceAddress, usedBlockAddress, usedSize, (unsigned char*)pBuffer_); } -int PLCBlock::recvDeviceMode(Context* context) +int PLCBlock::sendBlockMode() { - timeval tod; //Time-of-day for register time-stamping - int errorCode = 0; - Connection* pConn = thePLC_->getConnection(); + unsigned long usedAddress = address_; + unsigned long usedSize = memSize_; + unsigned long usedDeviceOffset = deviceOutputAddress_ * usedSize; - try + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) { - //if transaction is for one device only, context contains its reference - if (context->isForOneDevice()) - { - //Device context: get block of one device only ==================================== - Device* pDev = context->getDevice(); - - //Set base attributes of the device blocks - unsigned long usedDeviceAddress = pDev->getInputAddress(accessArea_); - unsigned long usedBlockAddress = address_; - unsigned long usedSize = memSize_; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (withCustomAttributes() == true) - { - usedDeviceAddress = customAddress_; - usedBlockAddress = customOffset_; - usedSize = customSize_; - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; - } - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (accessArea_) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); + usedAddress = customAddress_; + usedSize = customSize_; + usedDeviceOffset = customOffset_; + } + return sendBlock(usedAddress, usedDeviceOffset, usedSize, (unsigned char*)pBuffer_); +} - //Device context: Extract all the device registers from that block - pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context); +int PLCBlock::sendDeviceMode() +{ + unsigned long usedDeviceAddress = deviceOutputAddress_; + unsigned long usedBlockAddress = address_; + unsigned long usedSize = memSize_; - LOG_DELAY(RECV) << "done for block: " << name_; - } - } - else - { - //Dynamic resizing of the block is not possible in multiple access - if (withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - //Cluster/PLC context: get block of all devices one by one ========================= - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = thePLC_->getDeviceMap(); - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - if (!pDev->hasBlock(name_)) - { - continue; - } - - if (RECV & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(RECV).getLog() << "RecvAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; - } - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - //begin critical section - std::lock_guard<std::mutex> lock(bufferMux_); - switch (accessArea_) - { - case AccessArea::Digital: - errorCode = pConn->readDIO(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->readAIO(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - } - case AccessArea::Memory: - default: - { - errorCode = pConn->readMemory(pDev->getInputAddress(accessArea_), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Get one device-block only - (unsigned char*)pBuffer_ //Buffer to store the data - ); - break; - } - } - - if (pConn->isConnected() && (errorCode == 0)) - { //Data have just been received: get time-of-day to time-stamp the registers - gettimeofday(&tod, 0); - - //PLC context: Extract all registers value of the current device of the PLC from that block - pDev->importRegisters(this, (unsigned char*)pBuffer_, tod, context); - - LOG_DELAY(RECV) << "done for block: " << name_; - } - } - } - } - catch(const SilecsException& ex) + // Overwrite device-block address, offset & size in case user wants to resize the block dynamically + if (withCustomAttributes() == true) { - LOG(ERROR) << ex.what(); - LOG(ERROR) << "RecvAction (execute/ DeviceMode) failed."; - return ex.getCode(); + usedDeviceAddress = customAddress_; + usedBlockAddress = customOffset_; + usedSize = customSize_; } - return 0; + return sendBlock(usedDeviceAddress, usedBlockAddress, usedSize, (unsigned char*)pBuffer_); } -int PLCBlock::sendBlockMode(Context* context) +int PLCBlock::readBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) { + timeval tod; //Time-of-day for register time-stamping int errorCode = 0; - Connection* pConn = thePLC_->getConnection(); try { - //if transaction is for one device only, context contains its reference - if (context->isForOneDevice()) + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!plcConnection_.doOpen()) { - //Device context: send block of one device only ==================================== - Device* pDev = context->getDevice(); - - //Base attributes of the device within the complete data block containing all devices. - unsigned long usedAddress = address_; - unsigned long usedSize = memSize_; - AccessArea area = accessArea_; - unsigned long usedDeviceOffset = pDev->getOutputAddress(area) * usedSize; - unsigned char* pBuffer = ((unsigned char*)pBuffer_) + usedDeviceOffset; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (withCustomAttributes() == true) - { - usedAddress = customAddress_; - usedSize = customSize_; - usedDeviceOffset = customOffset_; - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = plcConnection_.readDIO(address, offset, size, pBuffer); + break; + case AccessArea::Analog: { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ BlockMode): device: " << pDev->getLabel() << ", block: " << name_; - - //Device context: Export all the device registers to that block - pDev->exportRegisters(this, pBuffer, context); - } - - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(usedAddress, //Base address (or DBn) of the block - usedDeviceOffset, //Device data address within the block - usedSize, //Set one device-block only - pBuffer //Buffer which contain the data - ); - break; - } + errorCode = plcConnection_.readAIO(address, offset, size, pBuffer); + break; } - - if (SEND & Log::topics_) + case AccessArea::Memory: + default: { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << name_; - } + errorCode = plcConnection_.readMemory(address, offset, size, pBuffer); + break; } } - else - { - //Dynamic resizing of the block is not possible in BLOCK_MODE - if (withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = thePLC_->getDeviceMap(); - - //Cluster/PLC context: set block of all devices in one go =========================== - LOG(SEND) << "SendAction (execute/ BlockMode): block: " << name_ << ", " << deviceCol.size() << " device(s)"; - - //PLC context: Export all registers value of all devices of the PLC to that block - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) - { - Device* pDev = pDeviceIter->second; - AccessArea area = accessArea_; - unsigned long deviceOffset = pDev->getOutputAddress(area) * memSize_; - unsigned char* pBuffer = ((unsigned char*)pBuffer_) + deviceOffset; - pDev->exportRegisters(this, pBuffer, context); - } - } - - switch (accessArea_) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(address_, //Base address (or DBn) of the block - 0, //Set all devices from the first one - bufferSize_, //Set blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(address_, //Base address (or DBn) of the block - 0, //Set all devices from the first one - bufferSize_, //Set blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(address_, //Base address (or DBn) of the block - 0, //Set all devices from the first one - bufferSize_, //Set blocks of all devices (full buffer size) - (unsigned char*)pBuffer_ //Buffer which contain the data (full buffer) - ); - break; - } - } + if (plcConnection_.isConnected() && (errorCode == 0)) + { //Data have just been received: get time-of-day to time-stamp the registers + gettimeofday(&tod, 0); - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << name_; - } - } + importRegisters(pBuffer, tod); + + LOG_DELAY(RECV) << "done for block: " << name_; } } catch(const SilecsException& ex) { LOG(ERROR) << ex.what(); - LOG(ERROR) << "SendAction (execute/ DeviceMode) on block: " << name_ << " has failed"; + LOG(ERROR) << "RecvAction (execute) for block " << name_ << " has failed."; return ex.getCode(); } return errorCode; } -int PLCBlock::sendDeviceMode(Context* context) +int PLCBlock::sendBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer) { - Connection* pConn = thePLC_->getConnection(); int errorCode = 0; try { - //if transaction is for one device only, context contains its reference - if (context->isForOneDevice()) + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!plcConnection_.doOpen()) { - //Device context: set block of one device only ==================================== - Device* pDev = context->getDevice(); - - //Set base attributes of the device blocks - AccessArea area = accessArea_; - unsigned long usedDeviceAddress = pDev->getOutputAddress(area); - unsigned long usedBlockAddress = address_; - unsigned long usedSize = memSize_; - - // Overwrite device-block address, offset & size in case user wants to resize the block dynamically - if (withCustomAttributes() == true) - { - usedDeviceAddress = customAddress_; - usedBlockAddress = customOffset_; - usedSize = customSize_; - } - - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; - - //Device context: Export all the device registers to that block - pDev->exportRegisters(this, (unsigned char*)pBuffer_, context); - } - - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(usedDeviceAddress, //Base address (or DBn) of the device - usedBlockAddress, //Block data address within the device - usedSize, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - } - } + if (plcConnection_.isEnabled()) + { + exportRegisters(pBuffer); + } - if (SEND & Log::topics_) + switch (accessArea_) + { + case AccessArea::Digital: + errorCode = plcConnection_.writeDIO(address, offset, size, pBuffer); + break; + case AccessArea::Analog: { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << name_; - } + errorCode = plcConnection_.writeAIO(address, offset, size, pBuffer); + break; } + case AccessArea::Memory: + default: + errorCode = plcConnection_.writeMemory(address, offset, size, pBuffer); + break; } - else + + if (SEND & Log::topics_) { - //Dynamic resizing of the block is not possible in multiple access - if (withCustomAttributes() == true) - throw SilecsException(__FILE__, __LINE__, COMM_BLOCK_RESIZING_NOT_ALLOWED); - - //Cluster/PLC context: set block of all devices one by one ========================= - deviceVectorType::iterator pDeviceIter; - deviceVectorType& deviceCol = thePLC_->getDeviceMap(); - for (pDeviceIter = deviceCol.begin(); pDeviceIter != deviceCol.end(); ++pDeviceIter) + if (plcConnection_.isEnabled()) { - Device* pDev = pDeviceIter->second; - if (!pDev->hasBlock(name_)) - { - continue; - } - // Try to open the connection, if it fails. Throw an exception. On success all the - // PLC blocks will be updated this function will be called recursively within doOpen. - // Once all blocks are updated continue from here. - if (!pConn->doOpen()) - { - throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; - } - { //critical section - std::lock_guard<std::mutex> lock(bufferMux_); - if (pConn->isEnabled()) - { - LOG(SEND) << "SendAction (execute/ DeviceMode): device: " << pDev->getLabel() << ", block: " << name_; - - //PLC context: Export all registers value of the current device of the PLC to that block - pDev->exportRegisters(this, (unsigned char*)pBuffer_, context); - } - - AccessArea area = accessArea_; - switch (area) - { - case AccessArea::Digital: - errorCode = pConn->writeDIO(pDev->getOutputAddress(area), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - case AccessArea::Analog: - { - errorCode = pConn->writeAIO(pDev->getOutputAddress(area), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - } - case AccessArea::Memory: - default: - errorCode = pConn->writeMemory(pDev->getOutputAddress(area), //Base address (or DBn) of the device - address_, //Block data address within the device - memSize_, //Set one device-block only - (unsigned char*)pBuffer_ //Buffer which contain the data - ); - break; - } - } - - if (SEND & Log::topics_) - { - if (pConn->isEnabled()) - { - Log(SEND).getLogDelay() << "done for block: " << name_; - } - } + Log(SEND).getLogDelay() << "done for block: " << name_; } } } catch(const SilecsException& ex) { LOG(ERROR) << ex.what(); - LOG(ERROR) << "SendAction (execute/ DeviceMode) failed"; + LOG(ERROR) << "SendAction (execute) failed"; return ex.getCode(); } return errorCode; } -int PLCBlock::send(Context* context) +int PLCBlock::send() { if (accessType_ == AccessType::Acquisition) { throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH); } - if (thePLC_->getProtocolModeID() == BlockMode) + if (paramConfig_.protocolModeID == BlockMode) { - return sendBlockMode(context); + return sendBlockMode(); } else { - return sendDeviceMode(context); + return sendDeviceMode(); } } -int PLCBlock::receive(Context* context) +int PLCBlock::receive() { if (accessType_ == AccessType::Command) { throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH); } - if (thePLC_->getProtocolModeID() == BlockMode) + if (paramConfig_.protocolModeID == BlockMode) { - return recvBlockMode(context); + return recvBlockMode(); } else { - return recvDeviceMode(context); + return recvDeviceMode(); } } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h index ebf452b..6f4068e 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCBlock.h @@ -16,6 +16,7 @@ Contributors: #include <silecs-communication/interface/core/SilecsService.h> #include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/equipment/SilecsParamConfig.h> namespace Silecs { @@ -26,27 +27,31 @@ class PLCBlock : public Block { public: - PLCBlock(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); + PLCBlock(const ElementXML& blockNode, const std::vector<ElementXML>& registerNodes, AccessType accessType, long deviceInputAddress, long deviceOutputAddress, Connection& plcConnection, const SilecsParamConfig& paramConfig); virtual ~PLCBlock(); - int send(Context* context) override; - int receive(Context* context) override; + // TODO: Receive and send functions can be made void and exceptions instead thrown. + int send() override; + int receive() override; -protected: +private: friend class Device; - int recvBlockMode(Context* context); - int recvDeviceMode(Context* context); - int sendBlockMode(Context* context); - int sendDeviceMode(Context* context); + int recvBlockMode(); + int recvDeviceMode(); + int sendBlockMode(); + int sendDeviceMode(); + + int readBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); + int sendBlock(long address, unsigned long offset, unsigned long size, unsigned char* pBuffer); /// Send/Receive data size (size of block * nb of device) unsigned long bufferSize_; -private: - //The frame buffer update (import/export registers) and related read/write data must be done - //in a critical section (the same buffer is used to send/recv data to all devices). - std::mutex bufferMux_; + long deviceInputAddress_; + long deviceOutputAddress_; + + SilecsParamConfig paramConfig_; }; } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp index d066ad6..6e7d980 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.cpp @@ -21,48 +21,49 @@ namespace Silecs constexpr int kDtlSize = 12; -PLCRegister::PLCRegister(Device* theDevice, const ElementXML& registerNode) : - Register(theDevice, registerNode) +PLCRegister::PLCRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + Register(registerNode), + paramConfig_(paramConfig) { } PLCRegister::~PLCRegister() { } -BigEndianRegister::BigEndianRegister(Device* theDevice, const ElementXML& registerNode) : - PLCRegister(theDevice, registerNode) +BigEndianRegister::BigEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + PLCRegister(registerNode, paramConfig) { } BigEndianRegister::~BigEndianRegister() { } -LittleEndianRegister::LittleEndianRegister(Device* theDevice, const ElementXML& registerNode) : - PLCRegister(theDevice, registerNode) +LittleEndianRegister::LittleEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + PLCRegister(registerNode, paramConfig) { } LittleEndianRegister::~LittleEndianRegister() { } -S7Register::S7Register(Device* theDevice, const ElementXML& registerNode) : - BigEndianRegister(theDevice, registerNode) +S7Register::S7Register(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + BigEndianRegister(registerNode, paramConfig) { } S7Register::~S7Register() { } -UnityRegister::UnityRegister(Device* theDevice, const ElementXML& registerNode) : - LittleEndianRegister(theDevice, registerNode) +UnityRegister::UnityRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + LittleEndianRegister(registerNode, paramConfig) { } UnityRegister::~UnityRegister() { } -TwinCATRegister::TwinCATRegister(Device* theDevice, const ElementXML& registerNode) : - UnityRegister(theDevice, registerNode) +TwinCATRegister::TwinCATRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig) : + UnityRegister(registerNode, paramConfig) { } TwinCATRegister::~TwinCATRegister() @@ -93,7 +94,7 @@ uint32_t TwinCATRegister::_swapl(uint32_t l) void *pl = &l; void *pul = &ul; - if ( (getPLC()->getModelID() == BC9xxx) && (getFormat() == Silecs::Float32)) + if ( (paramConfig_.modelID == BC9xxx) && (getFormat() == Silecs::Float32)) { //Particular case for BC9020 PLC: swap only bytes together (not the words) * ((uint16_t *)pul) = _swaps(* ((uint16_t *)pl)); * ((uint16_t *)pul + 1) = _swaps(* ((uint16_t *)pl + 1)); @@ -285,6 +286,7 @@ void LittleEndianRegister::swapBytesHToN(unsigned char *data, unsigned long size // ---------------------------------------------------------------------------------------- void PLCRegister::importValue(void* pBuffer, timeval ts) { + std::lock_guard<std::mutex> lock(mutex_); //Compute the register address within the block: block-address + register-offset unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; unsigned char* pData = pDataBase; @@ -339,14 +341,14 @@ void PLCRegister::importValue(void* pBuffer, timeval ts) { for (unsigned int j = 0; j < dimension2_; j++) // works also for 1d, in this case j is always 0 and points to the element on the array { - if (getPLC()->getBrandID() == Beckhoff) + if (paramConfig_.brandID == Beckhoff) { //Beckhoff controller implement the standard EPOCH on 32bits word dtSize = sizeof(uint32_t); uint32_t *timeVal = (uint32_t *)pData; swapBytesNToH((unsigned char *)& (timeVal[0]), sizeof(uint32_t)); ((double *)pRecvValue_)[i * dimension2_ + j] = static_cast<double>(timeVal[0]); } - else if (getPLC()->getProtocolTypeID() == S7Protocol) + else if (paramConfig_.protocolTypeID == S7Protocol) { if (dtSize == kDtlSize) { @@ -359,13 +361,13 @@ void PLCRegister::importValue(void* pBuffer, timeval ts) reinterpret_cast<double *>(pRecvValue_)[i * dimension2_ + j] = IeRfcGetTime(pData); } } - else if (getPLC()->getProtocolTypeID() == MBProtocol) + else if (paramConfig_.protocolTypeID == MBProtocol) { #ifdef MODBUS_SUPPORT_ENABLED ((double *)pRecvValue_)[i*dimension2_+j] = IeMdbGetTime(pData); #endif //MODBUS_SUPPORT_ENABLED } - else if (getPLC()->getProtocolTypeID() == CNVProtocol) + else if (paramConfig_.protocolTypeID == CNVProtocol) { //TODO for NI } else @@ -383,14 +385,15 @@ void PLCRegister::importValue(void* pBuffer, timeval ts) //DATA topic makes sense with RECV one if (RECV & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); } void PLCRegister::exportValue(void* pBuffer) { + std::lock_guard<std::mutex> lock(mutex_); //DATA topic makes sense with SEND one if (SEND & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); //Compute the register address within the block: block-address + register-offset unsigned char* pData = ((unsigned char*)pBuffer) + address_; @@ -440,14 +443,14 @@ void PLCRegister::exportValue(void* pBuffer) { time_t epoch = static_cast<time_t>((double) ((double *)pSendValue_)[i]); - if (getPLC()->getBrandID() == Beckhoff) + if (paramConfig_.brandID == Beckhoff) { //Beckhoff controller implement the standard EPOCH on 32bits word dtSize = sizeof(uint32_t); uint32_t *timeVal = (uint32_t *)pData; timeVal[0] = static_cast<uint32_t>(epoch); swapBytesHToN((unsigned char *)& (timeVal[0]), sizeof(uint32_t)); } - else if (getPLC()->getProtocolTypeID() == S7Protocol) + else if (paramConfig_.protocolTypeID == S7Protocol) { if (dtSize == kDtlSize) { @@ -460,13 +463,13 @@ void PLCRegister::exportValue(void* pBuffer) IeRfcSetTime(pData, epoch); } } - else if (getPLC()->getProtocolTypeID() == MBProtocol) + else if (paramConfig_.protocolTypeID == MBProtocol) { #ifdef MODBUS_SUPPORT_ENABLED IeMdbSetTime(pData, epoch); #endif //MODBUS_SUPPORT_ENABLED } - else if (getPLC()->getProtocolTypeID() == CNVProtocol) + else if (paramConfig_.protocolTypeID == CNVProtocol) { //TODO for NI } else @@ -481,6 +484,7 @@ void PLCRegister::exportValue(void* pBuffer) void PLCRegister::copyValue() { + std::lock_guard<std::mutex> lock(mutex_); //Transfer the value of the recvBuffer to to the sendBuffer if (type_ == String) { @@ -500,6 +504,7 @@ void PLCRegister::copyValue() // S7 METHODS ------------------------------------------------------------------------------- void S7Register::importString(void* pBuffer, timeval ts) { + std::lock_guard<std::mutex> lock(mutex_); // Compute the register address within the block: block-address + register-offset unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); @@ -518,14 +523,15 @@ void S7Register::importString(void* pBuffer, timeval ts) //DATA topic makes sense with RECV one if (RECV & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); } void S7Register::exportString(void* pBuffer) { + std::lock_guard<std::mutex> lock(mutex_); //DATA topic makes sense with SEND one if (SEND & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); //Compute the register address within the block: block-address + register-offset unsigned char* pData = ((unsigned char*)pBuffer) + address_; @@ -551,6 +557,7 @@ void S7Register::exportString(void* pBuffer) // TwinCAT object inherit from the same methods than UNITY. void UnityRegister::importString(void* pBuffer, timeval ts) { + std::lock_guard<std::mutex> lock(mutex_); // Compute the register address within the block: block-address + register-offset unsigned char* pDataBase = ((unsigned char*)pBuffer) + address_; std::string** pRecvStringValue_ = static_cast<std::string**>(pRecvValue_); @@ -569,14 +576,15 @@ void UnityRegister::importString(void* pBuffer, timeval ts) //DATA topic makes sense with RECV one if (RECV & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", ts: " << getTimeStampAsString() << ", value: " << getValAsByteString(pRecvValue_, 10); } void UnityRegister::exportString(void* pBuffer) { + std::lock_guard<std::mutex> lock(mutex_); //DATA topic makes sense with SEND one if (SEND & Log::topics_) - LOG(DATA) << theDevice_->getPLC()->getName() << "/" << theDevice_->getLabel() << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); + LOG(DATA) << paramConfig_.plcName << "/" << getName() << ", len: " << getLength() << ", dim1: " << getDimension1() << ", dim2: " << getDimension2() << ", value: " << getValAsByteString(pSendValue_, 10); //Compute the register address within the block: block-address + register-offset unsigned char* pData = ((unsigned char*)pBuffer) + address_; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h index c7c7200..5521075 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/PLCRegister.h @@ -22,6 +22,7 @@ Contributors: #include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/equipment/SilecsParamConfig.h> #ifdef __x86_64__ #include <endian.h> @@ -35,7 +36,7 @@ class PLCRegister : public Register private: protected: - PLCRegister(Device* theDevice, const ElementXML& registerNode); + PLCRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~PLCRegister(); // export register extraction methods @@ -76,6 +77,7 @@ protected: virtual void swapBytesNToH(unsigned char *data, unsigned long size) = 0; virtual void swapBytesHToN(unsigned char *data, unsigned long size) = 0; + SilecsParamConfig paramConfig_; }; /*! @@ -86,7 +88,7 @@ class BigEndianRegister : public PLCRegister { public: - BigEndianRegister(Silecs::Device* theDevice, const ElementXML& registerNode); + BigEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~BigEndianRegister(); protected: @@ -103,7 +105,7 @@ class LittleEndianRegister : public PLCRegister { public: - LittleEndianRegister(Silecs::Device* theDevice, const ElementXML& registerNode); + LittleEndianRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~LittleEndianRegister(); protected: @@ -119,7 +121,7 @@ protected: class S7Register : public BigEndianRegister { public: - S7Register(Silecs::Device* theDevice, const ElementXML& registerNode); + S7Register(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~S7Register(); private: @@ -147,7 +149,7 @@ private: class UnityRegister : public LittleEndianRegister { public: - UnityRegister(Silecs::Device* theDevice, const ElementXML& registerNode); + UnityRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~UnityRegister(); private: @@ -177,7 +179,7 @@ private: class TwinCATRegister : public UnityRegister { public: - TwinCATRegister(Silecs::Device* theDevice, const ElementXML& registerNode); + TwinCATRegister(const ElementXML& registerNode, const SilecsParamConfig& paramConfig); virtual ~TwinCATRegister(); protected: diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp index 10e521c..deb4651 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.cpp @@ -24,15 +24,14 @@ Contributors: namespace Silecs { -Block::Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType) : - thePLC_(thePLC), configuration_(false) +Block::Block(const ElementXML& blockNode, AccessType accessType, Connection& plcConnection) : + plcConnection_(plcConnection), + configuration_(false) { - std::string designName = blockNode.getAttribute("name"); - + name_ = blockNode.getAttribute("name");; if(blockNode.getName() == "Configuration-Block") configuration_ = true; - name_ = designName; StringUtilities::fromString(size_, blockNode.getAttribute("size")); StringUtilities::fromString(memSize_, blockNode.getAttribute("mem-size")); StringUtilities::fromString(address_, blockNode.getAttribute("address")); @@ -134,4 +133,50 @@ void Block::resetCustomAttributes() LOG(DEBUG) << "Reset custom attributes of block: " << name_; } +void Block::importRegisters(void* pBuffer, timeval ts) +{ + for (auto& reg : registers_) + { + if (reg->getFormat() == String) + { + reg->importString(pBuffer, ts); + } + else + { + reg->importValue(pBuffer, ts); + } + } +} + +void Block::exportRegisters(void* pBuffer) +{ + for (auto& reg : registers_) + { + if (reg->getFormat() == String) + { + reg->exportString(pBuffer); + } + else + { + reg->exportValue(pBuffer); + } + } +} + +void Block::copyInToOut() +{ + for (auto& reg : registers_) + { + if (reg->isReadable() && reg->isWritable()) + { + reg->copyValue(); + } + } +} + +const std::vector<std::unique_ptr<Register>>& Block::getRegisters() const +{ + return registers_; +} + } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h index 722a74a..e9a6371 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsBlock.h @@ -16,7 +16,10 @@ Contributors: #include <silecs-communication/interface/core/SilecsAction.h> #include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> +#include <memory> namespace Silecs { class Action; @@ -33,13 +36,13 @@ class ElementXML; */ class Block { - +friend class PLC; public: - Block(PLC* thePLC, const ElementXML& blockNode, AccessType accessType); + Block(const ElementXML& blockNode, AccessType accessType, Connection& plcConnection); virtual ~Block(); - virtual int receive(Context* context) = 0; - virtual int send(Context* context) = 0; + virtual int receive() = 0; + virtual int send() = 0; /*! * \fn whichAccessType @@ -67,10 +70,6 @@ public: { return configuration_; } - PLC* getPLC() const - { - return thePLC_; - } std::string getName() const { return name_; @@ -84,6 +83,16 @@ public: return (accessArea_); } + unsigned long getMemSize() const + { + return memSize_; + } + + unsigned long getAddress() const + { + return address_; + } + /// @cond void setCustomAttributes(const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); void resetCustomAttributes(); @@ -93,10 +102,35 @@ public: } /// @endcond + /*! + * \brief Copies input buffer in output buffer + * The method copies the input buffer in the output buffer for each READ-WRITE register for the block passed as parameter + * \param blockName name of the block for which the copy must be performed + */ + void copyInToOut(); + + const std::vector<std::unique_ptr<Register>>& getRegisters() const; + protected: - /// Parent PLC reference of that device - PLC* thePLC_; + /*! + * \fn importRegisters + * \brief Extract all the concerned registers data of that device from a given block and set the registers value. + * \param pBlock: block which contain list of registers to be imported + * \param pBuffer: direct pointer on the buffer which contain the registers data + * \param ts is the time-of-day to time-stamp each register + */ + void importRegisters(void* pBuffer, timeval ts); + + /*! + * \fn exportRegisters + * \brief Export all the concerned registers value of that device to a given block. + * \param pBlock: block which contain list of registers to be exported + * \param pBuffer: direct pointer on the buffer which will contain the registers data + */ + void exportRegisters(void* pBuffer); + + Connection& plcConnection_; /// Block attributes std::string name_; @@ -130,6 +164,8 @@ protected: unsigned long address_; + std::vector<std::unique_ptr<Register>> registers_; + // Send/Receive data buffer void *pBuffer_; }; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp index 2ec9ed1..0e112b0 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.cpp @@ -97,47 +97,54 @@ bool Cluster::getAddressByHostName(const std::string hostName, std::string& IPAd return false; } -Block* Cluster::getBlock(const std::string blockName) -{ // Retrieve the block from the first PLC (same for each of them) - return plcMap_.begin()->second->getBlock(blockName); -} - std::string Cluster::getBlockList(AccessType accessType) { - std::string blockList = ""; + std::set<std::string> uniqueBlocks; //At first, check this class/version is already deployed (one PLC in the Cluster at least) - if (plcMap_.size() > 0) + if (!plcMap_.empty()) { // Retrieve the block-map from the first PLC (same for each of them) - blockVectorType blockCol = plcMap_.begin()->second->getBlockCol(); - - blockVectorType::iterator block; - for (block = blockCol.begin(); block != blockCol.end(); ++block) + auto& devices = plcMap_.begin()->second->getDevices(); + for (auto& device : devices) { - if ( (*block)->getAccessType() == accessType) + auto& blockCol = device.getBlocks(); + for (auto& block : blockCol) { - std::string blockName = (*block)->getName(); - blockList.append(blockName + " "); + if (block->getAccessType() == accessType) + { + uniqueBlocks.insert(block->getName()); + } } } } + std::string blockList = ""; + for (auto& block : uniqueBlocks) + { + blockList.append(block + " "); + } return blockList; } std::string Cluster::getBlockList() { - std::string blockList = ""; + std::set<std::string> uniqueBlocks; //At first, check this class/version is already deployed (one PLC in the Cluster at least) - if (plcMap_.size() > 0) + if (!plcMap_.empty()) { // Retrieve the block-map from the first PLC (same for each of them) - blockVectorType blockCol = plcMap_.begin()->second->getBlockCol(); - - blockVectorType::iterator block; - for (block = blockCol.begin(); block != blockCol.end(); ++block) + auto& devices = plcMap_.begin()->second->getDevices(); + for (auto& device : devices) { - std::string blockName = (*block)->getName(); - blockList.append(blockName + " "); + auto& blockCol = device.getBlocks(); + for (auto& block : blockCol) + { + uniqueBlocks.insert(block->getName()); + } } } + std::string blockList = ""; + for (auto& block : uniqueBlocks) + { + blockList.append(block + " "); + } return blockList; } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h index aa68187..f19c1e5 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h @@ -140,12 +140,6 @@ private: bool getHostNameByAddress(const std::string IPAddress, std::string& hostName); bool getAddressByHostName(const std::string hostName, std::string& IPAddress); - /*! - * \fn getBlock - * \brief returns instance of the requested block - */ - Block* getBlock(const std::string blockName); - /// Store the current FEC name std::string hostName_; diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp index d324d6d..e1fa081 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.cpp @@ -13,7 +13,6 @@ Contributors: #include <silecs-communication/interface/equipment/SilecsDevice.h> -#include <silecs-communication/interface/core/Context.h> #include <silecs-communication/interface/core/SilecsService.h> #include <silecs-communication/interface/equipment/SilecsBlock.h> #include <silecs-communication/interface/equipment/SilecsCluster.h> @@ -23,6 +22,7 @@ Contributors: #include <silecs-communication/interface/utility/SilecsException.h> #include <silecs-communication/interface/utility/SilecsLog.h> #include <silecs-communication/interface/utility/XMLParser.h> +#include <silecs-communication/interface/equipment/PLCBlock.h> #include <silecs-communication/interface/equipment/CNVRegister.h> @@ -30,27 +30,17 @@ Contributors: namespace Silecs { -Device::Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes) : - thePLC_(thePLC) +Device::Device(const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes, Connection& plcConnection, const SilecsParamConfig& paramConfig) : + paramConfig_(paramConfig) { // Update Device ElementXML attributes label_ = deviceNode.getAttribute("label"); StringUtilities::fromString(address_, deviceNode.getAttribute("address")); - //For backward compatibility (IO addresses are not defined in Silecs version <1.4.0) - //Undefined address = -1 by default. - ai_address_ = -1; - ao_address_ = -1; - di_address_ = -1; - do_address_ = -1; - if (deviceNode.hasAttribute("AI-address")) - StringUtilities::fromString(ai_address_, deviceNode.getAttribute("AI-address")); - if (deviceNode.hasAttribute("AO-address")) - StringUtilities::fromString(ao_address_, deviceNode.getAttribute("AO-address")); - if (deviceNode.hasAttribute("DI-address")) - StringUtilities::fromString(di_address_, deviceNode.getAttribute("DI-address")); - if (deviceNode.hasAttribute("DO-address")) - StringUtilities::fromString(do_address_, deviceNode.getAttribute("DO-address")); + StringUtilities::fromString(ai_address_, deviceNode.getAttribute("AI-address")); + StringUtilities::fromString(ao_address_, deviceNode.getAttribute("AO-address")); + StringUtilities::fromString(di_address_, deviceNode.getAttribute("DI-address")); + StringUtilities::fromString(do_address_, deviceNode.getAttribute("DO-address")); LOG(ALLOC) << "Creating SilecsDevice: " << label_; @@ -63,79 +53,66 @@ Device::Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<Elem if (blockIter->hasAttribute("ioType")) // only IO-Blocks have this attribute accessArea = Block::whichAccessArea(blockIter->getAttribute("ioType")); auto& registerNodes = blockIter->getChildNodes(); - instantiateRegisters(blockName, accessType, accessArea, registerNodes); + + blocks_.emplace_back(new PLCBlock(*blockIter, registerNodes, accessType, getInputAddress(accessArea), + getOutputAddress(accessArea), plcConnection, paramConfig)); } } Device::~Device() { LOG(ALLOC) << "Device (delete): " << label_; - - // Remove the register instances related to this Device - registerVectorType::iterator pRegisterIter; - for (pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter) - delete pRegisterIter->second; - registerCol_.clear(); - - // Register instances have been deleted before, just clear the block-register Map. - blockRegisterMap_.clear(); } -PLC* Device::getPLC() const +const std::vector<std::unique_ptr<Block>>& Device::getBlocks() const { - return thePLC_; + return blocks_; } -Register* Device::getRegister(const std::string& registerName) const +const std::unique_ptr<Register>& Device::getRegister(const std::string& registerName) const { - for (auto iter = registerCol_.begin(); iter != registerCol_.end(); ++iter) + for (auto& block : blocks_) { - if (iter->first == registerName) + for (auto& reg : block->getRegisters()) { - return iter->second; + if (reg->getName() == registerName) + { + return reg; + } } } throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_REGISTER_NAME, registerName); - return NULL; // to suppress warning } -std::vector<Register*>& Device::getRegisterCollection(const std::string& blockName) +const std::vector<std::unique_ptr<Register>>& Device::getRegisterCollection(const std::string& blockName) const { - blockRegisterMapType::iterator iter = blockRegisterMap_.find(blockName); - if (iter == blockRegisterMap_.end()) + auto blockIt = std::find_if(blocks_.begin(), blocks_.end(), + [&blockName](const std::unique_ptr<Block>& block) + { + return block->getName() == blockName; + }); + if (blockIt == blocks_.end()) { throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_BLOCK_NAME, blockName); } - return iter->second; + return (*blockIt)->getRegisters(); } int Device::recv(const std::string& blockName) { //Synchronous device data receive - - //Context of the transaction: - //this = the device to be treated, - //false = is not for registers synchronization (normal transaction) - Context context(this, false); - //Execute the receive action for the required device (from the current thread) - return getBlock(blockName)->receive(&context); + return getBlock(blockName)->receive(); } int Device::send(const std::string& blockName) { //Synchronous device data send - - //Context of the transaction: - //this = the device to be treated, - //false = is not for registers synchronization (normal transaction) - Context context(this, false); - //Execute the receive action for the required device (from the current thread) - return getBlock(blockName)->send(&context); + return getBlock(blockName)->send(); } -std::string Device::getLabel() const +const std::string& Device::getLabel() const { return label_; } @@ -143,126 +120,44 @@ std::string Device::getLabel() const std::string Device::getRegisterList() const { std::string registerList = ""; - for (auto pRegisterIter = registerCol_.begin(); pRegisterIter != registerCol_.end(); ++pRegisterIter) + for (auto& block : blocks_) { - if (!registerList.empty()) - registerList.append(" "); - registerList.append(pRegisterIter->second->getName()); + for (auto& reg : block->getRegisters()) + { + if (!registerList.empty()) + { + registerList.append(" "); + } + registerList.append(reg->getName()); + } } return registerList; } -Register* Device::instantiateRegister(const ElementXML& registerNode) -{ - switch (getPLC()->getBrandID()) - { - // SIEMENS PLCs use Motorola memory convention (BigEndianRegister) - case Siemens: - return new S7Register(this, registerNode); - - // SCHNEIDER PLCs use Intel memory convention (LittleEndianRegister) - // RABBIT microcontrollers use Intel memory convention (LittleEndianRegister) - case Schneider: - case Digi: - return new UnityRegister(this, registerNode); - - // BECKHOFF PLCs use different memory convention depending on PLC type: - // . CX model: same convention than Unity - // . BC model: special convention for 64 bits data (float, ..): swap only the two 16bits words together (no bytes swap). - case Beckhoff: - return new TwinCATRegister(this, registerNode); - -#ifdef NI_SUPPORT_ENABLED - //NI Shared variables use specific convention - case Ni: - return new CNVRegister(this, registerNode); -#endif - - default: - throw SilecsException(__FILE__, __LINE__, DATA_UNKNOWN_PLC_MANUFACTURER, getPLC()->getBrand()); - - } //switch -} - -void Device::instantiateRegisters(const std::string& blockName, AccessType accessType, AccessArea accessArea, const std::vector<ElementXML>& registerNodes) +const std::unique_ptr<Block>& Device::getBlock(const std::string& blockName) { - std::vector<Register*> registerCol; - - //LOG(SETUP) << "Ordering registers for block: " << blockName << " on Device: " << getLabel(); - - for (auto registerIter = registerNodes.begin(); registerIter != registerNodes.end(); registerIter++) + auto blockIt = std::find_if(blocks_.begin(), blocks_.end(), + [&blockName](const std::unique_ptr<Block>& block) { - std::string registerName = registerIter->getAttribute("name"); - Register* pReg = instantiateRegister(*registerIter); - pReg->setAccessArea(accessArea); - pReg->setAccessType(accessType); - pReg->setBlockName(blockName); - registerCol.push_back(pReg); - registerCol_.push_back(std::make_pair(registerName, pReg)); - } - blockRegisterMap_.insert(std::make_pair(blockName, registerCol)); -} - -Block* Device::getBlock(const std::string& blockName) -{ - if (!hasBlock(blockName)) + return block->getName() == blockName; + }); + if (blockIt == blocks_.end()) { std::ostringstream errorMessage; errorMessage << "Block not found! The block '" << blockName << "' does not exist on the device '" << label_ << "'."; throw SilecsException(__FILE__, __LINE__, errorMessage.str()); } - return thePLC_->getBlock(blockName); + return *blockIt; } bool Device::hasBlock(const std::string& blockName) { - blockRegisterMapType::iterator iter; - iter = blockRegisterMap_.find(blockName); - return (iter != blockRegisterMap_.end()); -} - -void Device::importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext) -{ - std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName()); - std::vector<Register*>::iterator pReg; - for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++) - { - if (!pContext->isForSynchronization()) - { - if ( (*pReg)->getFormat() == String) - (*pReg)->importString(pBuffer, ts); - else - (*pReg)->importValue(pBuffer, ts); - } - } -} - -void Device::exportRegisters(Block* pBlock, void* pBuffer, Context* pContext) -{ - std::vector<Register*>& registerCol = getRegisterCollection(pBlock->getName()); - std::vector<Register*>::iterator pReg; - for (pReg = registerCol.begin(); pReg < registerCol.end(); pReg++) + auto blockIt = std::find_if(blocks_.begin(), blocks_.end(), + [&blockName](const std::unique_ptr<Block>& block) { - if (!pContext->isForSynchronization()) - { - if ( (*pReg)->getFormat() == String) - (*pReg)->exportString(pBuffer); - else - (*pReg)->exportValue(pBuffer); - } - } -} - -void Device::copyInToOut(const std::string& blockName) -{ - std::vector<Register*>& registerCol = getRegisterCollection(blockName); - for (unsigned int i = 0; i < registerCol.size(); i++) - { - Register* pReg = registerCol[i]; - if (pReg->isReadable() && pReg->isWritable()) - pReg->copyValue(); - } - + return block->getName() == blockName; + }); + return blockIt != blocks_.end(); } } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h index 2eb7916..4610506 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsDevice.h @@ -15,15 +15,19 @@ Contributors: #define _SILECS_DEVICE_H_ #include <silecs-communication/interface/core/SilecsService.h> +#include <silecs-communication/interface/equipment/SilecsBlock.h> +#include <silecs-communication/interface/communication/SilecsConnection.h> +#include <silecs-communication/interface/equipment/SilecsParamConfig.h> #include <string> #include <vector> #include <map> +#include <memory> +#include <iostream> namespace Silecs { class PLC; -class Block; class ElementXML; class Register; class Context; @@ -43,12 +47,6 @@ class Device { public: - /*! - * \brief Returns reference of the PLC where the device is instantiated - * \return Reference of the PLC object - */ - PLC* getPLC() const; - /*! * \brief Returns the label of the device as defined in the Deployment document. * A device label is not visible from the supervision. It's the device identifier within @@ -56,14 +54,14 @@ public: * corresponding index [1..n] in the device collection. * \return label or index of the device as string */ - std::string getLabel() const; + const std::string& getLabel() const; /*! * \brief Returns one register instance of the device by its name * \param registerName name of the register * \return Reference of the register object */ - Register* getRegister(const std::string& registerName) const; + const std::unique_ptr<Register>& getRegister(const std::string& registerName) const; /*! * \brief Acquires one particular registers block of the device. @@ -88,13 +86,13 @@ public: * The method copies the input buffer in the output buffer for each READ-WRITE register for the block passed as parameter * \param blockName name of the block for which the copy must be performed */ - void copyInToOut(const std::string& blockName); + // void copyInToOut(const std::string& blockName); /// @cond /*! * \return all registers of the device for a given block */ - std::vector<Register*>& getRegisterCollection(const std::string& blockName); + const std::vector<std::unique_ptr<Register>>& getRegisterCollection(const std::string& blockName) const; /*! * \return String list (space separated value) of the Device registers @@ -102,73 +100,71 @@ public: std::string getRegisterList() const; /// @endcond -private: - // export device attributes to the Actions - friend class PLC; - friend class Register; - friend class PLCRegister; - friend class PLCBlock; - friend class Context; + Device(const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes, Connection& plcConnection, const SilecsParamConfig& paramConfig); + ~Device(); + + Device(Device&& other) : + label_(std::move(other.label_)), + address_(other.address_), + ai_address_(other.ai_address_), + ao_address_(other.ao_address_), + di_address_(other.di_address_), + do_address_(other.do_address_), + blocks_(std::move(other.blocks_)) + { + address_ = -1; + ai_address_ = -1; + ao_address_ = -1; + di_address_ = -1; + do_address_ = -1; + }; - friend class CNVRegister; - friend class CNVRecvBlockMode; - friend class CNVRecvDeviceMode; - friend class CNVSendBlockMode; - friend class CNVSendDeviceMode; + const std::vector<std::unique_ptr<Block>>& getBlocks() const; - Device(PLC* thePLC, const ElementXML& deviceNode, const std::vector<ElementXML>& blockNodes); - virtual ~Device(); + /*! + * \fn getBlock + * \brief returns one instance of the requested block checking its access-type + */ + const std::unique_ptr<Block>& getBlock(const std::string& blockName); - inline long& getInputAddress(AccessArea area) + long getInputAddress(AccessArea area) { if (area == AccessArea::Digital) + { return di_address_; + } else if (area == AccessArea::Analog) + { return ai_address_; + } return address_; } - inline long& getOutputAddress(AccessArea area) + long getOutputAddress(AccessArea area) { if (area == AccessArea::Digital) + { return do_address_; + } else if (area == AccessArea::Analog) + { return ao_address_; + } return address_; } - Register* instantiateRegister(const ElementXML& registerNode); - - void instantiateRegisters(const std::string& blockName, AccessType accessType, AccessArea accessArea, const std::vector<ElementXML>& registerNodes); +private: + // export device attributes to the Actions + friend class PLC; - /*! - * \fn getBlock - * \brief returns one instance of the requested block checking its access-type - */ - Block* getBlock(const std::string& blockName); + friend class CNVRegister; + friend class CNVRecvBlockMode; + friend class CNVRecvDeviceMode; + friend class CNVSendBlockMode; + friend class CNVSendDeviceMode; bool hasBlock(const std::string& blockName); - /*! - * \fn importRegisters - * \brief Extract all the concerned registers data of that device from a given block and set the registers value. - * \param pBlock: block which contain list of registers to be imported - * \param pBuffer: direct pointer on the buffer which contain the registers data - * \param ts is the time-of-day to time-stamp each register - */ - void importRegisters(Block* pBlock, void* pBuffer, timeval ts, Context* pContext); - - /*! - * \fn exportRegisters - * \brief Export all the concerned registers value of that device to a given block. - * \param pBlock: block which contain list of registers to be exported - * \param pBuffer: direct pointer on the buffer which will contain the registers data - */ - void exportRegisters(Block* pBlock, void* pBuffer, Context* pContext); - - /// Parent PLC reference of that device - PLC* thePLC_; - /// Device attributes std::string label_; long address_; @@ -177,12 +173,9 @@ private: long di_address_; long do_address_; - /// Register collection of that device - registerVectorType registerCol_; - - /// Collections of the device registers by block - blockRegisterMapType blockRegisterMap_; + SilecsParamConfig paramConfig_; + std::vector<std::unique_ptr<Block>> blocks_; }; } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp index 69ef6e6..25c63a0 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp @@ -44,6 +44,7 @@ PLC::PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::s //Force PLC hostname lower-case name_ = plcName; StringUtilities::toLower(name_); + paramConfig_.plcName = name_; LOG(ALLOC) << "PLC (create): " << name_ << "/ " << IPaddr_; @@ -53,12 +54,10 @@ PLC::PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::s // Upload the parameters file and build the PLC configuration extractDatabase(); - // create default contexts for all-devices transaction (normal and for synchronization) - allDevicesTransaction_ = new Context(NULL/*no Device: for all devices)*/, false); - allDevicesSynchronization_ = new Context(NULL/*no Device: for all devices)*/, true); - // Instantiate the communication interface - plcConn_ = NULL; + createConnection(); + + createDevices(); } PLC::~PLC() @@ -67,39 +66,12 @@ PLC::~PLC() //Before removing the PLC resources, we need to interrupt all the related accesses (if connection is not shared) disconnect(); - - // Remove PLC communication resources - if (plcConn_ != NULL) - { - delete plcConn_; - plcConn_ = NULL; - } - - //theHeader object must not be delete from the PLC since it is shared between all the PLC - //instances. It will be removed by the Service destructor at the end. - - delete allDevicesTransaction_; - delete allDevicesSynchronization_; - - // Remove the Device instances related to this PLC - deviceVectorType::iterator pDeviceIter; - for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) - delete pDeviceIter->second; - deviceCol_.clear(); - - // Remove the Block instances related to this PLC - blockVectorType::iterator pBlockIter; - for (pBlockIter = blockCol_.begin(); pBlockIter != blockCol_.end(); ++pBlockIter) - { - delete *pBlockIter; - } } void PLC::connect(bool connectNow, bool compareChecksums) { //At first, Instantiate the PLC connection object if needed LOG((COMM|DIAG)) << "Attempt to establish connection ... "; - /*plcConn_ =*/getConnection(); //Check PLC is not already Enabled std::string connStr = name_ + "(" + IPaddr_ + ")" + ":" + theCluster_->getClassName() + "/v" + theCluster_->getClassVersion(); LOG(COMM) << connStr; @@ -113,58 +85,69 @@ void PLC::connect(bool connectNow, bool compareChecksums) LOG(COMM) << (connectNow ? "Open" : "Enable") << " Connection request for " << connStr; - if (getTypeID() == BusCoupler) + if (paramConfig_.typeID == BusCoupler) { //This is an Ethernet coupler (pure RIO) => immediate connection without SilecsHeader check plcConn_->enable(connectNow); return; } // Whatever the outcome of the connection that will follow, the PLC must be Enabled in any case. - // Thus, even if the PLC is off and rejects the first connection to upload the Header (see updateHeader), + // Thus, even if the PLC is off and rejects the first connection to upload the Header, // we will automatically attempt to reconnect later at the next PLC accesses (send/recv) ... again and again. plcConn_->enable(connectNow); - if (getTypeID() != BusCoupler && compareChecksums) + auto headerIt = std::find_if(devices_.begin(), devices_.end(), + [](const Device& dev) + { + return dev.getLabel() == "SilecsHeader"; + }); + + if (paramConfig_.typeID != BusCoupler && compareChecksums) { /* PLC memory could have change during a disconnection time (downloading or other). The Header registers must be reloaded for consistency checking. Do not continue the connection sequence if it is not even possible to load the header. */ LOG(COMM) << "getting checksum"; - remoteChecksum_ = theHeader_->getRegister("_checksum")->getVal<std::uint32_t>(); - if (remoteChecksum_ != localChecksum_) + if (headerIt == devices_.end()) + { + throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR, "Missing SilecsHeader."); + } + + remoteChecksum_ = headerIt->getRegister("_checksum")->getVal<std::uint32_t>(); + if (remoteChecksum_ != paramConfig_.localChecksum) { //Client and PLC mapping are not consistent ... no transaction are possible! disconnect(); std::ostringstream message; - message << "Checksum comparison failed. Checksum in parameter file: '" << localChecksum_ << "' Checksum in PLC: '" << remoteChecksum_ << "' Disconnecting PLC now."; + message << "Checksum comparison failed. Checksum in parameter file: '" << paramConfig_.localChecksum << "' Checksum in PLC: '" << remoteChecksum_ << "' Disconnecting PLC now."; throw SilecsException(__FILE__, __LINE__, CONFIG_CLIENT_PLC_NOT_CONSISTENT, message.str()); } } //Warn ACET service that a new connection is established (except for SilecsHeader) - if (theHeader_ != NULL) + if (headerIt == devices_.end()) { - TRACE("info") << "Connection setup: ClassName=" << theCluster_->getClassName() << ", " << "ClassVersion=" << theCluster_->getClassVersion() << ", " << "Owner=" << localOwner_ << ", " << "GenerationRelease=" << localRelease_ << ", " << "GenerationDate=" << localDate_ << ", " << "PlcChecksum=" << localChecksum_ << ", " << "PlcDomain=" << domain_ << ", " << "PlcHostname=" << name_ << ", " << "PlcBrand=" << brand_ << ", " << "PlcSystem=" << system_ << ", " << "PlcModel=" << model_ << ", " << "ProtocolAddress=" << baseMemAddr_ << ", " << "ProtocolMode=" << protocolMode_ << ", " << "InstanceNumber=" << deviceCol_.size(); + return; } + + TRACE("info") << "Connection setup: ClassName=" << theCluster_->getClassName() << ", " << "ClassVersion=" << theCluster_->getClassVersion() << ", " << "Owner=" << paramConfig_.localOwner << ", " << "GenerationRelease=" << paramConfig_.localRelease << ", " << "GenerationDate=" << paramConfig_.localDate << ", " << "PlcChecksum=" << paramConfig_.localChecksum << ", " << "PlcDomain=" << paramConfig_.domain << ", " << "PlcHostname=" << name_ << ", " << "PlcBrand=" << paramConfig_.brand << ", " << "PlcSystem=" << paramConfig_.system << ", " << "PlcModel=" << paramConfig_.model << ", " << "ProtocolAddress=" << paramConfig_.baseMemAddr << ", " << "ProtocolMode=" << paramConfig_.protocolMode << ", " << "InstanceNumber=" << devices_.size(); } -; void PLC::disconnect() { if (DEBUG & Log::topics_) LOG(COMM) << "Disconnection request for " << name_ << ":" << theCluster_->getClassName() << "/v" << theCluster_->getClassVersion(); - //close the connection (also close the connection if shared with other cluster on the same PLC!) - getConnection()->disable(); + //close the connection + plcConn_->disable(); } -; bool PLC::isEnabled() { - return ( (plcConn_ == NULL) ? false : plcConn_->isEnabled()); /*do not use getConnection() here*/ + return plcConn_->isEnabled(); } bool PLC::isConnected(bool connectNow) { - return (connectNow ? getConnection()->doOpen() : getConnection()->isConnected()); + return (connectNow ? plcConn_->doOpen() : plcConn_->isConnected()); } std::string PLC::getParamsFileName() const @@ -175,11 +158,9 @@ std::string PLC::getParamsFileName() const unsigned int PLC::getNrDevicesWithBlock(const std::string& blockName) { unsigned int devicesWithBlock = 0; - deviceVectorType::iterator pDeviceIter; - for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + for (auto& device : devices_) { - Device* pDev = pDeviceIter->second; - if (pDev->hasBlock(blockName)) + if (device.hasBlock(blockName)) { devicesWithBlock++; } @@ -197,31 +178,25 @@ const Cluster& PLC::getCluster() const return *theCluster_; } -bool PLC::hasHeader() const -{ - return theHeader_ != nullptr; -} - -Device* PLC::getDevice(const std::string& deviceName) const +Device* PLC::getDevice(const std::string& deviceName) { - for (auto iter = deviceCol_.begin(); iter != deviceCol_.end(); ++iter) + for (auto& device : devices_) { - if (iter->first == deviceName) + if (device.getLabel() == deviceName) { - return iter->second; + return &device; } } throw SilecsException(__FILE__, __LINE__, PARAM_UNKNOWN_DEVICE_NAME, deviceName + "/" + name_); - return NULL; //to suppress warning } std::vector<std::string> PLC::getDeviceList() const { std::vector<std::string> deviceList; - for (auto pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + for (auto& device : devices_) { - deviceList.push_back(pDeviceIter->first); + deviceList.push_back(device.getLabel()); } return deviceList; } @@ -234,100 +209,22 @@ std::string PLC::getIPAddress() const { return IPaddr_; } -std::string PLC::getDomain() const -{ - return domain_; -} -std::string PLC::getBrand() const -{ - return brand_; -} -std::string PLC::getSystem() const -{ - return system_; -} -std::string PLC::getModel() const -{ - return model_; -} -PLCType PLC::getPLCType() const -{ - return typeID_; -} -std::string PLC::getProtocolType() const -{ - return protocolType_; -} -std::string PLC::getProtocolMode() const -{ - return protocolMode_; -} -unsigned long PLC::getBaseAddress() const -{ - return baseMemAddr_; -} - -long PLC::getMemBaseAddress() const -{ - return baseMemAddr_; -} - -long PLC::getDIBaseAddress() const -{ - return baseDIAddr_; -} - -long PLC::getDOBaseAddress() const -{ - return baseDOAddr_; -} - -long PLC::getAIBaseAddress() const -{ - return baseAIAddr_; -} - -long PLC::getAOBaseAddress() const -{ - return baseAOAddr_; -} -deviceVectorType& PLC::getDeviceMap() -{ - return deviceCol_; -} -std::string PLC::getLocalRelease() const +const SilecsParamConfig& PLC::getParamConfig() const { - return localRelease_; -} -std::string PLC::getLocalOwner() const -{ - return localOwner_; -} -std::string PLC::getLocalDate() const -{ - return localDate_; -} -unsigned long PLC::getLocalChecksum() const -{ - return localChecksum_; + return paramConfig_; } void PLC::updateLocalData() { - blockVectorType::iterator blockIter; - for (blockIter = blockCol_.begin(); blockIter != blockCol_.end(); blockIter++) + for (auto& device : devices_) { - deviceVectorType::iterator pDeviceIter; - for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) + for (auto& block : device.getBlocks()) { - if (pDeviceIter->second->hasBlock( (*blockIter)->getName())) + if (block->isReadable()) { - if ( (*blockIter)->isReadable()) - { - LOG(COMM) << "Updating block '" << (*blockIter)->getName() << "' for device '" << pDeviceIter->second->getLabel() << "'"; - pDeviceIter->second->recv( (*blockIter)->getName()); - } + LOG(COMM) << "Updating block '" << block->getName() << "' for device '" << device.getLabel() << "'"; + block->receive(); } } } @@ -335,66 +232,232 @@ void PLC::updateLocalData() int PLC::recvUnitCode(UnitCodeType& dataStruct) { - return getConnection()->readUnitCode(dataStruct); + return plcConn_->readUnitCode(dataStruct); } int PLC::recvUnitStatus(UnitStatusType& dataStruct) { - return getConnection()->readUnitStatus(dataStruct); + return plcConn_->readUnitStatus(dataStruct); } bool PLC::isRunning() { - return getConnection()->isRunning(); + return plcConn_->isRunning(); } int PLC::recvCPUInfo(CPUInfoType& dataStruct) { - return getConnection()->readCPUInfo(dataStruct); + return plcConn_->readCPUInfo(dataStruct); } int PLC::recvCPInfo(CPInfoType& dataStruct) { - return getConnection()->readCPInfo(dataStruct); + return plcConn_->readCPInfo(dataStruct); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // //Puts the CPU in RUN mode performing a COLD START. int PLC::sendColdRestart() { - return getConnection()->coldRestart(); + return plcConn_->coldRestart(); } int PLC::sendPlcStop() { - return getConnection()->plcStop(); + return plcConn_->plcStop(); } // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int PLC::recvAllBlockMode(const std::string& blockName) +{ + // TODO: When devices will be structured by classes, make sure that same block name in two classes does not cause problems. + auto& block = getOneDeviceBlock(blockName); // Get first device's block. + + unsigned long address = block->getAddress(); + unsigned long memSize = block->getMemSize(); + unsigned long bufferSize = memSize * getNrDevicesWithBlock(blockName); + unsigned long offset = 0; + + AccessArea area = block->getAccessArea(); + + std::vector<unsigned char> buffer(bufferSize, 0); + + int errorCode = 0; + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!plcConn_->doOpen()) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + switch (area) + { + case AccessArea::Digital: + errorCode = plcConn_->readDIO(address, offset, bufferSize, buffer.data()); + break; + case AccessArea::Analog: + { + errorCode = plcConn_->readAIO(address, offset, bufferSize, buffer.data()); + break; + } + case AccessArea::Memory: + default: + errorCode = plcConn_->readMemory(address, offset, bufferSize, buffer.data()); + break; + } + + if (plcConn_->isConnected() && (errorCode == 0)) + { + timeval tod; + gettimeofday(&tod, 0); + + //PLC context: Extract all registers value of all devices of the PLC from that block + for (auto& device : devices_) + { + // Only extract if this device actually contains this block, otherwise skip it. + if (!device.hasBlock(blockName)) + { + continue; + } + auto& devBlock = device.getBlock(blockName); + unsigned long deviceOffset = device.getInputAddress(area) * memSize; + unsigned char* pBuffer = buffer.data() + deviceOffset; + devBlock->importRegisters(pBuffer, tod); + } + } + return errorCode; +} + +int PLC::sendAllBlockMode(const std::string& blockName) +{ + // TODO: When devices will be structured by classes, make sure that same block name in two classes does not cause problems. + auto& block = getOneDeviceBlock(blockName); // Get first device's block. + + unsigned long address = block->getAddress(); + unsigned long memSize = block->getMemSize(); + unsigned long bufferSize = memSize * getNrDevicesWithBlock(blockName); + unsigned long offset = 0; + + AccessArea area = block->getAccessArea(); + + std::vector<unsigned char> buffer(bufferSize, 0); + + int errorCode = 0; + + // Try to open the connection, if it fails. Throw an exception. On success all the + // PLC blocks will be updated this function will be called recursively within doOpen. + // Once all blocks are updated continue from here. + if (!plcConn_->doOpen()) + { + throw SilecsException{__FILE__, __LINE__, COMM_CONNECT_FAILURE}; + } + + if (plcConn_->isEnabled()) + { + //PLC context: Export all registers value of all devices of the PLC to that block + for (auto& device : devices_) + { + // Only if this device actually contains this block, otherwise skip it. + if (!device.hasBlock(blockName)) + { + continue; + } + auto& devBlock = device.getBlock(blockName); + unsigned long deviceOffset = device.getOutputAddress(area) * memSize; + unsigned char* pBuffer = buffer.data() + deviceOffset; + devBlock->exportRegisters(pBuffer); + } + } + switch (area) + { + case AccessArea::Digital: + errorCode = plcConn_->writeDIO(address, offset, bufferSize, buffer.data()); + break; + case AccessArea::Analog: + { + errorCode = plcConn_->writeAIO(address, offset, bufferSize, buffer.data()); + break; + } + case AccessArea::Memory: + default: + errorCode = plcConn_->writeMemory(address, offset, bufferSize, buffer.data()); + break; + } + + return errorCode; +} + +int PLC::receiveForAllDevices(const std::string& blockName) +{ + int status = 0; + if (paramConfig_.protocolModeID == ProtocolMode::DeviceMode) + { + for (auto& device : devices_) + { + if (device.hasBlock(blockName)) + { + auto ret = device.recv(blockName); + status = (ret != 0) ? ret : status; + } + } + } + else + { + return recvAllBlockMode(blockName); + } + + return status; +} + +int PLC::sendForAllDevices(const std::string& blockName) +{ + int status = 0; + if (paramConfig_.protocolModeID == ProtocolMode::DeviceMode) + { + for (auto& device : devices_) + { + if (device.hasBlock(blockName)) + { + auto ret = device.send(blockName); + status = (ret != 0) ? ret : status; + } + } + } + else + { + return sendAllBlockMode(blockName); + } + + return status; +} + int PLC::recv(const std::string& blockName) { //Synchronous data receive //Execute the receive action for all the PLC devices (from the current thread) - return getBlock(blockName)->receive(allDevicesTransaction_); + return receiveForAllDevices(blockName); } int PLC::send(const std::string& blockName) { //Synchronous data send //Execute the send action for all the PLC devices (from the current thread) - return getBlock(blockName)->send(allDevicesTransaction_); + return sendForAllDevices(blockName); } std::future<int> PLC::recvAsync(const std::string& blockName) { //Schedule task using asynchronous call - return std::async(std::launch::async, &Block::receive, getBlock(blockName), allDevicesTransaction_); + return std::async(std::launch::async, &PLC::receiveForAllDevices, this, blockName); } std::future<int> PLC::sendAsync(const std::string& blockName) { //Schedule task using asynchronous call - return std::async(std::launch::async, &Block::send, getBlock(blockName), allDevicesTransaction_); + return std::async(std::launch::async, &PLC::sendForAllDevices, this, blockName); } void PLC::extractDatabase() @@ -404,69 +467,65 @@ void PLC::extractDatabase() // Extract general information =========================================== ElementXML rootNode = xmlParser.getSingleElementFromXPath("/SILECS-Param"); - localRelease_ = rootNode.getAttribute("silecs-version"); - if( !Service::isVersionSupported(localRelease_) ) + paramConfig_.localRelease = rootNode.getAttribute("silecs-version"); + if( !Service::isVersionSupported(paramConfig_.localRelease) ) { std::ostringstream message; - message << "The version of the parameter-file: '" << localRelease_ << "' is not compartible with the version of the silecs-library: '" << Service::getVersion() << "'"; + message << "The version of the parameter-file: '" << paramConfig_.localRelease << "' is not compartible with the version of the silecs-library: '" << Service::getVersion() << "'"; throw SilecsException(__FILE__, __LINE__, message.str().c_str()); } ElementXML ownerNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Owner"); - localOwner_ = ownerNode.getAttribute("user-login"); + paramConfig_.localOwner = ownerNode.getAttribute("user-login"); ElementXML generationNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Generation"); - localDate_ = generationNode.getAttribute("date"); + paramConfig_.localDate = generationNode.getAttribute("date"); ElementXML deploymentNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/Mapping-Info/Deployment"); - StringUtilities::fromString(localChecksum_, deploymentNode.getAttribute("checksum")); + StringUtilities::fromString(paramConfig_.localChecksum, deploymentNode.getAttribute("checksum")); // Extract PLC general configuration ====================================== ElementXML mappingNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/SILECS-Mapping"); //name_ = pEl->getStringAttribute("name"); already done before - domain_ = mappingNode.getAttribute("domain"); - brand_ = mappingNode.getAttribute("plc-brand"); - system_ = mappingNode.getAttribute("plc-system"); - protocolMode_ = mappingNode.getAttribute("protocol"); - model_ = mappingNode.getAttribute("plc-model"); - - StringUtilities::fromString(baseMemAddr_, mappingNode.getAttribute("address")); - //For backward compatibility (IO addresses are not defined in Silecs version <1.4.0) - //Undefined address = -1 by default. - baseDIAddr_ = -1; - baseDOAddr_ = -1; - baseAIAddr_ = -1; - baseAOAddr_ = -1; - if (mappingNode.hasAttribute("AI-address")) - StringUtilities::fromString(baseAIAddr_, mappingNode.getAttribute("AI-address")); - if (mappingNode.hasAttribute("AO-address")) - StringUtilities::fromString(baseAOAddr_, mappingNode.getAttribute("AO-address")); - if (mappingNode.hasAttribute("DI-address")) - StringUtilities::fromString(baseDIAddr_, mappingNode.getAttribute("DI-address")); - if (mappingNode.hasAttribute("DO-address")) - StringUtilities::fromString(baseDOAddr_, mappingNode.getAttribute("DO-address")); - usedMem_ = mappingNode.getAttribute("used-mem"); - - typeID_ = BusCoupler; //by default, we consider the controller won't use Memory access - - brandID_ = whichPLCBrand(brand_); - modelID_ = whichPLCModel(model_); - systemID_ = whichPLCSystem(system_); - protocolModeID_ = whichProtocolMode(protocolMode_); - protocolTypeID_ = whichProtocolType(system_); - - switch (protocolTypeID_) + paramConfig_.domain = mappingNode.getAttribute("domain"); + paramConfig_.brand = mappingNode.getAttribute("plc-brand"); + paramConfig_.system = mappingNode.getAttribute("plc-system"); + paramConfig_.protocolMode = mappingNode.getAttribute("protocol"); + paramConfig_.model = mappingNode.getAttribute("plc-model"); + + StringUtilities::fromString(paramConfig_.baseMemAddr, mappingNode.getAttribute("address")); + StringUtilities::fromString(paramConfig_.baseAIAddr, mappingNode.getAttribute("AI-address")); + StringUtilities::fromString(paramConfig_.baseAOAddr, mappingNode.getAttribute("AO-address")); + StringUtilities::fromString(paramConfig_.baseDIAddr, mappingNode.getAttribute("DI-address")); + StringUtilities::fromString(paramConfig_.baseDOAddr, mappingNode.getAttribute("DO-address")); + paramConfig_.usedMem = mappingNode.getAttribute("used-mem"); + + paramConfig_.typeID = BusCoupler; //by default, we consider the controller won't use Memory access + + paramConfig_.brandID = whichPLCBrand(paramConfig_.brand); + paramConfig_.modelID = whichPLCModel(paramConfig_.model); + paramConfig_.systemID = whichPLCSystem(paramConfig_.system); + paramConfig_.protocolModeID = whichProtocolMode(paramConfig_.protocolMode); + paramConfig_.protocolTypeID = whichProtocolType(paramConfig_.system); + + switch (paramConfig_.protocolTypeID) { case MBProtocol: - protocolType_ = "MODBUS-TCP"; + paramConfig_.protocolType = "MODBUS-TCP"; break; case S7Protocol: - protocolType_ = "SNAP7-TCP"; + paramConfig_.protocolType = "SNAP7-TCP"; break; case CNVProtocol: - protocolType_ = "CNV-TCP"; + paramConfig_.protocolType = "CNV-TCP"; break; }; +} +void PLC::createDevices() +{ + XMLParser xmlParser(parameterFile_, true); + ElementXML mappingNode = xmlParser.getSingleElementFromXPath("/SILECS-Param/SILECS-Mapping"); + const std::vector<ElementXML>& classNodes = mappingNode.getChildNodes(); for (auto& classNode : classNodes) { @@ -476,99 +535,68 @@ void PLC::extractDatabase() std::vector<ElementXML> instanceNodes = xmlParser.getElementsFromXPath("/SILECS-Param/SILECS-Mapping/SILECS-Class[@name='" + className + "']/Instance"); for (auto instanceIter = instanceNodes.begin(); instanceIter != instanceNodes.end(); instanceIter++) { - Device* pDevice = new Device(this, *instanceIter, blockNodes); - deviceCol_.push_back(std::make_pair(pDevice->getLabel(), pDevice)); - if (pDevice->getLabel() == "SilecsHeader") - theHeader_ = pDevice; - } - - for (auto blockIter = blockNodes.begin(); blockIter != blockNodes.end(); blockIter++) - { - std::string blockName = (*blockIter).getAttribute("name"); - AccessType accessType = Block::whichAccessType( (*blockIter).getName()); - LOG((DIAG)) << "The block '" << blockName << " of type '" << (*blockIter).getName() << "' will be created."; - - if (brandID_ == Ni) + devices_.emplace_back(*instanceIter, blockNodes, *plcConn_, paramConfig_); + for (auto& block : devices_.back().getBlocks()) { -#ifdef NI_SUPPORT_ENABLED - // TODO: Implement blocks in the same way as done for PLCBlock. - throw SilecsException(__FILE__, __LINE__, "CNV Blocks not implemented"); -#else - throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); -#endif + //Force BusController type (with SilecsHeader check), if there is at least one Memory block defined + if (block->getAccessArea() == AccessArea::Memory) + { + paramConfig_.typeID = BusController; + } } - - Block* pBlock = new PLCBlock(this, *blockIter, accessType); - blockCol_.push_back(pBlock); - - //Force BusController type (with SilecsHeader check), if there is at least one Memory block defined - if (pBlock->getAccessArea() == AccessArea::Memory) - typeID_ = BusController; - - } //for blocks - } //for classes + } + } } -Connection* PLC::createConnection() +void PLC::createConnection() { - Connection* theConn = NULL; - try + switch (paramConfig_.protocolTypeID) { - switch (protocolTypeID_) - { - case S7Protocol: - theConn = new SNAP7Connection(this); - break; - case MBProtocol: + case S7Protocol: + plcConn_ = std::unique_ptr<Connection>(new SNAP7Connection(this)); + break; + case MBProtocol: #ifdef MODBUS_SUPPORT_ENABLED - theConn = new MBConnection(this); break; + plcConn_ = std::unique_ptr<Connection>(new MBConnection(this)); + break; +#else + throw SilecsException(__FILE__, __LINE__, "Support for Modbus-Devices is disabled"); #endif - case CNVProtocol: + case CNVProtocol: #ifdef NI_SUPPORT_ENABLED - theConn = new CNVConnection(this);break; + plcConn_ = std::unique_ptr<Connection>(new CNVConnection(this)); + break; #else - throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); + throw SilecsException(__FILE__, __LINE__, "Support for NI-Devices is disabled"); #endif - default: - throw SilecsException(__FILE__, __LINE__, "Unknown protocolTypeID_"); - } - } - catch(const SilecsException& ex) - { //Something has failed. Nothing to do, we trust the re-open mechanism from now. - LOG(ERROR) << ex.what(); - throw ex; + default: + throw SilecsException(__FILE__, __LINE__, "Unknown protocolTypeID"); } if (DEBUG & Log::topics_) LOG(COMM) << "PLC::createConnection()"; - return theConn; } -Connection* PLC::getConnection() +const std::unique_ptr<Block>& PLC::getOneDeviceBlock(const std::string& blockName) const { - if (plcConn_ == NULL) + for (auto& device : devices_) { - LOG((COMM|DIAG)) << "No connection found. Attempt to establish connection ... "; - plcConn_ = createConnection(); - } - return plcConn_; -} - -Block* PLC::getBlock(const std::string& blockName) const -{ - for (auto block = blockCol_.begin(); block != blockCol_.end(); block++) - { - if ( (*block)->getName() == blockName) - return *block; + for (auto& block : device.getBlocks()) + { + if (block->getName() == blockName) + { + return block; + } + } } std::ostringstream error; error << "The block '" << blockName << "' was not found."; throw SilecsException(__FILE__, __LINE__, error.str()); } -blockVectorType& PLC::getBlockCol() +const std::vector<Device>& PLC::getDevices() const { - return blockCol_; + return devices_; } PLCBrand PLC::whichPLCBrand(std::string brand) @@ -694,33 +722,47 @@ ProtocolMode PLC::whichProtocolMode(std::string mode) void PLC::copyInToOut(const std::string& blockName) { - deviceVectorType::iterator pDeviceIter; - for (pDeviceIter = deviceCol_.begin(); pDeviceIter != deviceCol_.end(); ++pDeviceIter) - pDeviceIter->second->copyInToOut(blockName); + for (auto& device : devices_) + { + device.getBlock(blockName)->copyInToOut(); + } } -void PLC::setReadBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) +void PLC::setBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) { //Set the custom offset/size of the referred Input block if any. //Will throw an exception if that block-name does not exist. - getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize); -} - -void PLC::resetReadBlockAttributes(const std::string& blockName) -{ - getBlock(blockName)->resetCustomAttributes(); -} - -void PLC::setWriteBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize) -{ - //Set the custom address/offset/size of the referred Output block if any. - //Will throw an exception if that block-name does not exist. - getBlock(blockName)->setCustomAttributes(customAddress, customOffset, customSize); + for (auto& device : devices_) + { + for (auto& block : device.getBlocks()) + { + if (block->getName() == blockName) + { + return block->setCustomAttributes(customAddress, customOffset, customSize); + } + } + } + + std::ostringstream error; + error << "The block '" << blockName << "' was not found."; + throw SilecsException(__FILE__, __LINE__, error.str()); } -void PLC::resetWriteBlockAttributes(const std::string& blockName) +void PLC::resetBlockAttributes(const std::string& blockName) { - getBlock(blockName)->resetCustomAttributes(); + for (auto& device : devices_) + { + for (auto& block : device.getBlocks()) + { + if (block->getName() == blockName) + { + return block->resetCustomAttributes(); + } + } + } + std::ostringstream error; + error << "The block '" << blockName << "' was not found."; + throw SilecsException(__FILE__, __LINE__, error.str()); } } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h index 062606c..464bce4 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h @@ -15,7 +15,9 @@ Contributors: #define _SILECS_PLC_H_ #include <silecs-communication/interface/core/SilecsService.h> -#include <silecs-communication/interface/core/Context.h> +#include <silecs-communication/interface/utility/Definitions.h> +#include <silecs-communication/interface/equipment/SilecsParamConfig.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> #include <future> #include <string> @@ -34,103 +36,6 @@ typedef std::vector<std::pair<std::string, Device*> > deviceVectorType; typedef std::vector<Block*> blockVectorType; typedef std::map<std::string, Connection*> connMapType; -// PLC type, brand, system, protocol type and mode -typedef enum -{ - BusController, - BusCoupler -} PLCType; - -// PLC brand, system, protocol type and mode -typedef enum -{ - Siemens, - Schneider, - Ni, - Digi, - Beckhoff -} PLCBrand; - -typedef enum -{ - ET200S, - S7300, - S7400, - S71200, - S71500, - S7VIRTUAL, - Premium, - Quantum, - M340, - BC9xxx, - CX9xxx, - BK9xxx, - RCM4010, - RCM2000, - CompactRIO, - PXIRT, - PXIWindows, - PCWindows, - OtherSupportCNV -} PLCModel; - -typedef enum -{ - Step7, - TiaPortal, - Unity, - TwinCat, - StdC, - ServerS7, - Labview -} PLCSystem; - -typedef enum -{ - MBProtocol, - S7Protocol, - CNVProtocol -} ProtocolType; - -typedef enum -{ - BlockMode, - DeviceMode -} ProtocolMode; -/// @endcond - -// PLC unit status -typedef struct -{ - int status; //bit-pattern hardware specific (look at the related documentation) -} UnitStatusType; - -// Order code -typedef struct -{ - std::string code; - std::string version; -} UnitCodeType; - -// CPU Info -typedef struct -{ - std::string moduleName; - std::string moduleTypeName; - std::string serialNumber; - std::string asName; - std::string copyright; -} CPUInfoType; - -// CP Info -typedef struct -{ - int maxPduLength; - int maxConnections; - int maxMPIRate; - int maxBusRate; -} CPInfoType; - /*! * \class PLC * \brief This object provides all services related to a PLC. It provides the information @@ -147,8 +52,6 @@ public: * \return List of the related Cluster instances (Class/Version) for the PLC. */ std::vector<std::string> getDeviceList() const; - - deviceVectorType& getDeviceMap(); /// @endcond // Diagnostic features ---------------------------------------- @@ -165,127 +68,6 @@ public: */ std::string getIPAddress() const; - /*! - * \brief Returns the PLC configuration domain: CPS, PSB, ADE, .., TST - * \return Accelerator domain - */ - std::string getDomain() const; - - /*! - * \brief Returns the PLC manufacturer: SIEMENS, SCHNEIDER, BECKHOFF, RABBIT, NI - * \return PLC brand - */ - std::string getBrand() const; - - /*! - * \brief Returns the PLC development system: STEP-7, TIA-PORTAL, UNITY Pro, TWINCat, Standard-C, Standard-Cpp, Labview - * \return PLC development system - */ - std::string getSystem() const; - - /*! - * \brief Returns PLC hardware model: UNITY_Premium, SIMATIC_S7-300, .. - * \return PLC hardware model - */ - std::string getModel() const; - - /*! - * \brief Returns PLC type: bus coupler or bus controller - * \return PLC type - */ - PLCType getPLCType() const; - - /*! - * \brief Returns the protocol type used for the PLC communication: MODBUS-TCP, S7-TCP, CNV-TCP - * \return PLC protocol type - */ - std::string getProtocolType() const; - - /*! - * \brief Returns the SILECS mode used to map the data within the PLC memory: DEVICE_MODE, BLOCK_MODE - * \return PLC protocol mode - */ - std::string getProtocolMode() const; - - /*! - * \deprecated Use getMemBaseAddress() instead - * \brief Returns the memory base address of the SILECS configuration within the PLC - * \return DB number for SIMATIC-S7 - * \return 16bits absolute memory address for UNITY Premium/Quantum - * \return 32bits absolute memory address for UNITY M340 - */ - unsigned long getBaseAddress() const __attribute__ ((deprecated)); - - /*! - * \brief Returns the memory base address of the SILECS configuration within the PLC - * \return DB number for SIMATIC-S7 - * \return 16bits absolute memory address for UNITY Premium/Quantum - * \return 32bits absolute memory address for UNITY M340 - */ - long getMemBaseAddress() const; - - /*! - * \brief Returns the digital input base address of the SILECS configuration within the PLC - * \return byte address for SIMATIC-S7 - * \return byte address for MODBUS TCP - * \return -1 in case of non existent address - */ - long getDIBaseAddress() const; - - /*! - * \brief Returns the digital output base address of the SILECS configuration within the PLC - * \return byte address for SIMATIC-S7 - * \return byte address for MODBUS TCP - * \return -1 in case of non existent address - */ - long getDOBaseAddress() const; - - /*! - * \brief Returns the analog input base address of the SILECS configuration within the PLC - * \return byte address for SIMATIC-S7 - * \return byte address for MODBUS TCP - * \return -1 in case of non existent address - */ - long getAIBaseAddress() const; - - /*! - * \brief Returns the analog output base address of the SILECS configuration within the PLC - * \return byte address for SIMATIC-S7 - * \return byte address for MODBUS TCP - * \return -1 in case of non existent address - */ - long getAOBaseAddress() const; - - /*! - * \brief Extracts SILECS release information from the client configuration parameters. - * Provides detail about SILECS software used to generate the client documents. - * \return SILECS release number - */ - std::string getLocalRelease() const; - - /*! - * \brief Extracts Owner information from the client configuration parameters. - * Owner of the deployment document is not necessary responsible for the 'Generate' action - * who can be done by any Editor of the document. - * \return Owner name - */ - std::string getLocalOwner() const; - - /*! - * \brief Extracts the Date information from the client configuration parameters. - * Date of the client parameters file generation. - * \return Coordinate Universal Time (UTC) - */ - std::string getLocalDate() const; - - /*! - * \brief Extracts the Checksum information from the client configuration parameters. - * CRC-32 Checksum relies on Classes and Deployment documents that have been used to - * design the client configuration. - * \return CRC32 checksum - */ - unsigned long getLocalChecksum() const; - // Miscellaneous features ---------------------------------------- /*! @@ -293,13 +75,7 @@ public: * \param deviceName label or index of the device * \return Reference of the device object */ - Device* getDevice(const std::string& deviceName) const; - - /*! - * \fn getBlock - * \brief returns instance of the requested block - */ - Block* getBlock(const std::string& blockName) const; + Device* getDevice(const std::string& deviceName); /*! * \brief Used to Enable the Client/PLC connection and connect the PLC immediately if needed (connectNow=true). @@ -377,31 +153,13 @@ public: * \param customOffset offset (in byte) of the data block to be received * \param customSize real size (in byte) of the data block to be received */ - void setReadBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); + void setBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); /*! * \brief Sets back the default attributes of the data block (the ones defined by the design) * \param blockName name of the related block */ - void resetReadBlockAttributes(const std::string& blockName); - - /*! - * \brief Used to change designed attributes of a data block. - * In that version, can be used to limit dynamically size of data to be sent (send). - * Interesting for specific application that uses general purpose data block with maximum size and adjusts the real data size at communication time. - * Caution! This option can be used only with single device access (using DEVICE_MODE or send/recv from the Device level). - * \param blockName name of the related block - * \param customAddress base address (DBn or absolute in byte) of the data block to be sent - * \param customOffset offset (in byte) of the data block to be sent - * \param customSize real size (in byte) of the data block to be sent - */ - void setWriteBlockAttributes(const std::string& blockName, const unsigned long customAddress, const unsigned long customOffset, const unsigned long customSize); - - /*! - * \brief Sets back the default attributes of the data block (the ones defined by the design) - * \param blockName name of the related block - */ - void resetWriteBlockAttributes(const std::string& blockName); + void resetBlockAttributes(const std::string& blockName); /// @cond /*! @@ -411,47 +169,16 @@ public: * Allow sharing connection pipe between different classes if required (from mapping configuration) * \return reference to the [shared-]connection instance of this PLC instance */ - Connection* createConnection(); //just to instantiate the object - Connection* getConnection(); + void createConnection(); //just to instantiate the object /// @endcond std::string getParamsFileName() const; - /*! - * \brief Used for detemining the required block buffer size in case of BLOCK_MODE. In BLOCK_MODE a single block contains a specific register for all the devices, - * hence when calculating the required buffer size, we need to only reserve the space for the devices which actually contain this block. - * \param blockName name of the block which should be used to count the devices - */ - unsigned int getNrDevicesWithBlock(const std::string& blockName); - - PLCType getTypeID() const - { - return typeID_; - } - PLCBrand getBrandID() const - { - return brandID_; - } - PLCModel getModelID() const - { - return modelID_; - } - PLCSystem getSystemID() const - { - return systemID_; - } - ProtocolMode getProtocolModeID() const - { - return protocolModeID_; - } - ProtocolType getProtocolTypeID() const - { - return protocolTypeID_; - } + const SilecsParamConfig& getParamConfig() const; const Cluster& getCluster() const; - bool hasHeader() const; + const std::vector<Device>& getDevices() const; private: friend class Cluster; @@ -460,16 +187,20 @@ private: PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, std::string parameterFile = ""); virtual ~PLC(); - void updateLocalData(); + /*! + * \brief Used for detemining the required block buffer size in case of BLOCK_MODE. In BLOCK_MODE a single block contains a specific register for all the devices, + * hence when calculating the required buffer size, we need to only reserve the space for the devices which actually contain this block. + * \param blockName name of the block which should be used to count the devices + */ + unsigned int getNrDevicesWithBlock(const std::string& blockName); /*! - * \fn updateHeader - * \brief This method is used to update the unique 'SilecsHeader' Device data of the PLC config. - * It consists to create the corresponding Cluster if needed, connect the current PLC, - * upload the diagnostic block registers ('hdrBlk') then disconnect the PLC. - * \return True if uploading was correctly done. + * \fn getBlock + * \brief returns instance of the first found block of the first device */ - bool updateHeader(); + const std::unique_ptr<Block>& getOneDeviceBlock(const std::string& blockName) const; + + void updateLocalData(); /*! * \fn recvAsync/ recvWait @@ -483,6 +214,12 @@ private: */ std::future<int> sendAsync(const std::string& blockName); + int receiveForAllDevices(const std::string& blockName); + int sendForAllDevices(const std::string& blockName); + + int recvAllBlockMode(const std::string& blockName); + int sendAllBlockMode(const std::string& blockName); + /*! * \fn whichPLC, whichProtocol... * \return the enumeration value of the given Protocol type/mode string @@ -500,11 +237,7 @@ private: */ void extractDatabase(); - /*! - * \brief Provides the map of the Block objects attached to the underlying PLC(s) - * \return Block object map - */ - blockVectorType& getBlockCol(); + void createDevices(); /// Parent cluster reference of that PLC Cluster* theCluster_; @@ -512,62 +245,28 @@ private: /// PLC attributes std::string name_; std::string IPaddr_; - std::string domain_; //TST, ADE, PSB, CPS, .. - std::string brand_; //SIEMENS, SCHNEIDER, .. - std::string system_; //STEP-7, UNITY, TWINCAT, .. - std::string model_; //SIMATIC S7-300, Premium, .. - std::string protocolMode_; //Device, Block - std::string protocolType_; //MODBUS-TCP, S7-TCP, .. - - PLCType typeID_; //BusController (with CPU), BusCoupler (pure IO) - PLCBrand brandID_; //Siemens, Schneider, ... enumeration - PLCModel modelID_; //S7-400, S7-300, ... enumeration - PLCSystem systemID_; //Step7, Unity, TwinCat, ... enumeration - ProtocolMode protocolModeID_; //BlockMode, DeviceMode enumeration - ProtocolType protocolTypeID_; //Modbus, S7 enumeration - - long baseMemAddr_; - long baseDIAddr_; - long baseDOAddr_; - long baseAIAddr_; - long baseAOAddr_; - std::string usedMem_; std::string parameterFile_; - // Unique instance of the Header Device for diagnostic purpose - Device* theHeader_; - /* Diagnostic registers are used to check the consistency between the * PLC memory (remote data) and the client parameters (local data). */ - //Local data, extracted from the parameters file - std::string localRelease_; //Release number of the SILECS software - std::string localOwner_; //Owner of the deployment document - std::string localDate_; //Date of the Generation (Client parameters and PLC Sources) - uint32_t localChecksum_; //Checksum of the deployed configuration - //Remote data, uploaded from the PLC memory std::string remoteVersion_; std::string remoteOwner_; std::string remoteDate_; uint32_t remoteChecksum_; - Context* allDevicesTransaction_; - Context* allDevicesSynchronization_; - - /// Device collection of the PLC - deviceVectorType deviceCol_; + SilecsParamConfig paramConfig_; - /// Block collection of the PLC listed by name. - blockVectorType blockCol_; + std::vector<Device> devices_; /// Object to manage the plc communication /* By default, we instantiate 1 connection (2 channels: r/w) per PLC/Cluster * In order to safe PLC resources it's possible to share 1 connection between clusters of the same PLC. * A connection ID is used to define if the connection is shared or not. */ - Connection* plcConn_; // the connection object that can be individual per PLC/Cluster or shared + std::unique_ptr<Connection> plcConn_; // the connection object that can be individual per PLC/Cluster or shared }; } // namespace diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h new file mode 100644 index 0000000..c7c5071 --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsParamConfig.h @@ -0,0 +1,43 @@ +#ifndef _SILECS_PARAM_CONFIG_H_ +#define _SILECS_PARAM_CONFIG_H_ + +#include <silecs-communication/interface/utility/Definitions.h> + +#include <string> +#include <vector> + +namespace Silecs +{ + +struct SilecsParamConfig +{ + std::string plcName; + std::string localRelease; //Release number of the SILECS software + std::string localOwner; //Owner of the deployment document + std::string localDate; //Date of the Generation (Client parameters and PLC Sources) + uint32_t localChecksum; //Checksum of the deployed configuration + std::string domain; //TST, ADE, PSB, CPS, .. + std::string brand; //SIEMENS, SCHNEIDER, .. + std::string system; //STEP-7, UNITY, TWINCAT, .. + std::string model; //SIMATIC S7-300, Premium, .. + std::string protocolMode; //Device, Block + std::string protocolType; //MODBUS-TCP, S7-TCP, .. + + long baseMemAddr; + long baseDIAddr; + long baseDOAddr; + long baseAIAddr; + long baseAOAddr; + std::string usedMem; + + PLCType typeID; //BusController (with CPU), BusCoupler (pure IO) + PLCBrand brandID; //Siemens, Schneider, ... enumeration + PLCModel modelID; //S7-400, S7-300, ... enumeration + PLCSystem systemID; //Step7, Unity, TwinCat, ... enumeration + ProtocolMode protocolModeID; //BlockMode, DeviceMode enumeration + ProtocolType protocolTypeID; //Modbus, S7 enumeration +}; + +} // namespace Silecs + +#endif // _SILECS_PARAM_CONFIG_H_ \ No newline at end of file diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp index b1bf784..1cb6a07 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.cpp @@ -26,8 +26,8 @@ Contributors: namespace Silecs { -Register::Register(Device* theDevice, const ElementXML& registerNode) : - theDevice_(theDevice), isConfiguration_(false) +Register::Register(const ElementXML& registerNode) : + isConfiguration_(false) { name_ = registerNode.getAttribute("name"); length_ = 1; @@ -111,17 +111,6 @@ Register::~Register() } } -PLC* Register::getPLC() -{ - return theDevice_->getPLC(); -} - -Device* Register::getDevice() -{ - return theDevice_; -} - - // SET methods ============================================================= void Register::setAccessArea(AccessArea accessArea) @@ -133,6 +122,7 @@ void Register::setAccessType(AccessType accessType) { accessType_ = accessType; + std::lock_guard<std::mutex> lock(mutex_); // By knowing the register type we can allocate 1 or 2 buffers for data exchanges. pRecvValue_ = pSendValue_ = NULL; @@ -945,6 +935,7 @@ std::string Register::getInputValAsString(unsigned long i) ; std::string Register::getInputValAsString(unsigned long i, unsigned long j) { + std::lock_guard<std::mutex> lock(mutex_); if (isReadable()) { return getValAsString(pRecvValue_, i, j); @@ -965,6 +956,7 @@ std::string Register::getOutputValAsString(unsigned long i) ; std::string Register::getOutputValAsString(unsigned long i, unsigned long j) { + std::lock_guard<std::mutex> lock(mutex_); if (isWritable()) { return getValAsString(pSendValue_, i, j); @@ -975,6 +967,7 @@ std::string Register::getOutputValAsString(unsigned long i, unsigned long j) std::string Register::dumpInputVal(bool asAsciiChar) { + std::lock_guard<std::mutex> lock(mutex_); std::ostringstream os; unsigned long byteSize = dimension1_ * dimension2_ * size_; for (unsigned int i = 0; i < byteSize; i++) @@ -995,6 +988,7 @@ std::string Register::dumpInputVal(bool asAsciiChar) std::string Register::dumpOutputVal(bool asAsciiChar) { + std::lock_guard<std::mutex> lock(mutex_); std::ostringstream os; unsigned long byteSize = dimension1_ * dimension2_ * size_; for (unsigned int i = 0; i < byteSize; i++) @@ -1043,6 +1037,7 @@ std::string Register::getTimeStampAsString() void Register::printVal() { + std::lock_guard<std::mutex> lock(mutex_); std::ostringstream os; os << getName() << " " << getFormatAsString() << "[" << dimension1_ << "][" << dimension2_ << "] "; if (getFormat() == String) diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h index f7b8fad..25d8eec 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsRegister.h @@ -17,6 +17,7 @@ Contributors: #include <stdint.h> #include <cstring> #include <string> +#include <mutex> #include <silecs-communication/interface/utility/SilecsException.h> @@ -95,12 +96,6 @@ class Register { public: - /*! - * \brief Returns reference of the Device where the register is instantiated - * \return Reference of the Device object - */ - Device* getDevice(); - /*! * \brief Returns the register name as defined in the Class design * \return Register name @@ -338,14 +333,17 @@ public: template<typename T> void setValArray(const T* pVal, uint32_t dim); template<typename T> void setValArray2D(const T* pVal, uint32_t dim1, uint32_t dim2); + virtual ~Register(); + /// @cond protected: - Register(Device* theDevice, const ElementXML& registerNode); - virtual ~Register(); + Register(const ElementXML& registerNode); // export register extraction methods friend class PLC; friend class Device; + friend class Block; + friend class PLCBlock; /*! * \brief Set access type. @@ -418,9 +416,6 @@ protected: void setDoubleArrayFromString(const std::vector<std::string>& data); - /// Parent reference of that register - Device* theDevice_; - /// Register name std::string name_; @@ -465,6 +460,9 @@ protected: void* pRecvValue_; void* pSendValue_; + /// Mutex for synchronizing access to pRecvValue_ and pSendValue_ from import/export functions and get/set functions. + std::mutex mutex_; + /// Name of the "parent" Block name (for general information) std::string blockName_; @@ -476,7 +474,6 @@ protected: // FEC clock and Timing are synchronized using SNTP (common GPS source) timeval tod_; - PLC* getPLC(); /// @endcond //private: @@ -491,6 +488,7 @@ inline bool Register::getVal<bool>() if ( !isValidType<bool>() || !isScalar()) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); if (* ((int8_t*)pRecvValue_) == 0) return false; else @@ -505,6 +503,7 @@ inline std::string Register::getVal<std::string>() if (!isValidType<std::string>() || (dimension1_ != 1) || (dimension2_ != 1)) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); return * (pRecvStringValue[0]); } @@ -516,6 +515,7 @@ T Register::getVal() throw SilecsException(__FILE__, __LINE__, DATA_READ_ACCESS_TYPE_MISMATCH, getName()); if (!isValidType<T>() || !isScalar()) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); return * ((T*)pRecvValue_); } @@ -529,6 +529,7 @@ inline void Register::getValArray<std::string>(std::string* pVal, uint32_t dim) if ( (dimension1_ != dim) || (dimension2_ > 1)) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); for (unsigned long i = 0; i < dimension1_; i++) { @@ -546,6 +547,7 @@ inline void Register::getValArray2D<std::string>(std::string* pVal, uint32_t dim if ( (dimension1_ != dim1) || (dimension2_ != dim2)) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pRecvStringValue = static_cast<std::string**>(pRecvValue_); for (unsigned long i = 0; i < dimension1_; i++) { @@ -565,6 +567,7 @@ void Register::getValArray(T* pValue, uint32_t dim) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); if (dimension1_ != dim) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); memcpy((void *)pValue, pRecvValue_, size_ * dimension1_); } @@ -577,6 +580,7 @@ void Register::getValArray2D(T* pValue, uint32_t dim1, uint32_t dim2) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); if ( (dimension1_ != dim1) || (dimension2_ != dim2)) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); memcpy((void *)pValue, pRecvValue_, size_ * dimension1_ * dimension2_); } @@ -589,6 +593,7 @@ inline const std::string** Register::getRefArray(uint32_t& dim) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); dim = dimension1_; // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); return (const std::string**)pRecvValue_; } @@ -602,6 +607,7 @@ inline const std::string** Register::getRefArray2D(uint32_t& dim1, uint32_t& dim dim1 = dimension1_; dim2 = dimension2_; // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); return (const std::string**)pRecvValue_; } @@ -613,6 +619,7 @@ T* Register::getRefArray(uint32_t& dim) if (!isValidType<T>() || !isSingleArray()) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); dim = dimension1_; + std::lock_guard<std::mutex> lock(mutex_); return (T*)pRecvValue_; } @@ -625,6 +632,7 @@ T* Register::getRefArray2D(uint32_t& dim1, uint32_t& dim2) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); dim1 = dimension1_; dim2 = dimension2_; + std::lock_guard<std::mutex> lock(mutex_); return (T*)pRecvValue_; } @@ -637,6 +645,7 @@ inline void Register::setVal<std::string>(std::string val) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); * (pSendStringValue[0]) = val; isInitialized_ = true; //the register value has been set once at least @@ -649,6 +658,7 @@ void Register::setVal(T val) throw SilecsException(__FILE__, __LINE__, DATA_WRITE_ACCESS_TYPE_MISMATCH, getName()); if (!isValidType<T>() || (dimension1_ != 1)) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); * ((T*)pSendValue_) = val; isInitialized_ = true; //the register value has been set once at least } @@ -664,6 +674,7 @@ inline void Register::setValArray<std::string>(const std::string* pVal, uint32_t throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); for (unsigned long i = 0; i < dimension1_; i++) { @@ -681,6 +692,7 @@ void Register::setValArray(const T* pVal, uint32_t dim) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); if (dimension1_ != dim) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); memcpy(pSendValue_, (void *)pVal, size_ * dimension1_); isInitialized_ = true; //the register value has been set once at least } @@ -696,6 +708,7 @@ inline void Register::setValArray2D<std::string>(const std::string* pVal, uint32 throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); // TODO: Fix this string casting. + std::lock_guard<std::mutex> lock(mutex_); std::string** pSendStringValue = static_cast<std::string**>(pSendValue_); for (unsigned long i = 0; i < dimension1_; i++) { @@ -716,6 +729,7 @@ void Register::setValArray2D(const T* pVal, uint32_t dim1, uint32_t dim2) throw SilecsException(__FILE__, __LINE__, PARAM_FORMAT_TYPE_MISMATCH, getName()); if ( (dimension1_ != dim1) || (dimension2_ != dim2)) throw SilecsException(__FILE__, __LINE__, PARAM_ARRAY_DIMENSION_MISMATCH, getName()); + std::lock_guard<std::mutex> lock(mutex_); memcpy(pSendValue_, (void *)pVal, size_ * dimension1_ * dimension2_); isInitialized_ = true; //the register value has been set once at least } diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h new file mode 100644 index 0000000..eba119c --- /dev/null +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/Definitions.h @@ -0,0 +1,106 @@ +#ifndef _SILECS_UTILITY_DEFINITIONS_H_ +#define _SILECS_UTILITY_DEFINITIONS_H_ + +namespace Silecs +{ + +// PLC type, brand, system, protocol type and mode +typedef enum +{ + BusController, + BusCoupler +} PLCType; + +// PLC brand, system, protocol type and mode +typedef enum +{ + Siemens, + Schneider, + Ni, + Digi, + Beckhoff +} PLCBrand; + +typedef enum +{ + ET200S, + S7300, + S7400, + S71200, + S71500, + S7VIRTUAL, + Premium, + Quantum, + M340, + BC9xxx, + CX9xxx, + BK9xxx, + RCM4010, + RCM2000, + CompactRIO, + PXIRT, + PXIWindows, + PCWindows, + OtherSupportCNV +} PLCModel; + +typedef enum +{ + Step7, + TiaPortal, + Unity, + TwinCat, + StdC, + ServerS7, + Labview +} PLCSystem; + +typedef enum +{ + MBProtocol, + S7Protocol, + CNVProtocol +} ProtocolType; + +typedef enum +{ + BlockMode, + DeviceMode +} ProtocolMode; +/// @endcond + +// PLC unit status +typedef struct +{ + int status; //bit-pattern hardware specific (look at the related documentation) +} UnitStatusType; + +// Order code +typedef struct +{ + std::string code; + std::string version; +} UnitCodeType; + +// CPU Info +typedef struct +{ + std::string moduleName; + std::string moduleTypeName; + std::string serialNumber; + std::string asName; + std::string copyright; +} CPUInfoType; + +// CP Info +typedef struct +{ + int maxPduLength; + int maxConnections; + int maxMPIRate; + int maxBusRate; +} CPInfoType; + +} // namespace Silecs + +#endif // _SILECS_UTILITY_DEFINITIONS_H_ \ No newline at end of file diff --git a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h index e5079cc..cba3307 100644 --- a/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h +++ b/silecs-communication-cpp/src/silecs-communication/interface/utility/StringUtilities.h @@ -48,7 +48,6 @@ public: static std::string toString(const void * ptr); static void toLower(std::string& str); static bool evalStringToBool(std::string stringVal); - // TODO: Merge both fromString methods ( std::ios_base argument is anyhwo always the same ) /*! * \brief transform a string into any integer-type * \param str the string to transform diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp index 7d40311..89ea6ed 100755 --- a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.cpp @@ -24,6 +24,8 @@ Contributors: #include <silecs-communication/interface/utility/XMLParser.h> #include <silecs-communication/interface/utility/SilecsException.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> #include <exception> extern silecsModule *mysilecs; @@ -996,7 +998,7 @@ void diagnosticToolMainView::on_copyButton_clicked() "You are trying to copy all the input value to the output values.\nThe copy will effect all the register of the block "+ui->copyComboBox->currentText()+" in the device "+QString::fromStdString(device->getLabel())+".\nDo you confirm this operation?", QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) { - device->copyInToOut(blockName); + device->getBlock(blockName)->copyInToOut(); mysilecs->updateDeviceItem(currentItem,false); } } diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h index dbc00fe..f4e64ed 100755 --- a/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/diagnostictoolmainview.h @@ -21,6 +21,8 @@ Contributors: #include <silecs-diagnostic/silecsmodule.h> #include <silecs-diagnostic/stderrredirect.h> +#include <silecs-communication/interface/equipment/SilecsRegister.h> + #include <iostream> #include <typeinfo> #include <map> diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp index 691a886..84b887d 100755 --- a/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/silecsmodule.cpp @@ -15,6 +15,8 @@ Contributors: #include <silecs-diagnostic/silecsmodule.h> #include <silecs-communication/interface/utility/XMLParser.h> #include <silecs-communication/interface/utility/StringUtilities.h> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> extern std::string UserName; @@ -182,9 +184,9 @@ Item *silecsModule::generateTree(const std::string& className, const std::string if(registerName.compare("")==0) break; Utils::logInfo(messageConsole_,"found Register: '" + registerName + "' in parameter file"); - Silecs::Register *reg = device->getRegister(registerName); + auto& reg = device->getRegister(registerName); - Item *registerItem = Utils::addTreeItem(deviceItem,QString::fromStdString(registerName),"",QString::fromStdString(REGISTER_TYPE),reg,":/Images/REG.png" ); + Item *registerItem = Utils::addTreeItem(deviceItem,QString::fromStdString(registerName),"",QString::fromStdString(REGISTER_TYPE),reg.get(),":/Images/REG.png" ); // Set the block name registerItem->setText(1 , QString::fromStdString(reg->getBlockName())); @@ -226,7 +228,7 @@ void silecsModule::setScalarDataInDeviceFromItem(Item *currentItem, const std::s if(registerName.compare("")==0) break; - Silecs::Register *reg = device->getRegister(registerName); + auto& reg = device->getRegister(registerName); // analyse just the register within the selected block if(reg->getBlockName().compare(blockName)!=0) @@ -288,7 +290,7 @@ void silecsModule::updateDeviceItem(Item *deviceItem,bool updateInputBufferOnly) { // Get the register Item in the tree view Item *regItem = dynamic_cast<Item*>(deviceItem->child(regIndex)); - Silecs::Register *reg = device->getRegister(regItem->text(0).toStdString()); + auto& reg = device->getRegister(regItem->text(0).toStdString()); Utils::logInfo(messageConsole_,"updating register: '" + reg->getName() + "'of device: '" + device-> getLabel() + "'" ); // PLC values diff --git a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp index 8da767a..a5e66ab 100755 --- a/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp +++ b/silecs-diagnostic-cpp/src/silecs-diagnostic/utils.cpp @@ -17,6 +17,9 @@ Contributors: #include <silecs-diagnostic/silecsmodule.h> #include <iomanip> +#include <silecs-communication/interface/equipment/SilecsDevice.h> +#include <silecs-communication/interface/equipment/SilecsPLC.h> + extern silecsModule *mysilecs; @@ -130,11 +133,13 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console) { std::string text = ""; + auto& paramConfig = plc->getParamConfig(); + if (plc->isConnected(false)) { text.append("<h3><font color ='green'>This PLC is currently connected</font></h3><hr/>"); - if (plc->getPLCType() == BusCoupler) + if (paramConfig.typeID == BusCoupler) { text.append("<h3><font color ='green'>PLC Runtime information</font></h3>"); text.append("<ul>"); @@ -162,38 +167,38 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console) text.append("<ul>"); text.append("<li>Name: " + plc->getName() + "</li>"); text.append("<li>Address: " + plc->getIPAddress() + "</li>"); - text.append("<li>Brand: " + plc->getBrand() + "</li>"); - text.append("<li>Model: " + plc->getModel() + "</li>"); - text.append("<li>Owner: " + plc->getLocalOwner() + "</li>"); + text.append("<li>Brand: " + paramConfig.brand + "</li>"); + text.append("<li>Model: " + paramConfig.model + "</li>"); + text.append("<li>Owner: " + paramConfig.localOwner + "</li>"); text.append("</ul><hr/>"); text.append("<h3>PLC configuration information</h3>"); text.append("<ul>"); - text.append("<li>Protocol type: " + plc->getProtocolType() + "</li>"); - text.append("<li>Protocol mode: " + plc->getProtocolMode() + "</li>"); + text.append("<li>Protocol type: " + paramConfig.protocolType + "</li>"); + text.append("<li>Protocol mode: " + paramConfig.protocolMode + "</li>"); - if (plc->getMemBaseAddress() > -1) - text.append("<li>Memory Base address: " + toString(plc->getMemBaseAddress()) + " (0x" + toString(plc->getMemBaseAddress(), 16) + ")" + "</li>"); + if (paramConfig.baseMemAddr > -1) + text.append("<li>Memory Base address: " + toString(paramConfig.baseMemAddr) + " (0x" + toString(paramConfig.baseMemAddr, 16) + ")" + "</li>"); else text.append("<li>Memory Base address: Not applicable</li>"); - if (plc->getDIBaseAddress() > -1) - text.append("<li>DI Base address: " + toString(plc->getDIBaseAddress()) + " (0x" + toString(plc->getDIBaseAddress(), 16) + ")" + "</li>"); + if (paramConfig.baseDIAddr > -1) + text.append("<li>DI Base address: " + toString(paramConfig.baseDIAddr) + " (0x" + toString(paramConfig.baseDIAddr, 16) + ")" + "</li>"); else text.append("<li>DI Base address: Not applicable</li>"); - if (plc->getDOBaseAddress() > -1) - text.append("<li>DO Base address: " + toString(plc->getDOBaseAddress()) + " (0x" + toString(plc->getDOBaseAddress(), 16) + ")" + "</li>"); + if (paramConfig.baseDOAddr > -1) + text.append("<li>DO Base address: " + toString(paramConfig.baseDOAddr) + " (0x" + toString(paramConfig.baseDOAddr, 16) + ")" + "</li>"); else text.append("<li>DO Base address: Not applicable</li>"); - if (plc->getAIBaseAddress() > -1) - text.append("<li>AI Base address: " + toString(plc->getAIBaseAddress()) + " (0x" + toString(plc->getAIBaseAddress(), 16) + ")" + "</li>"); + if (paramConfig.baseAIAddr > -1) + text.append("<li>AI Base address: " + toString(paramConfig.baseAIAddr) + " (0x" + toString(paramConfig.baseAIAddr, 16) + ")" + "</li>"); else text.append("<li>AI Base address: Not applicable</li>"); - if (plc->getAOBaseAddress() > -1) - text.append("<li>AO Base address: " + toString(plc->getAOBaseAddress()) + " (0x" + toString(plc->getAOBaseAddress(), 16) + ")" + "</li>"); + if (paramConfig.baseAOAddr > -1) + text.append("<li>AO Base address: " + toString(paramConfig.baseAOAddr) + " (0x" + toString(paramConfig.baseAOAddr, 16) + ")" + "</li>"); else text.append("<li>AO Base address: Not applicable</li>"); @@ -201,9 +206,9 @@ void Utils::displayPLCInformation(Silecs::PLC *plc, QTextEdit *console) text.append("<h3>PLC generation information</h3>"); text.append("<ul>"); - text.append("<li>Release: " + plc->getLocalRelease() + "</li>"); - text.append("<li>Date: " + plc->getLocalDate() + "</li>"); - text.append("<li>Checksum: " + toString(plc->getLocalChecksum()) + "</li>"); + text.append("<li>Release: " + paramConfig.localRelease + "</li>"); + text.append("<li>Date: " + paramConfig.localDate + "</li>"); + text.append("<li>Checksum: " + toString(paramConfig.localChecksum) + "</li>"); text.append("</ul><hr/>"); console->setText(QString::fromStdString(text)); -- GitLab