Skip to content

Commit

Permalink
Added logic to specify an include directive in the source file for a …
Browse files Browse the repository at this point in the history
…code tag. Improved field limiting logic by account for floating point rounding error and actual maximum enumeration size.
  • Loading branch information
billvaglienti committed Apr 13, 2020
1 parent 0244467 commit b7068e1
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 46 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ Code subtag attributes:
- `encode` : A verbatim code snippet that is inserted in the encode function.
- `decode` : A verbatim code snippet that is inserted in the decode function.
- `comment` : A one line comment above the code snippet.
- `include` : The name of a file to #include in the source code of the function that contains the structure encoding/decoding functions. This is useful to support calling external functions from the Code subtag.

Packet tag
----------
Expand Down
3 changes: 3 additions & 0 deletions encodable.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class Encodable : public ProtocolDocumentation
//! Return the include directives needed for this encodable
virtual void getIncludeDirectives(QStringList& list) const {Q_UNUSED(list);}

//! Return the include directives that go into source code needed for this encodable
virtual void getSourceIncludeDirectives(QStringList& list) const {Q_UNUSED(list);}

//! Return the include directives needed for this encodable's init and verify functions
virtual void getInitAndVerifyIncludeDirectives(QStringList& list) const {Q_UNUSED(list);}

Expand Down
14 changes: 8 additions & 6 deletions enumcreator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ QString EnumElement::getDeclaration() const
EnumCreator::EnumCreator(ProtocolParser* parse, QString Parent, ProtocolSupport supported) :
ProtocolDocumentation(parse, Parent, supported),
minbitwidth(0),
maxvalue(0),
hidden(false),
lookup(false),
lookupTitle(false),
Expand Down Expand Up @@ -122,6 +123,7 @@ void EnumCreator::clear(void)
filepath.clear();
sourceOutput.clear();
minbitwidth = 0;
maxvalue = 0;
hidden = false;
lookup = false;
lookupTitle = false;
Expand Down Expand Up @@ -482,7 +484,7 @@ void EnumCreator::checkAgainstKeywords(void)
void EnumCreator::computeNumberList(void)
{
// Attempt to get a list of numbers that represents the value of each enumeration
int maxValue = 1;
maxvalue = 1;
int value = -1;
QString baseString;

Expand Down Expand Up @@ -524,7 +526,7 @@ void EnumCreator::computeNumberList(void)
if (!ok)
{
replaceEnumerationNameWithValue(stringValue);
parser->replaceEnumerationNameWithValue(stringValue);
stringValue = parser->replaceEnumerationNameWithValue(stringValue);

// If this string is a composite of numbers, add them together if we can
stringValue = EncodedLength::collapseLengthString(stringValue, true);
Expand All @@ -549,19 +551,19 @@ void EnumCreator::computeNumberList(void)
}// if we got a string from the xml

// keep track of maximum value
if(value > maxValue)
maxValue = value;
if(value > maxvalue)
maxvalue = value;

// Remember the value
element.number = stringValue;

}// for the whole list of value strings

// Its possible we have no idea, so go with 8 bits in that case
if(maxValue > 0)
if(maxvalue > 0)
{
// Figure out the number of bits needed to encode the maximum value
minbitwidth = (int)ceil(log2(maxValue + 1));
minbitwidth = (int)ceil(log2(maxvalue + 1));
}
else
minbitwidth = 8;
Expand Down
6 changes: 6 additions & 0 deletions enumcreator.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class EnumCreator : public ProtocolDocumentation
//! Return the minimum number of bits needed to encode the enumeration
int getMinBitWidth(void) const {return minbitwidth;}

//! Return the maximum value used by the enumeration
int getMaximumValue(void) const {return maxvalue;}

//! Return true if this enumeration is hidden from the documentation
virtual bool isHidden (void) const Q_DECL_OVERRIDE {return hidden;}

Expand Down Expand Up @@ -159,6 +162,9 @@ class EnumCreator : public ProtocolDocumentation
//! Minimum number of bits needed to encode the enumeration
int minbitwidth;

//! Maximum value of this enumeration
int maxvalue;

//! Determines if this enum will be hidden from the documentation
bool hidden;

Expand Down
2 changes: 1 addition & 1 deletion exampleprotocol.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ efficiently encode data for little or big endian architectures.">
<Data name="mode" enum="engineModes" encodedType="unsigned8" comment="Engine control mode of operation"/>
<Data name="gain" inMemoryType="float32" array="3" comment="proportional, integral, derivative gains from RPM error to throttle" default = "0.1"/>
<Data name="maxRPM" inMemoryType="float32" encodedType="unsigned16" min="0" max="16000" comment="maximum RPM that can be commanded" default="10000"/>
<Code name="codeexample" decode="if(_pg_user->maxRPM &lt;= 0) return 0;" comment="Packet is not valid if maximum RPM is zero"/>
<Code name="codeexample" include="translation.h" decode="if(_pg_user->maxRPM &lt;= 0) return 0;" comment="Packet is not valid if maximum RPM is zero"/>

</Packet>

Expand Down
12 changes: 12 additions & 0 deletions protocolcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void ProtocolCode::clear(void)

encode.clear();
decode.clear();
include.clear();
}


Expand Down Expand Up @@ -55,6 +56,8 @@ void ProtocolCode::parse(void)
decode = attr.value().trimmed();
else if(attrname.compare("comment", Qt::CaseInsensitive) == 0)
comment = attr.value().trimmed();
else if(attrname.compare("include", Qt::CaseInsensitive) == 0)
include = attr.value().trimmed();
else if(support.disableunrecognized == false)
emitWarning("Unrecognized attribute \"" + attrname + "\"");

Expand Down Expand Up @@ -124,3 +127,12 @@ QString ProtocolCode::getDecodeString(bool isBigEndian, int* bitcount, bool isSt
return output;
}


//! Return the include directives that go into source code needed for this encodable
void ProtocolCode::getSourceIncludeDirectives(QStringList& list) const
{
if(!include.isEmpty())
list.append(include);
}


4 changes: 4 additions & 0 deletions protocolcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class ProtocolCode : public Encodable
//! Return the string that is used to declare this encodable
virtual QString getDeclaration(void) const Q_DECL_OVERRIDE {return QString();}

//! Return the include directives that go into source code needed for this encodable
virtual void getSourceIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;

//! Return the signature of this field in an encode function signature
virtual QString getEncodeSignature(void) const Q_DECL_OVERRIDE {return QString();}

Expand Down Expand Up @@ -97,6 +100,7 @@ class ProtocolCode : public Encodable
protected:
QString encode;
QString decode;
QString include;
};

#endif // PROTOCOLCODE_H
36 changes: 25 additions & 11 deletions protocolfield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ TypeData::TypeData(ProtocolSupport sup) :
isStruct(false),
isSigned(false),
isBitfield(false),

isFloat(false),
isEnum(false),
isString(false),
isFixedString(false),
isNull(false),
bits(8),
sigbits(0),
enummax(0),
support(sup)
{
}
Expand All @@ -39,6 +39,7 @@ TypeData::TypeData(const TypeData& that) :
isNull(that.isNull),
bits(that.bits),
sigbits(that.sigbits),
enummax(that.enummax),
support(that.support)
{
}
Expand All @@ -60,6 +61,7 @@ void TypeData::clear(void)
isNull = false;
bits = 8;
sigbits = 0;
enummax = 0;
}


Expand Down Expand Up @@ -218,6 +220,10 @@ double TypeData::getMaximumFloatValue(void) const
{
if(isString || isStruct)
return 0;
else if(isEnum)
{
return enummax;
}
else if(isFloat)
{
// Float encodings use float rules
Expand Down Expand Up @@ -286,6 +292,10 @@ uint64_t TypeData::getMaximumIntegerValue(void) const
{
if(isString || isStruct)
return 0;
else if(isEnum)
{
return enummax;
}
else if(isFloat)
{
return (uint64_t)getMaximumFloatValue();
Expand Down Expand Up @@ -1074,11 +1084,15 @@ void ProtocolField::parse(void)
else
{
int minbits = 8;
inMemoryType.enummax = 255;

// Figure out the minimum number of bits for the enumeration
const EnumCreator* creator = parser->lookUpEnumeration(enumName);
if(creator != 0)
{
minbits = creator->getMinBitWidth();
inMemoryType.enummax = creator->getMaximumValue();
}

if(encodedTypeString.isEmpty())
{
Expand Down Expand Up @@ -1392,7 +1406,7 @@ void ProtocolField::parse(void)
// scaler or maxString.
if(!minString.isEmpty())
{
encodedMin = ShuntingYard::computeInfix(minString, &ok);
encodedMin = ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(minString), &ok);

if(!ok)
{
Expand All @@ -1414,7 +1428,7 @@ void ProtocolField::parse(void)
// is specified then one will be computed based on maxString.
if(!maxString.isEmpty())
{
encodedMax = ShuntingYard::computeInfix(maxString, &ok);
encodedMax = ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(maxString), &ok);
if(!ok)
{
emitWarning("max is not a number, 1.0 assumed");
Expand Down Expand Up @@ -1472,7 +1486,7 @@ void ProtocolField::parse(void)
// produce the encoded value. Unlike minString and maxString it can
// apply even if the encodedType is floating point. Hence it is
// possible for encodedMax to be 0 while the scaler is not 1.0.
scaler = ShuntingYard::computeInfix(scalerString, &ok);
scaler = ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(scalerString), &ok);

if(!ok)
{
Expand Down Expand Up @@ -1608,7 +1622,7 @@ void ProtocolField::parse(void)
else if(!verifyMaxString.isEmpty())
{
// Compute the verify max value if we can
verifyMaxValue = ShuntingYard::computeInfix(verifyMaxString, &hasVerifyMaxValue);
verifyMaxValue = ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(verifyMaxString), &hasVerifyMaxValue);
}

// Now handle the verify minimum value
Expand All @@ -1620,7 +1634,7 @@ void ProtocolField::parse(void)
else if(!verifyMinString.isEmpty())
{
// Compute the verify min value if we can
verifyMinValue = ShuntingYard::computeInfix(verifyMinString, &hasVerifyMinValue);
verifyMinValue = ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(verifyMinString), &hasVerifyMinValue);
}

// Support the case where a numeric string uses "pi" or "e".
Expand Down Expand Up @@ -2046,7 +2060,7 @@ void ProtocolField::getDocumentationDetails(QList<int>& outline, QString& startB
return;

// See if we can replace any enumeration names with values
parser->replaceEnumerationNameWithValue(maxEncodedLength);
maxEncodedLength = parser->replaceEnumerationNameWithValue(maxEncodedLength);

// The byte after this one
QString nextStartByte = EncodedLength::collapseLengthString(startByte + "+" + maxEncodedLength);
Expand Down Expand Up @@ -3574,8 +3588,8 @@ QString ProtocolField::getLimitedArgument(QString argument) const
maxstring = verifyMaxString;
}

// Now check if this max value is less than the in-Memory maximum. If it is then we must apply the max limit
if(maxvalue < inMemoryType.getMaximumFloatValue())
// Now check if this max value is less than the in-Memory maximum. If it is then we must apply the max limit. We allow one lsb of fiddle.
if(std::nextafter(maxvalue, DBL_MAX) < inMemoryType.getMaximumFloatValue())
skipmax = false;

}// else if we can evaluate the verify value
Expand All @@ -3596,8 +3610,8 @@ QString ProtocolField::getLimitedArgument(QString argument) const
minstring = verifyMinString;
}

// Now check if this min value is more than the in-Memory minimum. If it is then we must apply the min limit
if(minvalue > inMemoryType.getMinimumFloatValue())
// Now check if this min value is more than the in-Memory minimum. If it is then we must apply the min limit. We allow one lsb of fiddle.
if(std::nextafter(minvalue, -DBL_MAX) > inMemoryType.getMinimumFloatValue())
skipmin = false;

}// else if we can evaluate the verify value
Expand Down
1 change: 1 addition & 0 deletions protocolfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TypeData
bool isNull; //!< true if type is null, i.e not in memory OR not encoded
int bits; //!< number of bits used by type
int sigbits; //!< number of bits for the significand of a float16 or float24
int enummax; //!< maximum value of the enumeration if isEnum is true

//! Pull a positive integer value from a string
static int extractPositiveInt(const QString& string, bool* ok = 0);
Expand Down
18 changes: 6 additions & 12 deletions protocolpacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,8 @@ void ProtocolPacket::parse(void)
// Warning about maximum data size, only applies to packets
if(support.maxdatasize > 0)
{
// The length strings, which may include enumerated identiers such as "N3D"
QString maxLength = encodedLength.maxEncodedLength;

// Replace any defined enumerations with their actual value
parser->replaceEnumerationNameWithValue(maxLength);

// maxdatasize will be zero if the length string cannot be computed
int maxdatasize = (int)(ShuntingYard::computeInfix(maxLength) + 0.5);
int maxdatasize = (int)(ShuntingYard::computeInfix(parser->replaceEnumerationNameWithValue(encodedLength.maxEncodedLength)) + 0.5);

// Warn the user if the packet might be too big
if(maxdatasize > support.maxdatasize)
Expand Down Expand Up @@ -1189,7 +1183,7 @@ QString ProtocolPacket::getTopLevelMarkdown(bool global, const QStringList& pack
if(!ids.at(0).isEmpty())
{
// In case the packet identifer is an enumeration we know
parser->replaceEnumerationNameWithValue(idvalue);
idvalue = parser->replaceEnumerationNameWithValue(idvalue);

if(id.compare(idvalue) == 0)
output += "- packet identifier: `" + id + "`\n";
Expand Down Expand Up @@ -1220,7 +1214,7 @@ QString ProtocolPacket::getTopLevelMarkdown(bool global, const QStringList& pack
QString idvalue = id;

// In case the packet identifer is an enumeration we know
parser->replaceEnumerationNameWithValue(idvalue);
idvalue = parser->replaceEnumerationNameWithValue(idvalue);

// Put the link here in this case
if(id.compare(idvalue) == 0)
Expand All @@ -1239,7 +1233,7 @@ QString ProtocolPacket::getTopLevelMarkdown(bool global, const QStringList& pack
QString minLength = EncodedLength::collapseLengthString(encodedLength.minEncodedLength, true).replace("1*", "");

// Replace any defined enumerations with their actual value
parser->replaceEnumerationNameWithValue(minLength);
minLength = parser->replaceEnumerationNameWithValue(minLength);

// Re-collapse, perhaps we can solve it now
minLength = EncodedLength::collapseLengthString(minLength, true);
Expand All @@ -1256,8 +1250,8 @@ QString ProtocolPacket::getTopLevelMarkdown(bool global, const QStringList& pack
QString minLength = EncodedLength::collapseLengthString(encodedLength.minEncodedLength, true).replace("1*", "");

// Replace any defined enumerations with their actual value
parser->replaceEnumerationNameWithValue(maxLength);
parser->replaceEnumerationNameWithValue(minLength);
maxLength = parser->replaceEnumerationNameWithValue(maxLength);
minLength = parser->replaceEnumerationNameWithValue(minLength);

// Re-collapse, perhaps we can solve it now
maxLength = EncodedLength::collapseLengthString(maxLength, true);
Expand Down
Loading

0 comments on commit b7068e1

Please sign in to comment.