diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 1071e983..d9edaae0 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -430,8 +430,7 @@ void SingleDataField::dump(ostream& output) result_t SingleDataField::read(const PartType partType, SymbolString& data, unsigned char offset, ostringstream& output, bool leadingSeparator, - bool verbose, const char* fieldName, signed char fieldIndex, - char separator) + DataFormat dataFormat, const char* fieldName, signed char fieldIndex) { if (partType != m_partType) return RESULT_OK; @@ -454,21 +453,38 @@ result_t SingleDataField::read(const PartType partType, return RESULT_EMPTY; } - if (leadingSeparator) - output << separator; + if (leadingSeparator) { + if (dataFormat==df_json) + output << ","; + else + output << UI_FIELD_SEPARATOR; + } - if (verbose) + if (dataFormat==df_verbose) output << m_name << "="; + else if (dataFormat==df_json) + output << "\n {\"name\": \"" << m_name << "\""; - result_t result = readSymbols(data, offset, output); + if (dataFormat==df_json) + output << ", \"value\": "; + result_t result = readSymbols(data, offset, output, dataFormat); if (result != RESULT_OK) return result; - if (verbose && m_unit.length() > 0) - output << " " << m_unit; - if (verbose && m_comment.length() > 0) - output << " [" << m_comment << "]"; - + if (m_unit.length() > 0) { + if (dataFormat==df_verbose) + output << " " << m_unit; + else if (dataFormat==df_json) + output << ", \"unit\": \"" << m_unit << '"'; + } + if (m_comment.length() > 0) { + if (dataFormat==df_verbose) + output << " [" << m_comment << "]"; + else if (dataFormat==df_json) + output << ", \"comment\": \"" << m_comment << '"'; + } + if (dataFormat==df_json) + output << "}"; return RESULT_OK; } @@ -525,8 +541,9 @@ void StringDataField::dump(ostream& output) dumpString(output, m_comment); } -result_t StringDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, ostringstream& output) +result_t StringDataField::readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat) { size_t start = 0, count = m_length; int incr = 1; @@ -541,6 +558,8 @@ result_t StringDataField::readSymbols(SymbolString& input, incr = -1; } + if (dataFormat==df_json) + output << '"'; for (size_t offset = start, i = 0; i < count; offset += incr, i++) { if (m_length == 4 && i == 2 && m_dataType.type == bt_dat) continue; // skip weekday in between @@ -614,6 +633,8 @@ result_t StringDataField::readSymbols(SymbolString& input, } last = ch; } + if (dataFormat==df_json) + output << '"'; return RESULT_OK; } @@ -940,8 +961,9 @@ void NumberDataField::dump(ostream& output) dumpString(output, m_comment); } -result_t NumberDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, ostringstream& output) +result_t NumberDataField::readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat) { unsigned int value = 0; int signedValue; @@ -953,7 +975,11 @@ result_t NumberDataField::readSymbols(SymbolString& input, output << setw(0) << dec; // initialize output if ((m_dataType.flags & REQ) == 0 && value == m_dataType.replacement) { + if (dataFormat==df_json) + output << '"'; output << NULL_VALUE; + if (dataFormat==df_json) + output << '"'; return RESULT_OK; } @@ -979,8 +1005,15 @@ result_t NumberDataField::readSymbols(SymbolString& input, if (m_divisor < 0) output << static_cast((float)signedValue * (float)(-m_divisor)); else if (m_divisor <= 1) { - if ((m_dataType.flags & (FIX|BCD)) == (FIX|BCD)) + if ((m_dataType.flags & (FIX|BCD)) == (FIX|BCD)) { + if (dataFormat==df_json) { + output << '"'; + output << setw(m_length * 2) << setfill('0'); + output << '"'; + return RESULT_OK; + } output << setw(m_length * 2) << setfill('0'); + } output << static_cast(signedValue) << setw(0); } else @@ -1098,8 +1131,9 @@ void ValueListDataField::dump(ostream& output) dumpString(output, m_comment); } -result_t ValueListDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, ostringstream& output) +result_t ValueListDataField::readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat) { unsigned int value = 0; @@ -1107,20 +1141,21 @@ result_t ValueListDataField::readSymbols(SymbolString& input, if (result != RESULT_OK) return result; - output << setw(0) << dec; // initialize output - map::iterator it = m_values.find(value); + if (it == m_values.end() && value != m_dataType.replacement) { + return RESULT_ERR_NOTFOUND; // value assignment not found + } + output << setw(0) << dec; // initialize output + if (dataFormat==df_json) + output << '"'; if (it != m_values.end()) { output << it->second; - return RESULT_OK; - } - - if (value == m_dataType.replacement) { + } else if (value == m_dataType.replacement) { output << NULL_VALUE; - return RESULT_OK; } - - return RESULT_ERR_NOTFOUND; // value assignment not found + if (dataFormat==df_json) + output << '"'; + return RESULT_OK; } result_t ValueListDataField::writeSymbols(istringstream& input, @@ -1238,8 +1273,7 @@ void DataFieldSet::dump(ostream& output) result_t DataFieldSet::read(const PartType partType, SymbolString& data, unsigned char offset, ostringstream& output, bool leadingSeparator, - bool verbose, const char* fieldName, signed char fieldIndex, - char separator) + DataFormat dataFormat, const char* fieldName, signed char fieldIndex) { bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { @@ -1250,7 +1284,7 @@ result_t DataFieldSet::read(const PartType partType, if (!previousFullByteOffset && !field->hasFullByteOffset(false)) offset--; - result_t result = field->read(partType, data, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + result_t result = field->read(partType, data, offset, output, leadingSeparator, dataFormat, fieldName, fieldIndex); if (result < RESULT_OK) return result; @@ -1274,9 +1308,11 @@ result_t DataFieldSet::read(const PartType partType, if (!found) { return RESULT_EMPTY; } - if (verbose) { - if (m_comment.length() > 0) + if (m_comment.length() > 0) { + if (dataFormat==df_verbose) output << " [" << m_comment << "]"; + else if (dataFormat==df_json) + output << ",\"comment\": \"" << m_comment << '"'; } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index c07575d2..777cce24 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -46,6 +46,13 @@ using namespace std; /** the separator character used between fields (in UI only). */ #define UI_FIELD_SEPARATOR ';' +/** the data output format. */ +enum DataFormat { + df_standard, //!< standard format (values only) + df_verbose, //!< verbose format (names, values, units, and comments) + df_json, //!< JSON format (names, values, units, and comments) +}; + /** the message part in which a data field is stored. */ enum PartType { pt_any, //!< stored in any data (master or slave) @@ -220,11 +227,9 @@ public: * @param offset the additional offset to add for reading binary data. * @param output the @a ostringstream to append the formatted value to. * @param leadingSeparator whether to prepend a separator before the formatted value. - * @param verbose whether to prepend the name, append the unit (if present), and append - * the comment in square brackets (if present). + * @param dataFormat the @a DataFormat to use. * @param fieldName the optional name of a field to limit the output to. * @param fieldIndex the optional index of the named field to limit the output to, or -1. - * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success (or if the partType does not match), * or @a RESULT_EMPTY if the field was skipped (either ignored or due to @a filterName), * or an error code. @@ -232,8 +237,7 @@ public: virtual result_t read(const PartType partType, SymbolString& data, unsigned char offset, ostringstream& output, bool leadingSeparator=false, - bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, - char separator=UI_FIELD_SEPARATOR) = 0; + DataFormat dataFormat=df_standard, const char* fieldName=NULL, signed char fieldIndex=-1) = 0; /** * Writes the value to the master or slave @a SymbolString. @@ -343,8 +347,7 @@ public: virtual result_t read(const PartType partType, SymbolString& data, unsigned char offset, ostringstream& output, bool leadingSeparator=false, - bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, - char separator=UI_FIELD_SEPARATOR); + DataFormat dataFormat=df_standard, const char* fieldName=NULL, signed char fieldIndex=-1); // @copydoc virtual result_t write(istringstream& input, @@ -360,7 +363,9 @@ protected: * @param output the ostringstream to append the formatted value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output) = 0; + virtual result_t readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat) = 0; /** * Internal method for writing the field to a @a SymbolString. @@ -426,7 +431,9 @@ public: protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat); // @copydoc virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); @@ -538,7 +545,9 @@ public: protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat); // @copydoc virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); @@ -597,7 +606,9 @@ public: protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char baseOffset, + ostringstream& output, + DataFormat dataFormat); // @copydoc virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); @@ -675,8 +686,7 @@ public: virtual result_t read(const PartType partType, SymbolString& data, unsigned char offset, ostringstream& output, bool leadingSeparator=false, - bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, - char separator=UI_FIELD_SEPARATOR); + DataFormat dataFormat=df_standard, const char* fieldName=NULL, signed char fieldIndex=-1); // @copydoc virtual result_t write(istringstream& input, diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 808e2e82..ec311078 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -351,15 +351,14 @@ result_t Message::prepareSlave(SymbolString& slaveData) result_t Message::decode(const PartType partType, SymbolString& data, ostringstream& output, bool leadingSeparator, - bool verbose, const char* fieldName, signed char fieldIndex, - char separator) + DataFormat dataFormat, const char* fieldName, signed char fieldIndex) { unsigned char offset; if (partType == pt_masterData) offset = (unsigned char)(m_id.size() - 2); else offset = 0; - result_t result = m_data->read(partType, data, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + result_t result = m_data->read(partType, data, offset, output, leadingSeparator, dataFormat, fieldName, fieldIndex); if (result < RESULT_OK) return result; if (result == RESULT_EMPTY && fieldName != NULL) @@ -382,17 +381,17 @@ result_t Message::decode(const PartType partType, SymbolString& data, result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, bool leadingSeparator, - bool verbose, char separator) + DataFormat dataFormat) { unsigned char offset = (unsigned char)(m_id.size() - 2); size_t startPos = output.str().length(); - result_t result = m_data->read(pt_masterData, masterData, offset, output, leadingSeparator, verbose, NULL, -1, separator); + result_t result = m_data->read(pt_masterData, masterData, offset, output, leadingSeparator, dataFormat, NULL, -1); if (result < RESULT_OK) return result; bool empty = result == RESULT_EMPTY; offset = 0; leadingSeparator = output.str().length() > startPos; - result = m_data->read(pt_slaveData, slaveData, offset, output, leadingSeparator, verbose, NULL, -1, separator); + result = m_data->read(pt_slaveData, slaveData, offset, output, leadingSeparator, dataFormat, NULL, -1); if (result < RESULT_OK) return result; if (result == RESULT_EMPTY && !empty) @@ -409,20 +408,18 @@ result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, return result; } -result_t Message::decodeLastData(ostringstream& output, - bool verbose, const char* fieldName, signed char fieldIndex, - char separator) +result_t Message::decodeLastData(ostringstream& output, bool leadingSeparator, + DataFormat dataFormat, const char* fieldName, signed char fieldIndex) { - bool leadingSeparator = false; unsigned char offset = (unsigned char)(m_id.size() - 2); size_t startPos = output.str().length(); - result_t result = m_data->read(pt_masterData, m_lastMasterData, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + result_t result = m_data->read(pt_masterData, m_lastMasterData, offset, output, leadingSeparator, dataFormat, fieldName, fieldIndex); if (result < RESULT_OK) return result; bool empty = result == RESULT_EMPTY; offset = 0; leadingSeparator = output.str().length() > startPos; - result = m_data->read(pt_slaveData, m_lastSlaveData, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + result = m_data->read(pt_slaveData, m_lastSlaveData, offset, output, leadingSeparator, dataFormat, fieldName, fieldIndex); if (result < RESULT_OK) return result; if (result == RESULT_EMPTY && !empty) diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 7a05aab2..d0a1f468 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -182,17 +182,14 @@ public: * @param data the unescaped data @a SymbolString for reading binary data. * @param output the @a ostringstream to append the formatted value to. * @param leadingSeparator whether to prepend a separator before the formatted value. - * @param verbose whether to prepend the name, append the unit (if present), and append - * the comment in square brackets (if present). + * @param dataFormat the @a DataFormat to use. * @param fieldName the optional name of a field to limit the output to. * @param fieldIndex the optional index of the named field to limit the output to, or -1. - * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ result_t decode(const PartType partType, SymbolString& data, ostringstream& output, bool leadingSeparator=false, - bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, - char separator=UI_FIELD_SEPARATOR); + DataFormat dataFormat=df_standard, const char* fieldName=NULL, signed char fieldIndex=-1); /** * Decode all parts of a received message. @@ -200,28 +197,24 @@ public: * @param slaveData the unescaped slave data @a SymbolString to decode. * @param output the @a ostringstream to append the formatted value to. * @param leadingSeparator whether to prepend a separator before the formatted value. - * @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. + * @param dataFormat the @a DataFormat to use. * @return @a RESULT_OK on success, or an error code. */ result_t decode(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, bool leadingSeparator=false, - bool verbose=false, char separator=UI_FIELD_SEPARATOR); + DataFormat dataFormat=df_standard); /** * Decode the value from the last stored data. * @param output the @a 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 leadingSeparator whether to prepend a separator before the formatted value. + * @param dataFormat the @a DataFormat to use. * @param fieldName the optional name of a field to limit the output to. * @param fieldIndex the optional index of the named field to limit the output to, or -1. - * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - result_t decodeLastData(ostringstream& output, - bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, - char separator=UI_FIELD_SEPARATOR); + result_t decodeLastData(ostringstream& output, bool leadingSeparator=false, + DataFormat dataFormat=df_standard, const char* fieldName=NULL, signed char fieldIndex=-1); /** * Get the time when @a m_lastValue was last stored.