Skip to content

Commit

Permalink
EIPScanner-19: add readonly flag of Parameter Object
Browse files Browse the repository at this point in the history
  • Loading branch information
atimin committed Jan 4, 2020
1 parent b145138 commit 65c86bd
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 22 deletions.
16 changes: 14 additions & 2 deletions src/ParameterObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace eipScanner {

enum DescriptorAttributeBits : cip::CipUint {
SUPPORTS_SCALING = 1 << 2,
READ_ONLY = 1 << 4,
};

ParameterObject::ParameterObject(cip::CipUint id, bool fullAttributes,
Expand All @@ -47,6 +48,7 @@ namespace eipScanner {
, _minValue(typeSize)
, _defaultValue(typeSize)
, _isScalable(false)
, _isReadOnly(false)
, _scalingMultiplier(1)
, _scalingDivisor(1)
, _scalingBase(1)
Expand Down Expand Up @@ -101,9 +103,12 @@ namespace eipScanner {
CipWord descriptor;
buffer >> descriptor >> reinterpret_cast<CipUsint&>(_type);

_isScalable = descriptor & DescriptorAttributeBits::SUPPORTS_SCALING;
_isReadOnly = descriptor & DescriptorAttributeBits::READ_ONLY;
Logger(LogLevel::DEBUG) << "Parameter object ID=" << instanceId
<< " has descriptor=0x" << std::hex << descriptor
<< " scalable=" << _isScalable;
<< " scalable=" << _isScalable
<< " readonly=" << _isReadOnly;

if (_hasFullAttributes) {
ignore.resize(1);
Expand All @@ -116,7 +121,6 @@ namespace eipScanner {
_units = units.toStdString();
_help = help.toStdString();

_isScalable = descriptor & DescriptorAttributeBits::SUPPORTS_SCALING;
if (_isScalable) {
ignore.resize(16); // Ignore scaling attributes we read it separately due to a bug
buffer >> ignore
Expand Down Expand Up @@ -193,6 +197,10 @@ namespace eipScanner {
return _isScalable;
}

bool ParameterObject::isReadOnly() const {
return _isReadOnly;
}

const std::string &ParameterObject::getUnits() const {
return _units;
}
Expand Down Expand Up @@ -225,6 +233,10 @@ namespace eipScanner {
_isScalable = isScalable;
}

void ParameterObject::setReadOnly(bool isReadOnly) {
_isReadOnly = isReadOnly;
}

void ParameterObject::setType(CipDataTypes type) {
_type = type;
}
Expand Down
37 changes: 25 additions & 12 deletions src/ParameterObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ class ParameterObject : public BaseObject {
*/
void updateValue(const SessionInfoIf::SPtr& si);

//// Flags from Descriptor Atribute [AttrID=4]
/**
* @return true if the parameter supports scaling
*/
bool isScalable() const;

/**
*
* @param isScalable true if the parameter supports scaling
*/
void setScalable(bool isScalable);

/**
* @return true if the parameter value is read only
*/
bool isReadOnly() const;

/**
*
* @param isReadOnly true if the parameter value is read only
*/
void setReadOnly(bool isReadOnly);

/**
* @brief Gets an actual value [AttrID=1] of the parameter.
* @note This is just a getter. To read value from EIP device, use ParameterObject::updateValue
Expand Down Expand Up @@ -249,17 +272,6 @@ class ParameterObject : public BaseObject {
*/
void setHelp(const std::string &help);

/**
* @return true if the parameter supports scaling
*/
bool isScalable() const;

/**
*
* @param isScalable true if the parameter supports scaling
*/
void setScalable(bool isScalable);

/**
* @brief Gets the multiplier [AttrID=13] of the parameter
* @return
Expand Down Expand Up @@ -341,7 +353,8 @@ class ParameterObject : public BaseObject {
}

bool _hasFullAttributes;
bool _isScalable{};
bool _isScalable;
bool _isReadOnly;

std::vector<uint8_t> _value;
cip::CipDataTypes _type;
Expand Down
31 changes: 23 additions & 8 deletions test/TestParameterObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ using ::testing::Return;
class TestParameterObject : public ::testing::Test {
public:
const static cip::CipUint OBJECT_ID = 1;
const std::vector<uint8_t> PARAM_DATA = {
std::vector<uint8_t> makeParamData(uint8_t descriptor) {
return {
0x01, 0x0, 0x0, 0x0, //value
0x6, //path size
0x20, 0x05, 0x24, 0x02, 0x30, 0x01, // path
0x4, 0x0, // descriptor (scalable)
descriptor, 0x0, // descriptor (scalable)
(uint8_t)cip::CipDataTypes::UDINT, // type
0x4, // data size
5, 'P', 'A', 'R', 'A', 'M', //name
Expand All @@ -32,28 +33,30 @@ class TestParameterObject : public ::testing::Test {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x1

};
};

void SetUp() override {
_messageRouter = std::make_shared<TMockMessageRouter>();
_nullSession = nullptr;
}

void mockReadingParamData(bool isScalable) {
void mockReadingParamData(bool fullAttribute, uint8_t descriptor = 0x04) {
cip::MessageRouterResponse response;
response.setData({4});

EXPECT_CALL(*_messageRouter, sendRequest(_nullSession,
cip::ServiceCodes::GET_ATTRIBUTE_SINGLE,
cip::EPath(ParameterObject::CLASS_ID, OBJECT_ID, 6), std::vector<uint8_t>())).WillOnce(Return(response));

response.setData(PARAM_DATA);
response.setData(makeParamData(descriptor));

EXPECT_CALL(*_messageRouter, sendRequest(_nullSession,
cip::ServiceCodes::GET_ATTRIBUTE_ALL,
cip::EPath(ParameterObject::CLASS_ID, OBJECT_ID), std::vector<uint8_t>())).WillOnce(Return(response));

if (isScalable) {
if ((descriptor & 0x04) > 0 && fullAttribute) {
response.setData({0x2, 0x0});
EXPECT_CALL(*_messageRouter, sendRequest(_nullSession,
cip::ServiceCodes::GET_ATTRIBUTE_SINGLE,
Expand Down Expand Up @@ -86,21 +89,23 @@ class TestParameterObject : public ::testing::Test {
};

TEST_F(TestParameterObject, ShouldReadAllStubDataInConstructor) {
mockReadingParamData(false);
mockReadingParamData(false,0x04);
ParameterObject parameterObject(OBJECT_ID, false, _nullSession, _messageRouter);

EXPECT_FALSE(parameterObject.hasFullAttributes());
EXPECT_FALSE(parameterObject.isScalable());
EXPECT_TRUE(parameterObject.isScalable());
EXPECT_FALSE(parameterObject.isReadOnly());
EXPECT_EQ(0x1, parameterObject.getActualValue<cip::CipUdint>());
EXPECT_EQ(cip::CipDataTypes::UDINT, parameterObject.getType());
EXPECT_EQ("", parameterObject.getName());
}

TEST_F(TestParameterObject, ShouldReadAllFullDataInConstructor) {
mockReadingParamData(true);
mockReadingParamData(true, 0x04);
ParameterObject parameterObject(OBJECT_ID, true, _nullSession, _messageRouter);

EXPECT_TRUE(parameterObject.hasFullAttributes());
EXPECT_FALSE(parameterObject.isReadOnly());
EXPECT_EQ(0x1, parameterObject.getActualValue<cip::CipUdint>());
EXPECT_EQ(cip::CipDataTypes::UDINT, parameterObject.getType());
EXPECT_EQ("PARAM", parameterObject.getName());
Expand Down Expand Up @@ -144,13 +149,16 @@ TEST_F(TestParameterObject, ShouldUpdateValue) {
TEST_F(TestParameterObject, ShouldProvideSettersAndConstructorWithoutNetworkCommunication) {
ParameterObject parameterObject(OBJECT_ID, true, sizeof(cip::CipUdint));

parameterObject.setReadOnly(true);
parameterObject.setScalable(true);
parameterObject.setScalingMultiplier(2);
parameterObject.setScalingDivisor(4);
parameterObject.setScalingBase(1);
parameterObject.setScalingOffset(6);
parameterObject.setPrecision(1);

EXPECT_TRUE(parameterObject.isReadOnly());

EXPECT_DOUBLE_EQ(0.3, parameterObject.getEngValue<cip::CipUdint>());

parameterObject.setEngMinValue<cip::CipUdint>(0.3);
Expand All @@ -164,4 +172,11 @@ TEST_F(TestParameterObject, ShouldProvideSettersAndConstructorWithoutNetworkComm
parameterObject.setEngDefaultValue<cip::CipUdint>(0.45);
EXPECT_DOUBLE_EQ(0.45, parameterObject.getEngDefaultValue<cip::CipUdint>());
EXPECT_DOUBLE_EQ(3, parameterObject.getDefaultValue<cip::CipUdint>());
}

TEST_F(TestParameterObject, ShouldReadFlagReadOnlyFromDescriptor) {
mockReadingParamData(false, 0x10);
ParameterObject parameterObject(OBJECT_ID, false, _nullSession, _messageRouter);

EXPECT_TRUE(parameterObject.isReadOnly());
}

0 comments on commit 65c86bd

Please sign in to comment.