From 1fec0f693cef847930a25b2920ad2143bebd6861 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 10 Dec 2016 23:51:10 +0100 Subject: [PATCH] added constant value data types --- src/lib/ebus/data.cpp | 96 ++++++++++++++++++++++++++++-- src/lib/ebus/data.h | 68 ++++++++++++++++++++- src/lib/ebus/datatype.h | 1 + src/lib/ebus/test/test_data.cpp | 12 ++++ src/lib/ebus/test/test_message.cpp | 4 ++ 5 files changed, 176 insertions(+), 5 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 859bbe97..aab820ab 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -101,11 +101,21 @@ result_t DataField::create(vector::iterator& it, } map values; + string constantValue; + bool verifyValue = false; if (it != end) { const string divisorStr = *it++; // [divisor|values] if (!divisorStr.empty()) { - if (divisorStr.find('=') == string::npos) { + size_t equalPos = divisorStr.find('='); + if (equalPos == string::npos) { divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result); + } else if (equalPos == 0 && divisorStr.length() > 1) { + verifyValue = divisorStr[1]=='='; // == forced verification of constant value + if (verifyValue && divisorStr.length() == 1) { + result = RESULT_ERR_INVALID_LIST; + break; + } + constantValue = divisorStr.substr(equalPos+(verifyValue?2:1)); } else { istringstream stream(divisorStr); while (getline(stream, token, VALUE_SEPARATOR)) { @@ -190,12 +200,14 @@ result_t DataField::create(vector::iterator& it, } transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper); SingleDataField* add = NULL; - result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, add); + result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, constantValue, verifyValue, add); if (add != NULL) { fields.push_back(add); } else if (result == RESULT_OK) { result = RESULT_ERR_NOTFOUND; // type not found } + } else if (!constantValue.empty()) { + result = RESULT_ERR_INVALID_ARG; // invalid value list } else { // template[:name] string fieldName; bool lastType = stream.eof(); @@ -241,7 +253,7 @@ void DataField::dumpString(ostream& output, const string str, const bool prepend result_t SingleDataField::create(const string id, const unsigned char length, const string name, const string comment, const string unit, const PartType partType, int divisor, map values, - SingleDataField* &returnField) + const string constantValue, const bool verifyValue, SingleDataField* &returnField) { DataType* dataType = DataTypeList::getInstance()->get(id, length==REMAIN_LEN ? (unsigned char)0 : length); if (!dataType) { @@ -268,6 +280,10 @@ result_t SingleDataField::create(const string id, const unsigned char length, return RESULT_ERR_OUT_OF_RANGE; // invalid length } } + if (!constantValue.empty()) { + returnField = new ConstantDataField(name, comment, unit, dataType, partType, byteCount, constantValue, verifyValue); + return RESULT_OK; + } if (dataType->isNumeric()) { NumberDataType* numType = (NumberDataType*)dataType; if (values.empty() && numType->hasFlag(DAY)) { @@ -285,7 +301,6 @@ result_t SingleDataField::create(const string id, const unsigned char length, if (values.begin()->first < numType->getMinValue() || values.rbegin()->first > numType->getMaxValue()) { return RESULT_ERR_OUT_OF_RANGE; } - //TODO add special field for fixed values (exactly one value in the list of values) returnField = new ValueListDataField(name, comment, unit, numType, partType, byteCount, values); return RESULT_OK; } @@ -621,6 +636,79 @@ result_t ValueListDataField::writeSymbols(istringstream& input, } +ConstantDataField* ConstantDataField::clone() +{ + return new ConstantDataField(*this); +} + +result_t ConstantDataField::derive(string name, string comment, + string unit, const PartType partType, + int divisor, map values, + vector& fields) +{ + if (m_partType != pt_any && partType == pt_any) + return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance + if (name.empty()) + name = m_name; + if (comment.empty()) + comment = m_comment; + if (unit.empty()) + unit = m_unit; + if (divisor != 0) + return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field + if (!values.empty()) { + return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field + } + fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify)); + + return RESULT_OK; +} + +void ConstantDataField::dump(ostream& output) +{ + output << setw(0) << dec; // initialize formatting + dumpString(output, m_name, false); + output << FIELD_SEPARATOR; + if (m_partType == pt_masterData) + output << "m"; + else if (m_partType == pt_slaveData) + output << "s"; + output << FIELD_SEPARATOR; + if (!m_dataType->dump(output, m_length)) { // no divisor appended + output << (m_verify?"==":"=") << m_value; + } // else: impossible since divisor is not allowed for ConstantDataField + dumpString(output, m_unit); + dumpString(output, m_comment); +} + +result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster, + const unsigned char offset, + ostringstream& output, OutputFormat outputFormat) +{ + ostringstream coutput; + result_t result = SingleDataField::readSymbols(input, isMaster, offset, coutput, 0); + if (result != RESULT_OK) { + return result; + } + if (m_verify) { + string value = coutput.str(); + FileReader::trim(value); + if (value!=m_value) { + return RESULT_ERR_OUT_OF_RANGE; + } + } + return RESULT_OK; +} + +result_t ConstantDataField::writeSymbols(istringstream& input, + const unsigned char offset, + SymbolString& output, const bool isMaster, unsigned char* usedLength) +{ + istringstream cinput(m_value); + return SingleDataField::writeSymbols(cinput, offset, output, isMaster, usedLength); +} + + DataFieldSet* DataFieldSet::s_identFields = NULL; DataFieldSet* DataFieldSet::getIdentFields() diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 3b2071c0..f2b5905b 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -256,6 +256,8 @@ class SingleDataField : public DataField * @param partType the message part in which the field is stored. * @param divisor the extra divisor (negative for reciprocal) to apply on the value, or 1 for none (if applicable). * @param values the value=text assignments. + * @param constantValue the constant value as string, or empty. + * @param verifyValue whether to verify the read value against the constant value. * @param returnField the variable in which the created @a SingleDataField instance shall be stored. * @return @a RESULT_OK on success, or an error code. * Note: the caller needs to free the created instance. @@ -263,7 +265,7 @@ class SingleDataField : public DataField static result_t create(const string id, const unsigned char length, const string name, const string comment, const string unit, const PartType partType, int divisor, map values, - SingleDataField* &returnField); + const string constantValue, const bool verifyValue, SingleDataField* &returnField); /** * Get the value unit. @@ -427,6 +429,70 @@ class ValueListDataField : public SingleDataField }; +/** + * A data field with a constant value. + */ +class ConstantDataField : public SingleDataField +{ +public: + + /** + * 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 length the number of symbols in the message part in which the field is stored. + * @param value the constant value. + * @param verify whether to verify the read value against the constant value. + */ + ConstantDataField(const string name, const string comment, + const string unit, DataType* dataType, const PartType partType, + const unsigned char length, const string value, const bool verify) + : SingleDataField(name, comment, unit, dataType, partType, length), + m_value(value), m_verify(verify) {} + + /** + * Destructor. + */ + virtual ~ConstantDataField() {} + + // @copydoc + virtual ConstantDataField* clone(); + + // @copydoc + virtual result_t derive(string name, string comment, + string unit, const PartType partType, int divisor, + map values, + vector& fields); + + // @copydoc + virtual void dump(ostream& output); + +protected: + + // @copydoc + virtual result_t readSymbols(SymbolString& input, const bool isMaster, + const unsigned char offset, + ostringstream& output, OutputFormat outputFormat); + + // @copydoc + virtual result_t writeSymbols(istringstream& input, + const unsigned char offset, + SymbolString& output, const bool isMaster, unsigned char* usedLength); + +private: + + /** the constant value. */ + const string m_value; + + /** whether to verify the read value against the constant value. */ + const bool m_verify; + +}; + + /** * A set of @a DataField instances. */ diff --git a/src/lib/ebus/datatype.h b/src/lib/ebus/datatype.h index 9331d275..a76b9da5 100644 --- a/src/lib/ebus/datatype.h +++ b/src/lib/ebus/datatype.h @@ -103,6 +103,7 @@ static const unsigned int EXP = 0x100; //!< exponential numeric representation static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType static const unsigned int SPE = 0x800; //!< special marker for certain types +static const unsigned int CON = 0x1000; //!< marker for a constant value /** diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index d36d7844..63ebff89 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -62,6 +62,10 @@ int main() {"x,,str:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778", "00", ""}, {"x,,str:*", "abcde", "10fe0700056162636465", "00", ""}, {"x,,str,2", "", "", "", "c"}, + {"x,,str:10,=dummy", "", "10fe07000a48616c6c6f2044752120", "00", "W"}, + {"x,,str:10,==dummy", "", "10fe07000a48616c6c6f2044752120", "00", "rW"}, + {"x,,str:10,=dummy", "", "10fe07000a64756d6d792020202020", "00", ""}, + {"x,,str:10,==dummy", "", "10fe07000a64756d6d792020202020", "00", ""}, {"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, {"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, {"x,,nts:10", "Hallo, Du", "10fe07000a48616c6c6f2c20447500", "00", ""}, @@ -78,6 +82,10 @@ int main() {"x,,hex:*", "48 61 6c 6c 6f", "10fe07000548616c6c6f", "00", ""}, {"x,,hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, {"x,,hex,2", "", "", "", "c"}, + {"x,,hex:5,=48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "W"}, + {"x,,hex:5,==48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"}, + {"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""}, + {"x,,hex:5,==48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""}, {"x,,bda", "26.10.2014","10fe07000426100614", "00", ""}, // Sunday {"x,,bda", "01.01.2000","10fe07000401010500", "00", ""}, // Saturday {"x,,bda", "31.12.2099","10fe07000431120399", "00", ""}, // Thursday @@ -255,6 +263,10 @@ int main() {"x,,uch", "-", "10feffff01ff", "00", ""}, {"x,,uch,10", "3.8", "10feffff0126", "00", ""}, {"x,,uch,-10", "380","10feffff0126", "00", ""}, + {"x,,uch,=48", "", "10feffff01ab", "00", "W"}, + {"x,,uch,==48", "", "10feffff01ab", "00", "rW"}, + {"x,,uch,=48", "", "10feffff0130", "00", ""}, + {"x,,uch,==48", "", "10feffff0130", "00", ""}, {"x,,sch", "-90", "10feffff01a6", "00", ""}, {"x,,sch", "0", "10feffff0100", "00", ""}, {"x,,sch", "-1", "10feffff01ff", "00", ""}, diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 118d11c5..9ace336e 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -65,8 +65,10 @@ int main() {"temp2,D2B,,°C,Temperatur", "", "", "", "template"}, {"power,UCH,,kW", "", "", "", "template"}, {"sensor,UCH,0=ok;85=circuit;170=cutoff,,Fühlerstatus", "", "", "", "template"}, + {"sensorc,UCH,=85,,Fühlerstatus", "", "", "", "template"}, {"pumpstate,UCH,0=off;1=on;2=overrun,,Pumpenstatus", "", "", "", "template"}, {"tempsensor,temp;sensor,,Temperatursensor", "", "", "", "template"}, + {"tempsensorc,temp;sensorc,,Temperatursensor", "", "", "", "template"}, {"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate","28.0;24.0;4.938;35.0;41.0;4","ff08b5110101","093830f00446520400ff","d"}, {"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor", "temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, {"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, @@ -74,6 +76,8 @@ int main() {"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00, \"unit\": \"field unit\", \"comment\": \"field comment\"},\n \"sensor\": {\"value\": \"ok\", \"comment\": \"Fühlerstatus\"}", "ff25b509030d2800", "0320ff00", "mJ"}, {"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, {"r,message circuit,message name,message comment,,25,B509,0d2800,,,D2C,,°C,Temperatur,,,sensor", "\n \"0\": {\"name\": \"\", \"value\": -14.00},\n \"1\": {\"name\": \"sensor\", \"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"}, + {"r,,name,,,25,B509,0d2800,,,tempsensorc", "-14.00", "ff25b509030d2800", "0320ff55", "m"}, + {"r,,name,,,25,B509,0d28,,m,sensorc,,,,,,temp", "-14.00", "ff25b509030d2855", "0220ff", "m"}, {"u,,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"}, {"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""}, {"w,,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", "m"},