added support for templates and sets of DataFields, simplified DataField creation, added missing bounds checks

This commit is contained in:
john30
2014-11-20 09:23:54 +01:00
parent 264ba1ca51
commit 5f922f8970
3 changed files with 724 additions and 406 deletions
+237 -85
View File
@@ -68,34 +68,26 @@ typedef struct {
} dataType_t;
class SingleDataField;
/**
* @brief Base class for all kinds of data fields.
*/
class DataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param partType the message part in which the field is stored.
* @param offset the relatvie offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param dataType the data type definition.
* @param unit the value unit.
* @param comment the field comment.
*/
DataField(const std::string name, const PartType partType,
const unsigned char offset, const unsigned char length,
const dataType_t dataType, const std::string unit,
const std::string comment)
: m_name(name), m_partType(partType), m_offset(offset),
m_length(length), m_dataType(dataType), m_unit(unit),
m_comment(comment) {}
DataField(const std::string name, const std::string comment)
: m_name(name), m_comment(comment) {}
/**
* @brief Destructor.
*/
virtual ~DataField() {}
/**
* @brief Factory method for creating new instances.
* @param it the iterator to traverse for the definition parts.
@@ -108,9 +100,103 @@ public:
* Note: the caller needs to cleanup created instances.
*/
static result_t create(std::vector<std::string>::iterator& it, const std::vector<std::string>::iterator end,
const std::map<std::string, DataField*> templates, std::vector<DataField*>& fields,
const std::map< std::string, DataField*> templates, DataField*& fields,
const bool isSetMessage=false, const unsigned char dstAddress=SYN);
/**
* @brief Returns the offset to the first symbol in the message part for a field following this field.
* @return the offset to the first symbol in the message part for a field following this field.
*/
virtual unsigned char getNextOffset() = 0;
/**
* @brief Derives a new DataField from this field.
* @param name the field name.
* @param comment the field comment, or empty to use this fields comment.
* @param unit the value unit, or empty to use this fields unit (if applicable).
* @param partType the message part in which the field is stored.
* @param offset the (additional) offset to the first symbol in the message part in which the field is stored.
* @param divisor the extra divisor to apply on the value, or 1 for none (if applicable).
* @param values the value=text assignments, or empty to use this fields assignments (if applicable).
*/
virtual result_t derive(std::string name, std::string comment,
std::string unit, const PartType partType, unsigned char offset,
unsigned int divisor, std::map<unsigned int, std::string> values,
std::vector<SingleDataField*>& fields) = 0;
/**
* @brief Get the field name.
* @return the field name.
*/
const std::string getName() { return m_name; }
/**
* @brief Get the field comment.
* @return the field comment.
*/
const std::string getComment() { return m_comment; }
/**
* @brief Reads the value from the master or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
* @param slaveData the unescaped slave data @a SymbolString for reading binary data.
* @param output the ostringstream to append the formatted value to.
* @param verbose whether to prepend the name, append the unit (if present), and append
* the comment in square brackets (if present).
* @param separator the separator character between multiple fields.
* @return RESULT_OK on success, or an error code.
*/
virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output,
bool verbose=false, char separator=';') = 0;
/**
* @brief Writes the value to the master or slave @a SymbolString.
* @param input the istringstream to parse the formatted value from.
* @param masterData the unescaped master data @a SymbolString for writing binary data.
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @param separator the separator character between multiple fields.
* @return RESULT_OK on success, or an error code.
*/
virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData,
char separator=';') = 0;
protected:
/** the field name. */
const std::string m_name;
/** the field comment. */
const std::string m_comment;
};
/**
* @brief A single DataField.
*/
class SingleDataField : public DataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param unit the value unit.
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param offset the offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
*/
SingleDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char offset, const unsigned char length)
: DataField(name, comment),
m_unit(unit), m_dataType(dataType), m_partType(partType),
m_offset(offset), m_length(length) {}
/**
* @brief Destructor.
*/
virtual ~SingleDataField() {}
/**
* @brief Get the value unit.
* @return the value unit.
*/
const std::string getUnit() { return m_unit; }
virtual unsigned char getNextOffset();
/**
* @brief Reads the value from the master or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
@@ -120,8 +206,8 @@ public:
* the comment in square brackets (if present).
* @return RESULT_OK on success, or an error code.
*/
result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output,
bool verbose=false);
virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output,
bool verbose=false, char separator=';');
/**
* @brief Writes the value to the master or slave @a SymbolString.
* @param input the istringstream to parse the formatted value from.
@@ -129,29 +215,11 @@ public:
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @return RESULT_OK on success, or an error code.
*/
result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData);
/**
* @brief Get the field name.
* @return the field name.
*/
const std::string getName() { return m_name; }
/**
* @brief Get the value unit.
* @return the value unit.
*/
const std::string getUnit() { return m_unit; }
/**
* @brief Get the field comment.
* @return the field comment.
*/
const std::string getComment() { return m_comment; }
virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData,
char separator=';');
protected:
virtual DataField* derive(std::string name, PartType partType, unsigned char offset, std::string unit,
std::string comment, unsigned int divisor, std::map<unsigned int, std::string> values) = 0;
/**
* @brief Internal method for reading the field from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from.
@@ -167,52 +235,52 @@ protected:
*/
virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) = 0;
/** the field name. */
const std::string m_name;
/** the value unit. */
const std::string m_unit;
/** the data type definition. */
const dataType_t m_dataType;
/** the message part in which the field is stored. */
const PartType m_partType;
/** the relative offset to the first symbol in the message part in which the field is stored. */
const unsigned char m_offset;
/** the number of symbols in the message part in which the field is stored. */
const unsigned char m_length;
/** the data type definition. */
const dataType_t m_dataType;
/** the value unit. */
const std::string m_unit;
/** the field comment. */
const std::string m_comment;
};
/**
* @brief Base class for all string based data fields.
*/
class StringDataField : public DataField
class StringDataField : public SingleDataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param unit the value unit.
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param offset the offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param dataType the data type definition.
* @param unit the value unit.
* @param comment the field comment.
*/
StringDataField(const std::string name, const PartType partType,
const unsigned char offset, const unsigned char length,
const dataType_t dataType, const std::string unit,
const std::string comment)
: DataField(name, partType, offset, length, dataType, unit, comment) {}
StringDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char offset, const unsigned char length)
: SingleDataField(name, comment, unit, dataType, partType, offset, length) {}
/**
* @brief Destructor.
*/
virtual ~StringDataField() {}
virtual result_t derive(std::string name, std::string comment,
std::string unit, const PartType partType, unsigned char offset,
unsigned int divisor, std::map<unsigned int, std::string> values,
std::vector<SingleDataField*>& fields);
protected:
virtual DataField* derive(std::string name, PartType partType, unsigned char offset, std::string unit,
std::string comment, unsigned int divisor, std::map<unsigned int, std::string> values);
virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output);
virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output);
@@ -222,32 +290,34 @@ protected:
/**
* @brief Base class for all numeric data fields.
*/
class NumericDataField : public DataField
class NumericDataField : public SingleDataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param unit the value unit.
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param offset the offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param bitOffset the offset to the first bit in the binary value.
* @param dataType the data type definition.
* @param unit the value unit.
* @param comment the field comment.
*/
NumericDataField(const std::string name, const PartType partType,
NumericDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char offset, const unsigned char length,
const dataType_t dataType, const std::string unit,
const std::string comment, const unsigned char bitOffset)
: DataField(name, partType, offset, length, dataType, unit, comment),
m_bitOffset(bitOffset) {}
const unsigned char bitOffset)
: SingleDataField(name, comment, unit, dataType, partType, offset, length),
m_bitOffset(bitOffset) {}
/**
* @brief Destructor.
*/
virtual ~NumericDataField() {}
protected:
/**
* @brief Internal method for reading the raw value from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from.
@@ -268,38 +338,43 @@ protected:
};
/**
* @brief Base class for all numeric data fields with a number representation.
*/
class NumberDataField : public NumericDataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param unit the value unit.
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param offset the offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param dataType the data type definition.
* @param unit the value unit.
* @param comment the field comment.
* @param divisor the extra divisor to apply on the value, or 1 for none.
*/
NumberDataField(const std::string name, const PartType partType,
NumberDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char offset, const unsigned char length,
const dataType_t dataType, const std::string unit,
const std::string comment, const unsigned int divisor)
: NumericDataField(name, partType, offset, length, dataType, unit, comment,
const unsigned int divisor)
: NumericDataField(name, comment, unit, dataType, partType, offset, length,
(dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0),
m_divisor(divisor) {}
m_divisor(divisor) {}
/**
* @brief Destructor.
*/
virtual ~NumberDataField() {}
protected:
virtual DataField* derive(std::string name, PartType partType, unsigned char offset, std::string unit,
std::string comment, unsigned int divisor, std::map<unsigned int, std::string> values);
virtual result_t derive(std::string name, std::string comment,
std::string unit, const PartType partType, unsigned char offset,
unsigned int divisor, std::map<unsigned int, std::string> values,
std::vector<SingleDataField*>& fields);
virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output);
virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output);
@@ -308,38 +383,43 @@ protected:
};
/**
* @brief A numeric data field with a list of value=text assignments and a string representation.
*/
class ValueListDataField : public NumericDataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param unit the value unit.
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param offset the offset to the first symbol in the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param dataType the data type definition.
* @param unit the value unit.
* @param comment the field comment.
* @param values the value=text assignments.
*/
ValueListDataField(const std::string name, const PartType partType,
ValueListDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char offset, const unsigned char length,
const dataType_t dataType, const std::string unit,
const std::string comment, const std::map<unsigned int, std::string> values)
:NumericDataField(name, partType, offset, length, dataType, unit, comment,
const std::map<unsigned int, std::string> values)
: NumericDataField(name, comment, unit, dataType, partType, offset, length,
(dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0),
m_values(values) {}
m_values(values) {}
/**
* @brief Destructor.
*/
virtual ~ValueListDataField() {}
protected:
virtual DataField* derive(std::string name, PartType partType, unsigned char offset, std::string unit,
std::string comment, unsigned int divisor, std::map<unsigned int, std::string> values);
virtual result_t derive(std::string name, std::string comment,
std::string unit, const PartType partType, unsigned char offset,
unsigned int divisor, std::map<unsigned int, std::string> values,
std::vector<SingleDataField*>& fields);
virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output);
virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output);
@@ -349,6 +429,78 @@ protected:
};
/**
* @brief A set of DataFields.
*/
class DataFieldSet : public DataField
{
public:
/**
* @brief Constructs a new instance.
* @param name the field name.
* @param comment the field comment.
* @param fields the list of SingleDataFields part of this set.
*/
DataFieldSet(const std::string name, const std::string comment,
const std::vector<SingleDataField*> fields)
: DataField(name, comment),
m_fields(fields) {}
/**
* @brief Destructor.
*/
virtual ~DataFieldSet();
virtual unsigned char getNextOffset();
virtual result_t derive(std::string name, std::string comment,
std::string unit, const PartType partType, unsigned char offset,
unsigned int divisor, std::map<unsigned int, std::string> values,
std::vector<SingleDataField*>& fields);
/**
* @brief Returns the SingleDataField at the specified index.
* @param index the index of the SingleDataField to return.
* @return the SingleDataField at the specified index, or NULL.
*/
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) return NULL; return m_fields[index]; }
/**
* @brief Returns the SingleDataField at the specified index.
* @param index the index of the SingleDataField to return.
* @return the SingleDataField at the specified index, or NULL.
*/
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) return NULL; return m_fields[index]; }
/**
* @brief Returns the number of SingleDataFields in this set.
* @return the number of available SingleDataField.
*/
size_t size() const { return m_fields.size(); }
/**
* @brief Reads the values from the master and/or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
* @param slaveData the unescaped slave data @a SymbolString for reading binary data.
* @param output the ostringstream to append the formatted value to.
* @param vervose whether to prepend the name, append the unit (if present), and append
* the comment in square brackets (if present).
* @return RESULT_OK on success, or an error code.
*/
virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output,
bool verbose=false, char separator=';');
/**
* @brief Writes the values to the master and/or slave @a SymbolString.
* @param input the istringstream to parse the formatted value from.
* @param masterData the unescaped master data @a SymbolString for writing binary data.
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @return RESULT_OK on success, or an error code.
*/
virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData,
char separator=';');
protected:
/** the list of SingleDataFields part of this set. */
std::vector<SingleDataField*> m_fields;
};
} //namespace
#endif // LIBEBUS_DATA_H_