Store PLCnext CommunityPLCnext on LinkedInPLCnext on Instagram  PLCnext on YouTube Github PLCnext CommunityStore PLCnext Community

  1. kshah
  2. PLCnext Engineer
  3. Wednesday, 21 April 2021
Hello,

I'm trying to use the JSON Decoder function block of the JSON Utility Library in the PLCnext Store and can't seem to be able to parse unsigned long ints. The values that I send seem to all end up in the liValue variable of the JSON_UDT_VALUE struct instead of the uliValue variable, with the according value of 2 for the enType variable. As far as I know JSON represents all numbers as 64-bit floats, so I'm not sure how the function block decides whether a given positive integer should be unsigned or signed. I only need 16-bit uints so I can just switch to reading from the liValue variable for now, but it would be useful to know what's going on under the hood there.

Thanks.
Accepted Answer
Eduard PLCnext Team Accepted Answer Pending Moderation
0
Votes
Undo
Hello kshah,
as described in documentation, the JSON Utility Library is based on the jsoncpp project, the parser is able to parse for "Json::ValueType".
Please see API-Documentation under following Link:
http://open-source-parsers.github.io/jsoncpp-docs/doxygen/namespace_json.html#a7d654b75c16a57007925868e38212b4e

The handling of numbers is described under following link:
https://www.json.org/json-en.html

In IEC61131 you have the conversion FB's and it is possible to convert the datatypes Int64 or UInt64 of Json values in needed IEC datatype e.g. "TO_BYTE", "TO_INT", "TO_UINT".
The SEL FB (selection FB) can be also useful.

The following code will be used for number decode:

bool Reader::decodeNumber(Token& token, Value& decoded) {
// Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then
// we decode the number as a double.
Location current = token.start_;
bool isNegative = *current == '-';
if (isNegative)
++current;
// TODO: Help the compiler do the div and mod at compile time or get rid of
// them.
Value::LargestUInt maxIntegerValue =
isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
: Value::maxLargestUInt;
Value::LargestUInt threshold = maxIntegerValue / 10;
Value::LargestUInt value = 0;
while (current < token.end_) {
Char c = *current++;
if (c < '0' || c > '9')
return decodeDouble(token, decoded);
auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, b) this is the last digit, and
// c) it's small enough to fit in that rounding delta, we're okay.
// Otherwise treat this number as a double to avoid overflow.
if (value > threshold || current != token.end_ ||
digit > maxIntegerValue % 10) {
return decodeDouble(token, decoded);
}
}
value = value * 10 + digit;
}
if (isNegative && value == maxIntegerValue)
decoded = Value::minLargestInt;
else if (isNegative)
decoded = -Value::LargestInt(value);
else if (value <= Value::LargestUInt(Value::maxInt))
decoded = Value::LargestInt(value);
else
decoded = value;
return true;
}

Best Regards
Eduard
Phoenix Contact Electronics Headquarter - PLCnext Runtime Product Management and Support
kshah Accepted Answer Pending Moderation
0
Votes
Undo
Hi Eduard,

Thanks for the link to the code. I'm not too familiar with C++, but after investigating a little it looks like the decoder will only parse the number as a ulint if it exceeds the maximum value for an lint, which makes sense. For my application I'll just read from the liValue and convert into a 16-bit uint.
  • Page :
  • 1


There are no replies made for this post yet.
However, you are not allowed to reply to this post.