diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 460fecb0..3edc1fb7 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -130,7 +130,7 @@ bool ScanRequest::notify(result_t result, const SlaveSymbolString& slave) { } if (result == RESULT_OK) { ostringstream output; - result = m_message->decodeLastData(true, nullptr, -1, 0, &output); // decode data + result = m_message->decodeLastData(true, nullptr, -1, OF_NONE, &output); // decode data string str = output.str(); m_busHandler->setScanResult(dstAddress, m_notifyIndex+m_index, str); } @@ -216,7 +216,7 @@ bool decodeType(const DataType* type, const SymbolString& input, size_t length, string in = input.getStr(input.getDataOffset()); for (size_t offset = 0; offset <= offsets; offset++) { ostringstream out; - result_t result = type->readSymbols(offset, length, input, 0, &out); + result_t result = type->readSymbols(offset, length, input, OF_NONE, &out); if (result != RESULT_OK) { continue; } @@ -231,7 +231,7 @@ bool decodeType(const DataType* type, const SymbolString& input, size_t length, first = false; *output << endl << " "; ostringstream::pos_type cnt = output->tellp(); - type->dump(false, length, false, output); + type->dump(OF_NONE, length, false, output); cnt = output->tellp() - cnt; while (cnt < 5) { *output << " "; @@ -1156,7 +1156,7 @@ void BusHandler::messageCompleted() { result = message->storeLastData(0, idData); if (result == RESULT_OK) { ostringstream output; - result = message->decodeLastData(true, nullptr, -1, 0, &output); + result = message->decodeLastData(true, nullptr, -1, OF_NONE, &output); if (result == RESULT_OK) { string str = output.str(); setScanResult(slaveAddress, 0, str); @@ -1176,7 +1176,7 @@ void BusHandler::messageCompleted() { result_t result = message->storeLastData(m_command, m_response); if (result == RESULT_OK) { ostringstream output; - result = message->decodeLastData(true, nullptr, -1, 0, &output); + result = message->decodeLastData(true, nullptr, -1, OF_NONE, &output); if (result == RESULT_OK) { string str = output.str(); setScanResult(dstAddress, 0, str); @@ -1216,7 +1216,7 @@ void BusHandler::messageCompleted() { result_t result = message->storeLastData(m_command, m_response); ostringstream output; if (result == RESULT_OK) { - result = message->decodeLastData(false, nullptr, -1, 0, &output); + result = message->decodeLastData(false, nullptr, -1, OF_NONE, &output); } if (result < RESULT_OK) { logError(lf_update, "unable to parse %s %s %s from %s / %s: %s", mode, circuit.c_str(), name.c_str(), @@ -1380,7 +1380,7 @@ void BusHandler::formatScanResult(ostringstream* output) const { *output << endl; } *output << hex << setw(2) << setfill('0') << static_cast(slave); - message->decodeLastData(true, nullptr, -1, 0, output); + message->decodeLastData(true, nullptr, -1, OF_NONE, output); } } } diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 658f529f..beddbf70 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -1029,7 +1029,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose size_t offset = 0; size_t field = 0; bool fromLocal = s_configUriPrefix.empty(); - result_t result = (*identFields)[field]->read(data, offset, false, nullptr, -1, 0, -1, &out); // manufacturer name + result_t result = (*identFields)[field]->read(data, offset, false, nullptr, -1, OF_NONE, -1, &out); // manufacturer name if (result == RESULT_ERR_NOTFOUND && fromLocal) { result = (*identFields)[field]->read(data, offset, false, nullptr, -1, OF_NUMERIC, -1, &out); // manufacturer name } @@ -1042,7 +1042,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose out.str(""); out.clear(); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); - result = (*identFields)[field]->read(data, offset, false, nullptr, -1, 0, -1, &out); // identification string + result = (*identFields)[field]->read(data, offset, false, nullptr, -1, OF_NONE, -1, &out); // identification string } if (result == RESULT_OK) { ident = out.str(); @@ -1307,7 +1307,7 @@ int main(int argc, char* argv[]) { } if (result == RESULT_OK && opt.dumpConfig) { logNotice(lf_main, "configuration dump:"); - s_messageMap->dump(true, &cout); + s_messageMap->dump(true, OF_NONE, &cout); } shutdown(overallResult != RESULT_OK); diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 606141e4..701c46bf 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -98,6 +98,13 @@ result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map< } +#define VERBOSITY_0 OF_NONE +#define VERBOSITY_1 OF_NAMES +#define VERBOSITY_2 (VERBOSITY_1 | OF_UNITS) +#define VERBOSITY_3 (VERBOSITY_2 | OF_COMMENTS) +#define VERBOSITY_4 (VERBOSITY_3 | OF_ALL_ATTRS) + + MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages) : Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages), m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.readOnly ? ESC : opt.initialScan), @@ -702,7 +709,7 @@ result_t MainLoop::executeAuth(const vector& args, string* user, ostring result_t MainLoop::executeRead(const vector& args, const string& levels, ostringstream* ostream) { size_t argPos = 1; bool hex = false, newDefinition = false; - OutputFormat verbosity = 0; + OutputFormat verbosity = OF_NONE; time_t maxAge = 5*60; string circuit, params; symbol_t srcAddress = SYN, dstAddress = SYN; @@ -732,21 +739,17 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, break; } } else if (args[argPos] == "-v") { - switch (verbosity) { - case 0: - verbosity = OF_NAMES; - break; - case OF_NAMES: - verbosity |= OF_UNITS; - break; - case OF_NAMES|OF_UNITS: - verbosity |= OF_COMMENTS; - break; + if ((verbosity & VERBOSITY_3) == VERBOSITY_0) { + verbosity |= VERBOSITY_1; + } else if ((verbosity & VERBOSITY_3) == VERBOSITY_1) { + verbosity |= VERBOSITY_2; + } else { + verbosity |= VERBOSITY_3; } } else if (args[argPos] == "-vv") { - verbosity |= OF_NAMES|OF_UNITS; + verbosity |= VERBOSITY_2; } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { - verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; + verbosity |= VERBOSITY_3; } else if (args[argPos] == "-n") { verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { @@ -799,7 +802,7 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, } argPos++; } - if ((hex && (newDefinition || verbosity != 0 || !circuit.empty() || !params.empty() || dstAddress != SYN + if ((hex && (newDefinition || verbosity != OF_NONE || !circuit.empty() || !params.empty() || dstAddress != SYN || pollPriority > 0 || args.size() < argPos + 1)) || (newDefinition && (hex || !circuit.empty() || pollPriority > 0 || args.size() != argPos + 1))) { argPos = 0; // print usage @@ -882,7 +885,7 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, ret = message->storeLastData(master, slave); ostringstream result; if (ret == RESULT_OK) { - ret = message->decodeLastData(false, nullptr, -1, 0, &result); + ret = message->decodeLastData(false, nullptr, -1, OF_NONE, &result); } if (ret >= RESULT_OK) { logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), @@ -1107,7 +1110,7 @@ result_t MainLoop::executeWrite(const vector& args, const string levels, ret = message->storeLastData(master, slave); ostringstream result; if (ret == RESULT_OK) { - ret = message->decodeLastData(false, nullptr, -1, 0, &result); + ret = message->decodeLastData(false, nullptr, -1, OF_NONE, &result); } if (ret >= RESULT_OK) { logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), @@ -1178,7 +1181,7 @@ result_t MainLoop::executeWrite(const vector& args, const string levels, return RESULT_OK; } - ret = message->decodeLastData(false, false, nullptr, -1, 0, ostream); // decode data + ret = message->decodeLastData(false, false, nullptr, -1, OF_NONE, ostream); // decode data if (ret >= RESULT_OK && ostream->str().empty()) { logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); @@ -1325,29 +1328,27 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true, onlyWithData = false, hexFormat = false, userLevel = true, withConditions = false; string useLevels = levels; - OutputFormat verbosity = 0; + OutputFormat verbosity = OF_NONE; vector fieldNames; string circuit; vector id; while (args.size() > argPos && args[argPos][0] == '-') { if (args[argPos] == "-v") { - switch (verbosity) { - case 0: - verbosity |= OF_NAMES; - break; - case OF_NAMES: - verbosity |= OF_UNITS; - break; - case OF_NAMES|OF_UNITS: - verbosity |= OF_COMMENTS; - break; + if ((verbosity & VERBOSITY_4) == VERBOSITY_0) { + verbosity |= VERBOSITY_1; + } else if ((verbosity & VERBOSITY_4) == VERBOSITY_1) { + verbosity |= VERBOSITY_2; + } else if ((verbosity & VERBOSITY_4) == VERBOSITY_2) { + verbosity |= VERBOSITY_3; + } else { + verbosity |= VERBOSITY_4; } } else if (args[argPos] == "-vv") { - verbosity |= OF_NAMES|OF_UNITS; + verbosity |= VERBOSITY_2; } else if (args[argPos] == "-vvv") { - verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; - } else if (args[argPos] == "-V") { - verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS|OF_ALL_ATTRS; + verbosity |= VERBOSITY_3; + } else if (args[argPos] == "-vvvv" || args[argPos] == "-V") { + verbosity |= VERBOSITY_4; } else if (args[argPos] == "-f") { configFormat = true; if (hexFormat) { @@ -1470,12 +1471,12 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, if (found) { *ostream << endl; } - message->dump(nullptr, withConditions, ostream); + message->dump(nullptr, withConditions, verbosity, ostream); } else if (!fieldNames.empty()) { if (found) { *ostream << endl; } - message->dump(&fieldNames, withConditions, ostream); + message->dump(&fieldNames, withConditions, verbosity, ostream); } else { if (found) { *ostream << endl; @@ -1496,7 +1497,7 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, << " / " << message->getLastSlaveData().getStr() << ")"; } } - if ((verbosity & (OF_NAMES|OF_UNITS|OF_COMMENTS)) == (OF_NAMES|OF_UNITS|OF_COMMENTS)) { + if ((verbosity & VERBOSITY_3) == VERBOSITY_3) { symbol_t dstAddress = message->getDstAddress(); if (dstAddress != SYN) { snprintf(str, sizeof(str), "%02x", dstAddress); @@ -1536,26 +1537,22 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, result_t MainLoop::executeListen(const vector& args, ClientSettings* settings, ostringstream* ostream) { size_t argPos = 1; - OutputFormat verbosity = 0; + OutputFormat verbosity = OF_NONE; bool listenWithUnknown = false; bool listenOnlyUnknown = false; while (args.size() > argPos && args[argPos][0] == '-') { if (args[argPos] == "-v") { - switch (verbosity) { - case 0: - verbosity = OF_NAMES; - break; - case OF_NAMES: - verbosity |= OF_UNITS; - break; - case OF_NAMES|OF_UNITS: - verbosity |= OF_COMMENTS; - break; + if ((verbosity & VERBOSITY_3) == VERBOSITY_0) { + verbosity |= VERBOSITY_1; + } else if ((verbosity & VERBOSITY_3) == VERBOSITY_1) { + verbosity |= VERBOSITY_2; + } else { + verbosity |= VERBOSITY_3; } } else if (args[argPos] == "-vv") { - verbosity |= OF_NAMES|OF_UNITS; + verbosity |= VERBOSITY_2; } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { - verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; + verbosity |= VERBOSITY_3; } else if (args[argPos] == "-n") { verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { @@ -1686,24 +1683,20 @@ result_t MainLoop::executeDefine(const vector& args, ostringstream* ostr result_t MainLoop::executeDecode(const vector& args, ostringstream* ostream) { size_t argPos = 1; - OutputFormat verbosity = 0; + OutputFormat verbosity = OF_NONE; while (args.size() > argPos && args[argPos][0] == '-') { if (args[argPos] == "-v") { - switch (verbosity) { - case 0: - verbosity = OF_NAMES; - break; - case OF_NAMES: - verbosity |= OF_UNITS; - break; - case OF_NAMES|OF_UNITS: - verbosity |= OF_COMMENTS; - break; + if ((verbosity & VERBOSITY_3) == VERBOSITY_0) { + verbosity |= VERBOSITY_1; + } else if ((verbosity & VERBOSITY_3) == VERBOSITY_1) { + verbosity |= VERBOSITY_2; + } else { + verbosity |= VERBOSITY_3; } } else if (args[argPos] == "-vv") { - verbosity |= OF_NAMES|OF_UNITS; + verbosity |= VERBOSITY_2; } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { - verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; + verbosity |= VERBOSITY_3; } else if (args[argPos] == "-n") { verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { @@ -2096,7 +2089,7 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri time_t maxLastUp = 0; if (ret == RESULT_OK) { bool first = true; - verbosity |= OF_JSON | (full ? OF_ALL_ATTRS : 0) | (withDefinition ? OF_DEFINTION : 0); + verbosity |= OF_JSON | (full ? OF_ALL_ATTRS : OF_NONE) | (withDefinition ? OF_DEFINITION : OF_NONE); deque messages; m_messages->findAll(circuit, name, getUserLevels(user), exact, true, withWrite, true, true, true, 0, 0, false, &messages); @@ -2147,7 +2140,7 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri Message* next = *(it+1); same = next->getCircuit() == lastCircuit && next->getName() == name; } - message->decodeJson(!first, same, raw, verbosity, ostream); + message->decodeJson(!first, same, true, raw, verbosity, ostream); lastName = name; first = false; } diff --git a/src/ebusd/network.h b/src/ebusd/network.h index 902fa60b..13f1069c 100644 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -67,7 +67,7 @@ class NetMessage { explicit NetMessage(bool isHttp) : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) { m_settings.mode = cm_normal; - m_settings.format = 0; + m_settings.format = OF_NONE; m_settings.listenWithUnknown = false; m_settings.listenOnlyUnknown = false; pthread_mutex_init(&m_mutex, nullptr); diff --git a/src/lib/ebus/contrib/test/test_tem.cpp b/src/lib/ebus/contrib/test/test_tem.cpp index ba12278f..e33ed923 100755 --- a/src/lib/ebus/contrib/test/test_tem.cpp +++ b/src/lib/ebus/contrib/test/test_tem.cpp @@ -178,7 +178,7 @@ int main() { continue; } cout << "\"" << check[0] << "\"=\""; - fields->dump(false, false, &cout); + fields->dump(false, OF_NONE, &cout); cout << "\": create OK" << endl; ostringstream output; @@ -194,9 +194,9 @@ int main() { cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; error = true; } - result = fields->read(mstr, 0, false, nullptr, -1, 0, -1, &output); + result = fields->read(mstr, 0, false, nullptr, -1, OF_NONE, -1, &output); if (result >= RESULT_OK) { - result = fields->read(sstr, 0, !output.str().empty(), nullptr, -1, 0, -1, &output); + result = fields->read(sstr, 0, !output.str().empty(), nullptr, -1, OF_NONE, -1, &output); } if (failedRead) { if (result >= RESULT_OK) { diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 7c69ba45..39a4c00b 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -67,6 +67,7 @@ string AttributedItem::pluck(const string& key, map* row) { } void AttributedItem::dumpString(bool prependFieldSeparator, const string& str, ostream* output) { + // not to be used for JSON format if (prependFieldSeparator) { *output << FIELD_SEPARATOR; } @@ -102,7 +103,7 @@ void AttributedItem::appendJson(bool prependFieldSeparator, const string& name, } } if (prependFieldSeparator) { - *output << FIELD_SEPARATOR; + *output << ","; } *output << " \"" << name << "\": "; if (plain) { @@ -129,9 +130,9 @@ void AttributedItem::mergeAttributes(map* attributes) const { } } -void AttributedItem::dumpAttribute(bool prependFieldSeparator, bool asJson, const string& name, ostream* output) +void AttributedItem::dumpAttribute(bool prependFieldSeparator, OutputFormat outputFormat, const string& name, ostream* output) const { - if (asJson) { + if (outputFormat & OF_JSON) { appendJson(prependFieldSeparator, name, getAttribute(name), false, output); } else { dumpString(prependFieldSeparator, getAttribute(name), output); @@ -171,7 +172,7 @@ bool AttributedItem::appendAttributes(OutputFormat outputFormat, ostream* output result_t result = RESULT_EMPTY; size_t addr = parseInt(entry.second.c_str(), 16, 0, 255, &result); if (result == RESULT_OK) { - *output << FIELD_SEPARATOR << " \"" << key << "\": " << addr; + *output << ", \"" << key << "\": " << addr; continue; } } @@ -469,44 +470,43 @@ result_t SingleDataField::create(const string& name, const map& return RESULT_OK; } -void SingleDataField::dumpPrefix(bool prependFieldSeparator, bool asJson, ostream* output) const { +void SingleDataField::dumpPrefix(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const { *output << setw(0) << dec; // initialize formatting - if (asJson) { + if (outputFormat & OF_JSON) { if (prependFieldSeparator) { - *output << FIELD_SEPARATOR; + *output << ","; } *output << "\n {"; appendJson(false, "name", m_name, true, output); } else { dumpString(prependFieldSeparator, m_name, output); } - *output << FIELD_SEPARATOR; - if (asJson) { - *output << " \"slave\": " << (m_partType == pt_slaveData ? "true" : "false") << ", "; + if (outputFormat & OF_JSON) { + *output << ", \"slave\": " << (m_partType == pt_slaveData ? "true" : "false") << ", "; } else { + *output << FIELD_SEPARATOR; if (m_partType == pt_masterData) { *output << "m"; } else if (m_partType == pt_slaveData) { *output << "s"; } - } - if (!asJson) { *output << FIELD_SEPARATOR; } - m_dataType->dump(asJson, m_length, true, output); + m_dataType->dump(outputFormat, m_length, true, output); } -void SingleDataField::dumpSuffix(bool asJson, ostream* output) const { - dumpAttribute(true, asJson, "unit", output); - dumpAttribute(true, asJson, "comment", output); - if (asJson) { +void SingleDataField::dumpSuffix(OutputFormat outputFormat, ostream* output) const { + dumpAttribute(true, outputFormat, "unit", output); + dumpAttribute(true, outputFormat, "comment", output); + if (outputFormat & OF_JSON) { + appendAttributes(outputFormat & ~(OF_UNITS|OF_COMMENTS), output); *output << "}"; } } -void SingleDataField::dump(bool prependFieldSeparator, bool asJson, ostream* output) const { - dumpPrefix(prependFieldSeparator, asJson, output); - dumpSuffix(asJson, output); +void SingleDataField::dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const { + dumpPrefix(prependFieldSeparator, outputFormat, output); + dumpSuffix(outputFormat, output); } result_t SingleDataField::read(const SymbolString& data, size_t offset, @@ -557,7 +557,7 @@ result_t SingleDataField::read(const SymbolString& data, size_t offset, *output << "\"" << static_cast(outputIndex < 0 ? 0 : outputIndex) << "\":"; } if (!shortFormat) { - *output << " {\"name\": \"" << m_name << "\"" << ", \"value\": "; + *output << " {\"name\": \"" << m_name << "\", \"value\": "; } } else { if (fieldIndex < 0) { @@ -722,11 +722,11 @@ result_t ValueListDataField::derive(const string& name, PartType partType, int d return RESULT_OK; } -void ValueListDataField::dump(bool prependFieldSeparator, bool asJson, ostream* output) const { - dumpPrefix(prependFieldSeparator, asJson, output); +void ValueListDataField::dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const { + dumpPrefix(prependFieldSeparator, outputFormat, output); // no divisor appended since it is not allowed for ValueListDataField bool first = true; - if (asJson) { + if (outputFormat & OF_JSON) { *output << ", \"values\": {"; for (const auto it : m_values) { appendJson(!first, formatInt(it.first), it.second, true, output); // TODO optimize? @@ -743,7 +743,7 @@ void ValueListDataField::dump(bool prependFieldSeparator, bool asJson, ostream* *output << it.first << "=" << it.second; } } - dumpSuffix(asJson, output); + dumpSuffix(outputFormat, output); } result_t ValueListDataField::readSymbols(const SymbolString& input, size_t offset, @@ -838,22 +838,22 @@ result_t ConstantDataField::derive(const string& name, PartType partType, int di return RESULT_OK; } -void ConstantDataField::dump(bool prependFieldSeparator, bool asJson, ostream* output) const { - dumpPrefix(prependFieldSeparator, asJson, output); +void ConstantDataField::dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const { + dumpPrefix(prependFieldSeparator, outputFormat, output); // no divisor appended since it is not allowed for ConstantDataField - if (asJson) { + if (outputFormat & OF_JSON) { appendJson(false, "value", m_value, true, output); - *output << ", \"verify\":" << (m_verify ? "true" : "false"); + *output << ", \"verify\": " << (m_verify ? "true" : "false"); } else { *output << (m_verify?"==":"=") << m_value; } - dumpSuffix(asJson, output); + dumpSuffix(outputFormat, output); } result_t ConstantDataField::readSymbols(const SymbolString& input, size_t offset, OutputFormat outputFormat, ostream* output) const { ostringstream coutput; - result_t result = SingleDataField::readSymbols(input, offset, 0, &coutput); + result_t result = SingleDataField::readSymbols(input, offset, outputFormat, &coutput); if (result != RESULT_OK) { return result; } @@ -1024,9 +1024,9 @@ bool DataFieldSet::hasField(const char* fieldName, bool numeric) const { return false; } -void DataFieldSet::dump(bool prependFieldSeparator, bool asJson, ostream* output) const { +void DataFieldSet::dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const { for (const auto field : m_fields) { - field->dump(prependFieldSeparator, asJson, output); + field->dump(prependFieldSeparator, outputFormat, output); prependFieldSeparator = true; } } diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index f40e9f52..3622a1d3 100755 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -122,11 +122,11 @@ class AttributedItem { /** * Dump the attribute optionally embedded in @a TEXT_SEPARATOR to the output. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. - * @param asJson whether to output in JSON format. + * @param outputFormat the @a OutputFormat options. * @param name the name of the attribute to dump. * @param output the @a ostream to dump to. */ - void dumpAttribute(bool prependFieldSeparator, bool asJson, const string& name, ostream* output) const; + void dumpAttribute(bool prependFieldSeparator, OutputFormat outputFormat, const string& name, ostream* output) const; /** * Append the attribute value to the output. @@ -273,10 +273,10 @@ class DataField : public AttributedItem { /** * Dump the field settings to the output. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. - * @param asJson whether to output in JSON format. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to dump to. */ - virtual void dump(bool prependFieldSeparator, bool asJson, ostream* output) const = 0; + virtual void dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const = 0; /** * Return whether the field is available. @@ -420,20 +420,20 @@ class SingleDataField : public DataField { /** * Dump the common prefix field settings to the output (name and part type). * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. - * @param asJson whether to output in JSON format. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to dump to. */ - void dumpPrefix(bool prependFieldSeparator, bool asJson, ostream* output) const; + void dumpPrefix(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const; /** * Dump the common suffix field settings to the output (optional unit and comment). - * @param asJson whether to output in JSON format. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to dump to. */ - void dumpSuffix(bool asJson, ostream* output) const; + void dumpSuffix(OutputFormat outputFormat, ostream* output) const; // @copydoc - void dump(bool prependFieldSeparator, bool asJson, ostream* output) const override; + void dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const override; // @copydoc bool hasField(const char* fieldName, bool numeric) const override; @@ -519,7 +519,7 @@ class ValueListDataField : public SingleDataField { vector* fields) const override; // @copydoc - void dump(bool prependFieldSeparator, bool asJson, ostream* output) const override; + void dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const override; protected: @@ -572,7 +572,7 @@ class ConstantDataField : public SingleDataField { vector* fields) const override; // @copydoc - void dump(bool prependFieldSeparator, bool asJson, ostream* output) const override; + void dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const override; protected: @@ -685,7 +685,7 @@ class DataFieldSet : public DataField { bool hasField(const char* fieldName, bool numeric) const override; // @copydoc - void dump(bool prependFieldSeparator, bool asJson, ostream* output) const override; + void dump(bool prependFieldSeparator, OutputFormat outputFormat, ostream* output) const override; // @copydoc result_t read(const SymbolString& data, size_t offset, diff --git a/src/lib/ebus/datatype.cpp b/src/lib/ebus/datatype.cpp index 4de68eaa..f2d5b8fd 100755 --- a/src/lib/ebus/datatype.cpp +++ b/src/lib/ebus/datatype.cpp @@ -42,10 +42,10 @@ using std::setw; using std::endl; -bool DataType::dump(bool asJson, size_t length, bool appendDivisor, ostream* output) const { - if (asJson) { - *output << "\"type\": \"" << m_id << "\"" << FIELD_SEPARATOR << " \"isbits\": " - << (getBitCount() < 8 ? "true" : "false") << FIELD_SEPARATOR << " \"length\": "; +bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { + if (outputFormat & OF_JSON) { + *output << "\"type\": \"" << m_id << "\", \"isbits\": " + << (getBitCount() < 8 ? "true" : "false") << ", \"length\": "; if (isAdjustableLength() && length == REMAIN_LEN) { *output << "-1"; } else { @@ -297,11 +297,11 @@ result_t DateTimeDataType::readSymbols(size_t offset, size_t length, const Symbo last = symbol; continue; } - unsigned int minutes = symbol*256 + last; + minutes = symbol*256 + last; if (minutes > 24*60) { return RESULT_ERR_OUT_OF_RANGE; // invalid value } - unsigned int minutesHour = minutes / 60; + unsigned int minutesHour = (unsigned int)(minutes / 60); if (minutesHour > 24) { return RESULT_ERR_OUT_OF_RANGE; // invalid hour } @@ -353,7 +353,7 @@ result_t DateTimeDataType::readSymbols(size_t offset, size_t length, const Symbo } *output << dec << setfill('0') << setw(2) << static_cast(d) << "." << setw(2) << static_cast(m) << "." << static_cast(y + 1900); - m = minutes%(24*60); + m = (int)(minutes%(24*60)); d = m/60; *output << " " << setw(2) << dec << setfill('0') << static_cast(d); m -= d*60; @@ -568,25 +568,25 @@ size_t NumberDataType::calcPrecision(int divisor) { return precision; } -bool NumberDataType::dump(bool asJson, size_t length, bool appendDivisor, ostream* output) const { +bool NumberDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { if (m_bitCount < 8) { - DataType::dump(asJson, m_bitCount, appendDivisor, output); + DataType::dump(outputFormat, m_bitCount, appendDivisor, output); } else { - DataType::dump(asJson, length, appendDivisor, output); + DataType::dump(outputFormat, length, appendDivisor, output); } if (!appendDivisor) { return false; } if (m_baseType) { if (m_baseType->m_divisor != m_divisor) { - if (asJson) { + if (outputFormat & OF_JSON) { *output << ", \"divisor\": "; } *output << (m_divisor / m_baseType->m_divisor); return true; } } else if (m_divisor != 1) { - if (asJson) { + if (outputFormat & OF_JSON) { *output << ", \"divisor\": "; } *output << m_divisor; diff --git a/src/lib/ebus/datatype.h b/src/lib/ebus/datatype.h index 06e5408a..825493bb 100755 --- a/src/lib/ebus/datatype.h +++ b/src/lib/ebus/datatype.h @@ -78,36 +78,61 @@ using std::ostringstream; /** the maximum value for value lists. */ #define MAX_VALUE (0xFFFFFFFFu) +typedef unsigned int OutputFormatBaseType; -/** the type for data output format options. */ -typedef int OutputFormat; +enum OutputFormat : OutputFormatBaseType { + /** no bit set at all. */ + OF_NONE = 0, -/** bit flag for @a OutputFormat: include names. */ -#define OF_NAMES 0x01 + /** bit flag for @a OutputFormat: include names. */ + OF_NAMES = 1 << 0, -/** bit flag for @a OutputFormat: include units. */ -#define OF_UNITS 0x02 + /** bit flag for @a OutputFormat: include units. */ + OF_UNITS = 1 << 1, -/** bit flag for @a OutputFormat: include comments. */ -#define OF_COMMENTS 0x04 + /** bit flag for @a OutputFormat: include comments. */ + OF_COMMENTS = 1 << 2, -/** bit flag for @a OutputFormat: numeric format (keep numeric value of value=name pairs). */ -#define OF_NUMERIC 0x08 + /** bit flag for @a OutputFormat: numeric format (keep numeric value of value=name pairs). */ + OF_NUMERIC = 1 << 3, -/** bit flag for @a OutputFormat: value=name format for such pairs. */ -#define OF_VALUENAME 0x10 + /** bit flag for @a OutputFormat: value=name format for such pairs. */ + OF_VALUENAME = 1 << 4, -/** bit flag for @a OutputFormat: JSON format. */ -#define OF_JSON 0x20 + /** bit flag for @a OutputFormat: JSON format. */ + OF_JSON = 1 << 5, -/** bit flag for @a OutputFormat: short format (only name and value, no indentation). */ -#define OF_SHORT 0x40 + /** bit flag for @a OutputFormat: short format (only name and value for fields). */ + OF_SHORT = 1 << 6, -/** bit flag for @a OutputFormat: include all attributes. */ -#define OF_ALL_ATTRS 0x80 + /** bit flag for @a OutputFormat: include all attributes. */ + OF_ALL_ATTRS = 1 << 7, -/** bit flag for @a OutputFormat: include message/field definition. */ -#define OF_DEFINTION 0x100 + /** bit flag for @a OutputFormat: include message/field definition. */ + OF_DEFINITION = 1 << 8, +}; + +constexpr inline enum OutputFormat operator| (enum OutputFormat self, enum OutputFormat other) { + return (enum OutputFormat)((OutputFormatBaseType)self | (OutputFormatBaseType)other); +} + +inline enum OutputFormat& operator|= (enum OutputFormat& self, enum OutputFormat other) { + self = self | other; + return self; +} + +constexpr inline enum OutputFormat operator& (enum OutputFormat self, enum OutputFormat other) { + return (enum OutputFormat)((OutputFormatBaseType)self & (OutputFormatBaseType)other); +} + +inline enum OutputFormat& operator&= (enum OutputFormat& self, enum OutputFormat other) { + self = self & other; + return self; +} + +constexpr inline enum OutputFormat operator~ (enum OutputFormat self) { + return (enum OutputFormat)(~(OutputFormatBaseType)self); +} /** the message part in which a data field is stored. */ enum PartType { @@ -219,13 +244,13 @@ class DataType { /** * Dump the type identifier with the specified length and optionally the * divisor to the output. - * @param asJson whether to output in JSON format. + * @param outputFormat the @a OutputFormat options. * @param length the number of symbols to read/write. * @param appendDivisor whether to append the divisor (if available). * @param output the @a ostream to dump to. * @return true when a non-default divisor was written to the output. */ - virtual bool dump(bool asJson, size_t length, bool appendDivisor, ostream* output) const; + virtual bool dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const; /** * Internal method for reading the numeric raw value from a @a SymbolString. @@ -436,7 +461,7 @@ class NumberDataType : public DataType { static size_t calcPrecision(int divisor); // @copydoc - bool dump(bool asJson, size_t length, bool appendDivisor, ostream* output) const override; + bool dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const override; /** * Derive a new @a NumberDataType from this. diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 5ebdf4b9..dd765e02 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -845,7 +845,8 @@ void Message::dumpHeader(const vector* fieldNames, ostream* output) { } } -void Message::dump(const vector* fieldNames, bool withConditions, ostream* output) const { +void Message::dump(const vector* fieldNames, bool withConditions, OutputFormat outputFormat, ostream* output) const { + // not to be used together with OF_JSON bool first = true; if (fieldNames == nullptr) { for (const auto& fieldName : knownFieldNamesFull) { @@ -857,7 +858,7 @@ void Message::dump(const vector* fieldNames, bool withConditions, ostrea } else { *output << FIELD_SEPARATOR; } - dumpField(fieldName, withConditions, output); + dumpField(fieldName, withConditions, outputFormat, output); } return; } @@ -867,11 +868,11 @@ void Message::dump(const vector* fieldNames, bool withConditions, ostrea } else { *output << FIELD_SEPARATOR; } - dumpField(fieldName, withConditions, output); + dumpField(fieldName, withConditions, outputFormat, output); } } -void Message::dumpField(const string& fieldName, bool withConditions, ostream* output) const { +void Message::dumpField(const string& fieldName, bool withConditions, OutputFormat outputFormat, ostream* output) const { if (fieldName == "type") { if (withConditions && m_condition != nullptr) { m_condition->dump(false, output); @@ -928,10 +929,10 @@ void Message::dumpField(const string& fieldName, bool withConditions, ostream* o return; } if (fieldName == "fields") { - m_data->dump(false, false, output); + m_data->dump(false, outputFormat, output); return; } - dumpAttribute(false, false, fieldName, output); + dumpAttribute(false, outputFormat, fieldName, output); } void addData(const SymbolString& data, ostringstream* output) { @@ -948,26 +949,44 @@ void addData(const SymbolString& data, ostringstream* output) { *output << "]"; } -void Message::decodeJson(bool leadingSeparator, bool appendDirection, bool addRaw, OutputFormat outputFormat, - ostringstream* output) const { +void Message::decodeJson(bool leadingSeparator, bool appendDirectionCondition, bool withData, bool addRaw, + OutputFormat outputFormat, ostringstream* output) const { + outputFormat |= OF_JSON; if (leadingSeparator) { - *output << ","; + *output << ",\n"; } - *output << "\n \"" << getName(); - if (appendDirection) { + *output << " \""; + *output << getName(); + if (appendDirectionCondition) { if (isPassive()) { *output << "-u"; } else if (isWrite()) { *output << "-w"; } + if (isConditional()) { + m_condition->dump(false, output); + } } - bool withDefinition = (outputFormat & OF_DEFINTION) != 0; + bool withDefinition = outputFormat & OF_DEFINITION; *output << "\": {" << "\n \"name\": \"" << getName() << "\"" << ",\n \"passive\": " << (isPassive() ? "true" : "false") - << ",\n \"write\": " << (isWrite() ? "true" : "false") - << ",\n \"lastup\": " << setw(0) << dec << m_lastUpdateTime; - bool hasData = getLastUpdateTime() != 0; + << ",\n \"write\": " << (isWrite() ? "true" : "false"); + if (outputFormat & OF_ALL_ATTRS) { + *output << ",\n \"level\": \"" << getLevel() << "\""; + if (getPollPriority()>0) { + *output << ",\n \"pollprio\": " << setw(0) << dec << getPollPriority(); + } + if (isConditional()) { + *output << ",\n \"condition\": \""; + m_condition->dump(false, output); + *output << "\""; + } + } + if (withData) { + *output << ",\n \"lastup\": " << setw(0) << dec << getLastUpdateTime(); + } + bool hasData = withData && (getLastUpdateTime() != 0); if (hasData || withDefinition) { if (withDefinition && m_srcAddress != SYN) { *output << ",\n \"qq\": " << dec << static_cast(m_srcAddress); @@ -983,7 +1002,7 @@ void Message::decodeJson(bool leadingSeparator, bool appendDirection, bool addRa } *output << "]"; } - appendAttributes(OF_JSON | outputFormat, output); + appendAttributes(outputFormat, output); if (hasData) { if (addRaw) { addData(m_lastMasterData, output); @@ -1004,7 +1023,7 @@ void Message::decodeJson(bool leadingSeparator, bool appendDirection, bool addRa } if (withDefinition) { *output << ",\n \"fielddefs\": ["; - m_data->dump(false, true, output); + m_data->dump(false, outputFormat, output); *output << "\n ]"; } } @@ -1256,9 +1275,9 @@ result_t ChainedMessage::combineLastParts() { return result; } -void ChainedMessage::dumpField(const string& fieldName, bool withConditions, ostream* output) const { +void ChainedMessage::dumpField(const string& fieldName, bool withConditions, OutputFormat outputFormat, ostream* output) const { if (fieldName != "id") { - Message::dumpField(fieldName, withConditions, output); + Message::dumpField(fieldName, withConditions, outputFormat, output); return; } bool first = true; @@ -1608,7 +1627,7 @@ bool SimpleNumericCondition::checkValue(const Message* message, const string& fi bool SimpleStringCondition::checkValue(const Message* message, const string& field) { ostringstream output; - result_t result = message->decodeLastData(false, field.length() == 0 ? nullptr : field.c_str(), -1, 0, &output); + result_t result = message->decodeLastData(false, field.length() == 0 ? nullptr : field.c_str(), -1, OF_NONE, &output); if (result == RESULT_OK) { string value = output.str(); for (size_t i = 0; i < m_values.size(); i++) { @@ -2786,10 +2805,17 @@ Message* MessageMap::getNextPoll() { return ret; } -void MessageMap::dump(bool withConditions, ostream* output) const { +void MessageMap::dump(bool withConditions, OutputFormat outputFormat, ostream* output) const { bool first = true; - Message::dumpHeader(nullptr, output); - *output << endl; + bool isJson = (outputFormat & OF_JSON) != 0; + if (isJson) { + *output << "{"; + } else { + Message::dumpHeader(nullptr, output); + } + if (!(outputFormat & OF_SHORT)) { + *output << endl; + } for (const auto it : m_messagesByName) { if (it.first[0] == FIELD_SEPARATOR) { // skip instances stored multiple times (key starting with "-") continue; @@ -2799,28 +2825,46 @@ void MessageMap::dump(bool withConditions, ostream* output) const { if (!message) { continue; } + bool wasFirst = first; if (first) { first = false; } else { *output << endl; } - message->dump(nullptr, withConditions, output); + if (isJson) { + ostringstream str; + message->decodeJson(!wasFirst, true, false, false, outputFormat, &str); + *output << str.str(); + } else { + message->dump(nullptr, withConditions, outputFormat, output); + } } } else { Message* message = getFirstAvailable(it.second); if (!message) { continue; } + bool wasFirst = first; if (first) { first = false; } else { *output << endl; } - message->dump(nullptr, withConditions, output); + if (isJson) { + ostringstream str; + message->decodeJson(!wasFirst, true, false, false, outputFormat, &str); + *output << str.str(); + } else { + message->dump(nullptr, withConditions, outputFormat, output); + } } } - if (!first) { - *output << endl; + if (isJson) { + *output << "}" << endl; + } else { + if (!first) { + *output << endl; + } } } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index fd5b8a5f..f9a3bdd7 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -543,28 +543,31 @@ class Message : public AttributedItem { * Write the message definition or parts of it to the @a ostream. * @param fieldNames the list of field names to write, or nullptr for all. * @param withConditions whether to include the optional conditions prefix. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to append the formatted value to. */ - void dump(const vector* fieldNames, bool withConditions, ostream* output) const; + void dump(const vector* fieldNames, bool withConditions, OutputFormat outputFormat, ostream* output) const; /** * Write the specified field to the @a ostream. * @param fieldName the field name to write. * @param withConditions whether to include the optional conditions prefix. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to append the formatted value to. */ - virtual void dumpField(const string& fieldName, bool withConditions, ostream* output) const; + virtual void dumpField(const string& fieldName, bool withConditions, OutputFormat outputFormat, ostream* output) const; /** * Decode the message from the last stored data in JSON format. * @param leadingSeparator whether to prepend a separator before the first value. - * @param appendDirection whether to append the direction to the name key (for passive and write). + * @param appendDirectionCondition whether to append the direction and condition to the name key. + * @param withData whether to add the last data as well. * @param addRaw whether to add the raw symbols as well. * @param outputFormat the @a OutputFormat options to use. * @param output the @a ostringstream to append the decoded value(s) to. */ - virtual void decodeJson(bool leadingSeparator, bool appendDirection, bool addRaw, OutputFormat outputFormat, - ostringstream* output) const; + virtual void decodeJson(bool leadingSeparator, bool appendDirectionCondition, bool withData, bool addRaw, + OutputFormat outputFormat, ostringstream* output) const; protected: /** the optional circuit name. */ @@ -723,7 +726,7 @@ class ChainedMessage : public Message { protected: // @copydoc - void dumpField(const string& fieldName, bool withConditions, ostream* output) const override; + void dumpField(const string& fieldName, bool withConditions, OutputFormat outputFormat, ostream* output) const override; private: @@ -1519,9 +1522,10 @@ class MessageMap : public MappedFileReader { /** * Write the message definitions to the @a ostream. * @param withConditions whether to include the optional conditions prefix. + * @param outputFormat the @a OutputFormat options. * @param output the @a ostream to append the formatted messages to. */ - void dump(bool withConditions, ostream* output) const; + void dump(bool withConditions, OutputFormat outputFormat, ostream* output) const; private: diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 3ebb2e4b..15015bcf 100755 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -568,7 +568,7 @@ int main() { if (flags.find('i') != string::npos) { findIndex = parseSignedInt(flags.substr(flags.find('i')+1).c_str(), 10, 0, 9, &result); } - OutputFormat verbosity = 0; + OutputFormat verbosity = OF_NONE; if (flags.find("v") != string::npos) { verbosity |= OF_NAMES; } @@ -633,7 +633,7 @@ int main() { continue; } cout << "\"" << check[0] << "\"=\""; - fields->dump(false, false, &cout); + fields->dump(false, OF_NONE, &cout); cout << "\": create OK" << endl; ostringstream output; @@ -650,9 +650,9 @@ int main() { cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; error = true; } - result = fields->read(mstr, 0, false, findName, findIndex, verbosity|(numeric?OF_NUMERIC:0), -1, &output); + result = fields->read(mstr, 0, false, findName, findIndex, verbosity|(numeric?OF_NUMERIC:OF_NONE), -1, &output); if (result >= RESULT_OK) { - result = fields->read(sstr, 0, !output.str().empty(), findName, findIndex, verbosity|(numeric?OF_NUMERIC:0), -1, &output); + result = fields->read(sstr, 0, !output.str().empty(), findName, findIndex, verbosity|(numeric?OF_NUMERIC:OF_NONE), -1, &output); } if (failedRead) { if (result >= RESULT_OK) { diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 0ccc9278..0f9a94a5 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -183,8 +183,6 @@ int main() { {"*r,cir*cuit#level,na*me,com*ment,ff,75,b509,0d", "", "", "", ""}, {"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH", "r,cirCIRCUITcuit,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42", "ff75b509030d0100", "012a", "DN"}, {"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH", - // "\"naNAMEme\": {r,cirCIRCUITcuit,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42" - "\n" " \"naNAMEme\": {\n" " \"name\": \"naNAMEme\",\n" " \"passive\": false,\n" @@ -407,7 +405,7 @@ int main() { ostringstream output; if (withMessageDump) { if (decodeJson) { - message->decodeJson(false, false, false, OF_JSON|OF_DEFINTION, &output); + message->decodeJson(false, false, true, false, OF_JSON|OF_DEFINITION, &output); string str = output.str(); size_t start = str.find("\"lastup\": "); if (start != string::npos) { @@ -420,12 +418,12 @@ int main() { output.str(""); output << str; } else { - message->dump(nullptr, true, &output); + message->dump(nullptr, true, OF_NONE, &output); } output << ": "; } result = message->decodeLastData(false, nullptr, -1, - (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), &output); + (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:OF_NONE)|(decodeJson?OF_NAMES|OF_JSON:OF_NONE), &output); if (result != RESULT_OK) { cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error " << (message->isWrite() ? "write: " : "read: ") << getResultCode(result) << endl;