diff --git a/README.md b/README.md
index 8db655c..9deefd6 100644
--- a/README.md
+++ b/README.md
@@ -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
----------
diff --git a/encodable.h b/encodable.h
index 66a55ae..f27b48f 100644
--- a/encodable.h
+++ b/encodable.h
@@ -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);}
diff --git a/enumcreator.cpp b/enumcreator.cpp
index 00a97f4..be8b110 100644
--- a/enumcreator.cpp
+++ b/enumcreator.cpp
@@ -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),
@@ -122,6 +123,7 @@ void EnumCreator::clear(void)
filepath.clear();
sourceOutput.clear();
minbitwidth = 0;
+ maxvalue = 0;
hidden = false;
lookup = false;
lookupTitle = false;
@@ -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;
@@ -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);
@@ -549,8 +551,8 @@ 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;
@@ -558,10 +560,10 @@ void EnumCreator::computeNumberList(void)
}// 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;
diff --git a/enumcreator.h b/enumcreator.h
index a340c0b..8d53345 100644
--- a/enumcreator.h
+++ b/enumcreator.h
@@ -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;}
@@ -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;
diff --git a/exampleprotocol.xml b/exampleprotocol.xml
index daeb19b..47effb5 100644
--- a/exampleprotocol.xml
+++ b/exampleprotocol.xml
@@ -182,7 +182,7 @@ efficiently encode data for little or big endian architectures.">
-
+
diff --git a/protocolcode.cpp b/protocolcode.cpp
index a25dad5..56d329c 100644
--- a/protocolcode.cpp
+++ b/protocolcode.cpp
@@ -21,6 +21,7 @@ void ProtocolCode::clear(void)
encode.clear();
decode.clear();
+ include.clear();
}
@@ -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 + "\"");
@@ -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);
+}
+
+
diff --git a/protocolcode.h b/protocolcode.h
index 7d2894f..208ec92 100644
--- a/protocolcode.h
+++ b/protocolcode.h
@@ -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();}
@@ -97,6 +100,7 @@ class ProtocolCode : public Encodable
protected:
QString encode;
QString decode;
+ QString include;
};
#endif // PROTOCOLCODE_H
diff --git a/protocolfield.cpp b/protocolfield.cpp
index d37b534..6763263 100644
--- a/protocolfield.cpp
+++ b/protocolfield.cpp
@@ -14,7 +14,6 @@ TypeData::TypeData(ProtocolSupport sup) :
isStruct(false),
isSigned(false),
isBitfield(false),
-
isFloat(false),
isEnum(false),
isString(false),
@@ -22,6 +21,7 @@ TypeData::TypeData(ProtocolSupport sup) :
isNull(false),
bits(8),
sigbits(0),
+ enummax(0),
support(sup)
{
}
@@ -39,6 +39,7 @@ TypeData::TypeData(const TypeData& that) :
isNull(that.isNull),
bits(that.bits),
sigbits(that.sigbits),
+ enummax(that.enummax),
support(that.support)
{
}
@@ -60,6 +61,7 @@ void TypeData::clear(void)
isNull = false;
bits = 8;
sigbits = 0;
+ enummax = 0;
}
@@ -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
@@ -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();
@@ -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())
{
@@ -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)
{
@@ -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");
@@ -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)
{
@@ -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
@@ -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".
@@ -2046,7 +2060,7 @@ void ProtocolField::getDocumentationDetails(QList& 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);
@@ -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
@@ -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
diff --git a/protocolfield.h b/protocolfield.h
index d584118..42afa3b 100644
--- a/protocolfield.h
+++ b/protocolfield.h
@@ -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);
diff --git a/protocolpacket.cpp b/protocolpacket.cpp
index 263d940..b9fa844 100644
--- a/protocolpacket.cpp
+++ b/protocolpacket.cpp
@@ -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)
@@ -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";
@@ -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)
@@ -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);
@@ -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);
diff --git a/protocolparser.cpp b/protocolparser.cpp
index 839dd58..e3b4c08 100644
--- a/protocolparser.cpp
+++ b/protocolparser.cpp
@@ -17,7 +17,7 @@
#include
// The version of the protocol generator is set here
-const QString ProtocolParser::genVersion = "2.21.a";
+const QString ProtocolParser::genVersion = "2.22.b";
/*!
* \brief ProtocolParser::ProtocolParser
@@ -1122,22 +1122,24 @@ const EnumCreator* ProtocolParser::lookUpEnumeration(const QString& enumName) co
/*!
* Replace any text that matches an enumeration name with the value of that enumeration
- * \param text is modified to replace names with numbers
- * \return a reference to text
+ * \param text is the source text to search, which won't be modified
+ * \return A new string that replaces any enumeration names with the value of the enumeration
*/
-QString& ProtocolParser::replaceEnumerationNameWithValue(QString& text) const
+QString ProtocolParser::replaceEnumerationNameWithValue(const QString& text) const
{
+ QString replace = text;
+
for(int i = 0; i < globalEnums.size(); i++)
{
- globalEnums.at(i)->replaceEnumerationNameWithValue(text);
+ globalEnums.at(i)->replaceEnumerationNameWithValue(replace);
}
for(int i = 0; i < enums.size(); i++)
{
- enums.at(i)->replaceEnumerationNameWithValue(text);
+ enums.at(i)->replaceEnumerationNameWithValue(replace);
}
- return text;
+ return replace;
}
diff --git a/protocolparser.h b/protocolparser.h
index 251b18c..4972158 100644
--- a/protocolparser.h
+++ b/protocolparser.h
@@ -107,7 +107,7 @@ class ProtocolParser
const EnumCreator* lookUpEnumeration(const QString& enumName) const;
//! Replace any text that matches an enumeration name with the value of that enumeration
- QString& replaceEnumerationNameWithValue(QString& text) const;
+ QString replaceEnumerationNameWithValue(const QString& text) const;
//! Determine if text is part of an enumeration.
QString getEnumerationNameForEnumValue(const QString& text) const;
diff --git a/protocolstructure.cpp b/protocolstructure.cpp
index 01044ac..f8978d1 100644
--- a/protocolstructure.cpp
+++ b/protocolstructure.cpp
@@ -582,6 +582,22 @@ void ProtocolStructure::getIncludeDirectives(QStringList& list) const
}
list.removeDuplicates();
+
+}// ProtocolStructure::getIncludeDirectives
+
+
+/*!
+ * Append the include directives in source code for this encodable. Mostly this is empty,
+ * but code encodables may have source code includes.
+ * \param list is appended with any directives this encodable requires.
+ */
+void ProtocolStructure::getSourceIncludeDirectives(QStringList& list) const
+{
+ // Includes that our encodable members may need
+ for(int i = 0; i < encodables.length(); i++)
+ encodables.at(i)->getSourceIncludeDirectives(list);
+
+ list.removeDuplicates();
}
@@ -2549,7 +2565,7 @@ void ProtocolStructure::getDocumentationDetails(QList& outline, QString& st
QString maxEncodedLength = encodedLength.maxEncodedLength;
// 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);
diff --git a/protocolstructure.h b/protocolstructure.h
index 0bba462..870ff37 100644
--- a/protocolstructure.h
+++ b/protocolstructure.h
@@ -157,6 +157,9 @@ class ProtocolStructure : public Encodable
//! Return the include directives needed for this encodable
virtual void getIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;
+ //! Return the include directives that go into source code for this encodable
+ virtual void getSourceIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;
+
//! Return the include directives needed for this encodable's init and verify functions
virtual void getInitAndVerifyIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;
diff --git a/protocolstructuremodule.cpp b/protocolstructuremodule.cpp
index 7e46a6d..ea675e1 100644
--- a/protocolstructuremodule.cpp
+++ b/protocolstructuremodule.cpp
@@ -488,13 +488,9 @@ void ProtocolStructureModule::setupFiles(QString moduleName,
verifyheaderfile->makeLineSeparator();
}
- if(support.specialFloat)
- source.writeIncludeDirective("floatspecial.h");
-
- source.writeIncludeDirective("fielddecode.h");
- source.writeIncludeDirective("fieldencode.h");
- source.writeIncludeDirective("scaleddecode.h");
- source.writeIncludeDirective("scaledencode.h");
+ list.clear();
+ getSourceIncludeDirectives(list);
+ source.writeIncludeDirectives(list);
// Outputs for the enumerations in source file, if any
for(int i = 0; i < enumList.count(); i++)
@@ -544,6 +540,27 @@ void ProtocolStructureModule::getIncludeDirectives(QStringList& list) const
}
+/*!
+ * Return the include directives that go into source code for this encodable
+ * \param list is appended with any directives for source code.
+ */
+void ProtocolStructureModule::getSourceIncludeDirectives(QStringList& list) const
+{
+ if(support.specialFloat)
+ list.append("floatspecial.h");
+
+ list.append("fielddecode.h");
+ list.append("fieldencode.h");
+ list.append("scaleddecode.h");
+ list.append("scaledencode.h");
+
+ // And any of our children's headers
+ ProtocolStructure::getSourceIncludeDirectives(list);
+
+ list.removeDuplicates();
+}
+
+
/*!
* Return the include directives needed for this encodable's init and verify functions
* \param list is appended with any directives this encodable requires.
diff --git a/protocolstructuremodule.h b/protocolstructuremodule.h
index 4c1ccf7..122b9f5 100644
--- a/protocolstructuremodule.h
+++ b/protocolstructuremodule.h
@@ -30,6 +30,9 @@ class ProtocolStructureModule : public ProtocolStructure
//! Return the include directives needed for this encodable
virtual void getIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;
+ //! Return the include directives that go into source code for this encodable
+ virtual void getSourceIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;
+
//! Return the include directives needed for this encodable's init and verify functions
virtual void getInitAndVerifyIncludeDirectives(QStringList& list) const Q_DECL_OVERRIDE;