From 25196e4852d1e07f9c14f3d60e947995d6a5e1c6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 08:33:11 +0100 Subject: [PATCH 01/15] add optional length to parseInt() and set result on success, remove unused stuff, avoid reading beyond eof, check divisor in StringDataField::derive(), fix for NumberDataField::writeSymbols() --- src/lib/ebus/data.cpp | 35 +++++++++++++++++++---------------- src/lib/ebus/data.h | 3 ++- 2 files changed, 21 insertions(+), 17 deletions(-) mode change 100644 => 100755 src/lib/ebus/data.cpp mode change 100644 => 100755 src/lib/ebus/data.h diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp old mode 100644 new mode 100755 index 411dd540..413b9edc --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -18,8 +18,6 @@ */ #include "data.h" -#include "decode.h" -#include "encode.h" #include #include #include @@ -100,7 +98,7 @@ static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" #define NULL_VALUE "-" #define MAX_POS 16 -unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result) { +unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length) { char* strEnd = NULL; unsigned int ret = strtoul(str, &strEnd, base); @@ -114,6 +112,10 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co result = RESULT_ERR_INVALID_ARG; // invalid value return 0; } + if (length != NULL) + *length = strEnd - str; + + result = RESULT_OK; return ret; } @@ -429,8 +431,8 @@ result_t StringDataField::derive(std::string name, std::string comment, { if (m_partType != pt_template && partType == pt_template) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance - if (values.empty() == false) - return RESULT_ERR_INVALID_ARG; // cannot set values for string field + if (divisor != 0 || values.empty() == false) + return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field if (name.empty() == true) name = m_name; if (comment.empty() == true) @@ -517,8 +519,6 @@ result_t StringDataField::writeSymbols(std::istringstream& input, { size_t start = m_offset, end = m_offset + m_length; int incr = 1; - const char* str; - char* strEnd; unsigned long int value = 0, last = 0; std::string token; @@ -534,7 +534,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, switch (m_dataType.type) { case bt_hexstr: - while (input.peek() == ' ') + while (input.eof() == false && input.peek() == ' ') input.get(); if (input.eof() == true) // no more digits value = m_dataType.replacement; // fill up with replacement @@ -542,12 +542,11 @@ result_t StringDataField::writeSymbols(std::istringstream& input, token.clear(); token.push_back(input.get()); if (input.eof() == true) - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_INVALID_ARG; // too short hex value token.push_back(input.get()); if (input.eof() == true) - return RESULT_ERR_INVALID_ARG; // invalid hex value + return RESULT_ERR_INVALID_ARG; // too short hex value - result_t result; value = parseInt(token.c_str(), 16, 0, 0xff, result); if (result != RESULT_OK) return result; // invalid hex value @@ -556,7 +555,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, case bt_dat: if (m_length == 4 && i == 2) continue; // skip weekday in between - if (std::getline(input, token, '.') == 0) + if (input.eof() == true || std::getline(input, token, '.') == 0) return RESULT_ERR_INVALID_ARG; // incomplete value = parseInt(token.c_str(), 10, 0, 9999, result); if (result != RESULT_OK) @@ -567,7 +566,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, return RESULT_ERR_INVALID_ARG; // invalid date part break; case bt_tim: - if (std::getline(input, token, ':') == 0) + if (input.eof() == true || std::getline(input, token, ':') == 0) return RESULT_ERR_INVALID_ARG; // incomplete value = parseInt(token.c_str(), 10, 0, 59, result); if (result != RESULT_OK) @@ -588,9 +587,13 @@ result_t StringDataField::writeSymbols(std::istringstream& input, } break; default: - value = input.get(); - if (input.eof() == true || value < 0x20) + if (input.eof() == true) value = m_dataType.replacement; + else { + value = input.get(); + if (input.eof() == true || value < 0x20) + value = m_dataType.replacement; + } break; } if ((m_dataType.flags & BCD) != 0) { @@ -798,7 +801,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, else { char* strEnd = NULL; double dvalue = strtod(str, &strEnd); - if (strEnd == NULL || strEnd != 0) + if (strEnd == NULL || *strEnd != 0) return RESULT_ERR_INVALID_ARG; // invalid value dvalue = round(dvalue * m_divisor); if ((m_dataType.flags & SIG) != 0) { diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h old mode 100644 new mode 100755 index daa56d65..747f9a8b --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -71,8 +71,9 @@ typedef struct { * @param minValue the minimum resulting value. * @param maxValue the maximum resulting value. * @param result the variable in which to store an error code when parsing failed or the value is out of bounds. + * @param length the optional variable in which to store the number of read characters. */ -unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result); +unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL); class SingleDataField; From 80c42df040c83cc6444a82aa329c1954fbdd4f53 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 08:33:11 +0100 Subject: [PATCH 02/15] add optional length to parseInt() and set result on success, remove unused stuff, avoid reading beyond eof, check divisor in StringDataField::derive(), fix for NumberDataField::writeSymbols() --- src/lib/ebus/data.cpp | 0 src/lib/ebus/data.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/ebus/data.cpp mode change 100755 => 100644 src/lib/ebus/data.h diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h old mode 100755 new mode 100644 From 75eb227ade8109b7718cacb8c966043ceff805e6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 08:44:24 +0100 Subject: [PATCH 03/15] added test for set, better error messages --- src/lib/ebus/test/test_data.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 62058b68..f100e632 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -84,11 +84,15 @@ int main() {"x;;bcd", "99", "10feffff0199", "00", ""}, {"x;;bcd", "-", "10feffff01ff", "00", ""}, {"x;;bcd", "", "10feffff019a", "00", "rw"}, - {"x;16;uch", "15", "10feffff11000102030405060708090a0b0c0d0e0f10", "00", "W"}, + {"x;16;uch", "15", "10feffff11000102030405060708090a0b0c0d0e0f10", "00", "W"}, {"x;17;uch", "", "10feffff00", "00", "c"}, - {"x;s3;uch", "2", "1025ffff0310111213", "0300010203", "W"}, - {"x;s3;uch", "2", "1025ffff00", "00000002", ""}, - {"x;s3;uch;;;;y;m2;uch", "2;3","1025ffff020003", "00000002", ""}, + {"x;s3;uch", "2", "1025ffff0310111213", "0300010203", "W"}, + {"x;s3;uch", "2", "1025ffff00", "03000002", ""}, + {"x;3;uch", "2", "1025ffff03010101", "03000002", "W"}, + {"x;3;uch", "1", "1025ffff03010101", "03000002", "sW"}, + {"x;1;uch", "2", "1025ffff00", "0102", ""}, + {"x;1;uch", "1", "1025ffff0101", "00", "s"}, + {"x;s3;uch;;;;y;m2;uch", "2;3","1025ffff020003", "03000002", ""}, {"x;;uch", "38", "10feffff0126", "00", ""}, {"x;;uch", "0", "10feffff0100", "00", ""}, {"x;;uch", "254", "10feffff01fe", "00", ""}, @@ -225,17 +229,18 @@ int main() else std::cout << "\"" << check[0] << "\": failed create OK" << std::endl; continue; - } else if (result != RESULT_OK) { + } + if (result != RESULT_OK) { std::cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << std::endl; continue; } if (fields == NULL) { - std::cout << "\"" << check[0] << "\": create error: empty" << std::endl; + std::cout << "\"" << check[0] << "\": create error: NULL" << std::endl; continue; } if (it != entries.end()) { - std::cout << "\"" << check[0] << "\": create error: non-empty" << std::endl; + std::cout << "\"" << check[0] << "\": create error: trailing input" << std::endl; continue; } std::cout << "\"" << check[0] << "\": create OK" << std::endl; From 7bbceec8ed635b6ae2ae5fc5ad22d95896ce0b4f Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 08:47:02 +0100 Subject: [PATCH 04/15] started development of new Message class --- src/lib/ebus/message.cpp | 169 ++++++++++++++++++++++++++++ src/lib/ebus/message.h | 171 +++++++++++++++++++++++++++++ src/lib/ebus/test/test_message.cpp | 111 +++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 src/lib/ebus/message.cpp create mode 100644 src/lib/ebus/message.h create mode 100644 src/lib/ebus/test/test_message.cpp diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp new file mode 100644 index 00000000..b174e3b8 --- /dev/null +++ b/src/lib/ebus/message.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) John Baier 2014 + * + * This file is part of ebusd. + * + * ebusd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ebusd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ebusd. If not, see http://www.gnu.org/licenses/. + */ + +#include "message.h" +#include "data.h" +#include "result.h" +#include "symbol.h" +#include +#include +#include + +result_t Message::create(std::vector::iterator& it, const std::vector::iterator end, + const std::map templates, Message*& returnValue) +{ + result_t result; + // [type];class;name;[comment];[QQ];ZZ;id;fields... + if (it == end) + return RESULT_ERR_EOF; + + const char* str = (*it++).c_str(); + if (it == end) + return RESULT_ERR_EOF; + bool isSetMessage, isActiveMessage; + unsigned int pollPriority = 0; + if (strcasecmp(str, "W") == 0) { + isActiveMessage = true; + isSetMessage = true; + } else if (str[0] == 'C' || str[0] == 'c') { + isActiveMessage = false; + isSetMessage = str[1] == 'W' || str[1] == 'w'; + } else if (str[0] == 'P' || str[0] == 'p') { + isActiveMessage = true; + isSetMessage = false; + if (str[1] == 0) + pollPriority = 1; + else { + result_t result; + pollPriority = parseInt(str+1, 10, 1, 9, result); + if (result != RESULT_OK) + return result; + } + } else { + isActiveMessage = true; + isSetMessage = false; + } + + std::string clazz = *it++; + if (it == end) + return RESULT_ERR_EOF; + + std::string name = *it++; + if (it == end) + return RESULT_ERR_EOF; + if (name.length() == 0) + return RESULT_ERR_INVALID_ARG; // empty name + + std::string comment = *it++; + if (it == end) + return RESULT_ERR_EOF; + + str = (*it++).c_str(); + if (it == end) + return RESULT_ERR_EOF; + unsigned char srcAddress; + if (*str == 0 || isActiveMessage == true) + srcAddress = SYN; // no specific source defined, or ignore for active message + else { + srcAddress = parseInt(str, 16, 0, 0xff, result); + if (result != RESULT_OK) + return result; + if (isMaster(srcAddress) == false) + return RESULT_ERR_INVALID_ARG; + } + + str = (*it++).c_str(); + if (it == end) + return RESULT_ERR_EOF; + + unsigned char dstAddress = parseInt(str, 16, 0, 0xff, result); + if (result != RESULT_OK) + return result; + if (isValidAddress(dstAddress) == false) + return RESULT_ERR_INVALID_ARG; + + std::istringstream input(*it++); // message id (PBSB + optional master data) + std::vector id; + std::string token; + if (it == end) + return RESULT_ERR_EOF; + while (input.eof() == false) { + while (input.peek() == ' ') + input.get(); + if (input.eof() == true) // no more digits + break; + token.clear(); + token.push_back(input.get()); + if (input.eof() == true) + return RESULT_ERR_INVALID_ARG; // too short hex + token.push_back(input.get()); + + unsigned char value = parseInt(token.c_str(), 16, 0, 0xff, result); + if (result != RESULT_OK) + return result; // invalid hex value + id.push_back(value); + } + if (id.size() < 2 || id.size() > 6) + return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID + + DataField* data = NULL; + result = DataField::create(it, end, templates, data, isSetMessage, dstAddress); + if (result != RESULT_OK) + return result; + + returnValue = new Message(clazz, name, isSetMessage, isActiveMessage, comment, srcAddress, dstAddress, id, data, pollPriority); + return RESULT_OK; +} + +result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, std::istringstream& input, char separator) +{ + if (m_isActiveMessage == true) { + masterData.clear(); + masterData.push_back(srcAddress, false); + masterData.push_back(m_dstAddress, false); + masterData.push_back(m_id[0], false); + masterData.push_back(m_id[1], false); + masterData.push_back(m_id.size() - 2, false); // TODO adjust length + for (size_t i=2; iwrite(input, masterData, slaveData, separator); + if (result != RESULT_OK) + return result; + masterData.push_back(masterData.getCRC(), false, false); + } + return RESULT_OK; +} + +result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, + std::ostringstream& output, char separator, bool answer) +{ + if (m_isActiveMessage == true) { + result_t result = m_data->read(masterData, slaveData, output, false, separator); + if (result != RESULT_OK) + return result; + } + else if (answer == true) { + std::istringstream input; // TODO create input from database of internal variables + result_t result = m_data->write(input, masterData, slaveData, separator); + if (result != RESULT_OK) + return result; + } + return RESULT_OK; +} diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h new file mode 100644 index 00000000..8d5aadda --- /dev/null +++ b/src/lib/ebus/message.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) John Baier 2014 + * + * This file is part of ebusd. + * + * ebusd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ebusd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ebusd. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef LIBEBUS_MESSAGE_H_ +#define LIBEBUS_MESSAGE_H_ + +#include "data.h" +#include "result.h" +#include "symbol.h" +#include +#include + +/** + * @brief Base class for all kinds of bus messages. + */ +class Message +{ +public: + + /** + * @brief Constructs a new instance. + * @param class the optional device class. + * @param name the message name (unique within the same class and type). + * @param isSetMessage whether this is a set message. + * @param isActiveMessage true if message can be initiated by the daemon + * itself any any other participant, false if message can only be initiated + * by a participant other than the daemon. + * @param comment the comment. + * @param srcAddress the source address (optional if passive), or @a SYN for any. + * @param dstAddress the destination address. + * @param id the primary, secondary, and optional further ID bytes. + * @param data the @a DataField for encoding/decoding the message. + * @param pollPriority the priority for polling, or 0 for no polling at all. + */ + Message(const std::string clazz, const std::string name, const bool isSetMessage, + const bool isActiveMessage, const std::string comment, + const unsigned char srcAddress, const unsigned char dstAddress, + const std::vector id, DataField* data, + const unsigned int pollPriority) + : m_class(clazz), m_name(name), m_isSetMessage(isSetMessage), + m_isActiveMessage(isActiveMessage), m_comment(comment), + m_srcAddress(srcAddress), m_dstAddress(dstAddress), + m_id(id), m_data(data), m_pollPriority(pollPriority) {} + /** + * @brief Destructor. + */ + virtual ~Message() { delete m_data; } + /** + * @brief Factory method for creating a new instance. + * @param it the iterator to traverse for the definition parts. + * @param end the iterator pointing to the end of the definition parts. + * @param templates a map of @a DataField templates to be referenced by name. + * @param returnValue the variable in which to store the created instance. + * @return @a RESULT_OK on success, or an error code. + * Note: the caller needs to free the created instance. + */ + static result_t create(std::vector::iterator& it, const std::vector::iterator end, + const std::map templates, Message*& returnValue); + /** + * @brief Get the optional device class. + * @return the optional device class. + */ + std::string getClass() const { return m_class; } + /** + * @brief Get the message name (unique within the same class and type). + * @return the message name (unique within the same class and type). + */ + std::string getName() const { return m_name; } + /** + * @brief Get whether this is a set message. + * @return whether this is a set message. + */ + bool isSetMessage() const { return m_isSetMessage; } + /** + * @brief Get whether message can be initiated by the daemon itself and any other + * participant. + * @return true if message can be initiated by the daemon itself and any other + * participant, false if message can only be initiated by a participant + * other than the daemon. + */ + bool isActiveMessage() const { return m_isActiveMessage; } + /** + * @brief Get the comment. + * @return the comment. + */ + std::string getComment() const { return m_comment; } + /** + * @brief Get the source address. + * @return the source address, or @a SYN for any. + */ + unsigned char getSrcAddress() const { return m_srcAddress; } + /** + * @brief Get the destination address. + * @return the destination address. + */ + unsigned char getDstAddress() const { return m_dstAddress; } + /** + * @brief Get the command ID bytes. + * @return the primary, secondary, and optionally further command ID bytes. + */ + std::vector getId() const { return m_id; } + /** + * @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 @a std::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 @a RESULT_OK on success, or an error code. + */ + //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 @a std::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 @a RESULT_OK on success, or an error code. + */ + result_t prepare(const unsigned char srcAddress, SymbolString& masterData, + std::istringstream& input, char separator=';'); + result_t handle(SymbolString& masterData, SymbolString& slaveData, + std::ostringstream& output, char separator=';', bool answer=false); + + +private: + + /** the optional device class. */ + const std::string m_class; + /** the message name (unique within the same class and type). */ + const std::string m_name; + /** whether this is a set message. */ + const bool m_isSetMessage; + /** true if message can be initiated by the daemon itself and any other + * participant, false if message can only be initiated by a participant + * other than the daemon. */ + const bool m_isActiveMessage; + /** the comment. */ + const std::string m_comment; + /** the source address (optional if passive), or @a SYN for any. */ + const unsigned char m_srcAddress; + /** the destination address. */ + const unsigned char m_dstAddress; + /** the primary, secondary, and optionally further command ID bytes. */ + const std::vector m_id; + /** the @a DataField for encoding/decoding the message. */ + DataField* m_data; + /** the priority for polling, or 0 for no polling at all. */ + const unsigned char m_pollPriority; + +}; + +#endif // LIBEBUS_MESSAGE_H_ diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp new file mode 100644 index 00000000..fe4a9723 --- /dev/null +++ b/src/lib/ebus/test/test_message.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) John Baier 2014 + * + * This file is part of libebus. + * + * libebus is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libebus is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libebus. If not, see http://www.gnu.org/licenses/. + */ + +#include "message.h" +#include +#include + +void verify(bool expectFailMatch, std::string type, std::string input, + bool match, std::string expectStr, std::string gotStr) +{ + if (expectFailMatch == true) { + if (match == true) + std::cout << " failed " << type << " match >" << input + << "< error: unexpectedly succeeded" << std::endl; + else + std::cout << " failed " << type << " match >" << input << "< OK" + << std::endl; + } + else if (match == true) + std::cout << " " << type << " >" << input << "< OK" << std::endl; + else + std::cout << " " << type << " >" << input << "< error: got >" << gotStr + << "<, expected >" << expectStr << "<" << std::endl; +} + +int main() +{ + // message= [type];class;name;[comment];[QQ];ZZ;id;fields... + // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] + std::string checks[][5] = { + // "message", "flags" + {";;first;;;fe;0700;x;;bda", "26.10.2014", "10fe07000426100014", "00", ""}, + {";;first;;;15;b509;id;x;;bda", "26.10.2014", "10fe07000426100014", "00", ""}, + }; + std::map templates; + Message* message = NULL; + for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { + std::string check[5] = checks[i]; + std::istringstream isstr(check[0]); + std::string expectStr = check[1]; + SymbolString mstr = SymbolString(check[2], false); + SymbolString sstr = SymbolString(check[3], false); + std::string flags = check[4]; + bool failedCreate = flags.find('c') != std::string::npos; + std::string item; + std::vector entries; + + while (std::getline(isstr, item, ';') != 0) + entries.push_back(item); + + if (message != NULL) { + delete message; + message = NULL; + } + std::vector::iterator it = entries.begin(); + result_t result = Message::create(it, entries.end(), templates, message); + + if (failedCreate == true) { + if (result == RESULT_OK) + std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl; + else + std::cout << "\"" << check[0] << "\": failed create OK" << std::endl; + continue; + } + if (result != RESULT_OK) { + std::cout << "\"" << check[0] << "\": create error: " + << getResultCode(result) << std::endl; + continue; + } + if (message == NULL) { + std::cout << "\"" << check[0] << "\": create error: NULL" << std::endl; + continue; + } + if (it != entries.end()) { + std::cout << "\"" << check[0] << "\": create error: trailing input" << std::endl; + continue; + } + std::cout << "\"" << check[0] << "\": create OK" << std::endl; + + std::istringstream input(expectStr); + result = message->prepare(SYN, mstr, input); + if (result != RESULT_OK) + std::cout << " prepare >" << expectStr << "< error: " + << getResultCode(result) << std::endl; + + delete message; + message = NULL; + } + + for (std::map::iterator it = templates.begin(); it != templates.end(); it++) + delete it->second; + + return 0; + +} From 54de8319c9d9cc94480cb2f64c5be3b4c9c01911 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 09:24:03 +0100 Subject: [PATCH 05/15] better verify message --- src/lib/ebus/test/test_data.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index f100e632..a689a3b7 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -33,9 +33,9 @@ void verify(bool expectFailMatch, std::string type, std::string input, << std::endl; } else if (match == true) - std::cout << " " << type << " >" << input << "< OK" << std::endl; + std::cout << " " << type << " match >" << input << "< OK" << std::endl; else - std::cout << " " << type << " >" << input << "< error: got >" << gotStr + std::cout << " " << type << " match >" << input << "< error: got >" << gotStr << "<, expected >" << expectStr << "<" << std::endl; } From 8461c66103cc11a7c8a1c999e9ce266eb1d1c6ee Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 09:41:11 +0100 Subject: [PATCH 06/15] fixed getNextOffset() and added optional PartType argument, renamed pt_template to pt_any, added getPartType() --- src/lib/ebus/data.cpp | 29 ++++++++++++++++++++--------- src/lib/ebus/data.h | 20 +++++++++++++------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 413b9edc..b993330e 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -165,7 +165,7 @@ result_t DataField::create(std::vector::iterator& it, posStr++; } else if (isTemplate) { - partType = pt_template; + partType = pt_any; } else { result = RESULT_ERR_INVALID_ARG; @@ -174,7 +174,7 @@ result_t DataField::create(std::vector::iterator& it, if (posStr[0] == 0) { if (fields.empty() == false) - offset = fields.back()->getNextOffset(); + offset = fields.back()->getNextOffset(partType); else offset = 0; length = 0; @@ -274,7 +274,7 @@ result_t DataField::create(std::vector::iterator& it, result = ref->second->derive(name, comment, unit, partType, offset, divisor, values, fields); if (result != RESULT_OK) break; - offset = fields.back()->getNextOffset(); + offset = fields.back()->getNextOffset(partType); } if (offset > MAX_POS) { result = RESULT_ERR_INVALID_ARG; // invalid pos definition @@ -362,8 +362,11 @@ result_t DataField::create(std::vector::iterator& it, } -unsigned char SingleDataField::getNextOffset() +unsigned char SingleDataField::getNextOffset(PartType partType) { + if (partType != pt_any && partType != m_partType) + return 0; + unsigned char offset = m_offset + m_length; if ((m_dataType.numBits % 8) != 0 && m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) < 8) @@ -429,7 +432,7 @@ result_t StringDataField::derive(std::string name, std::string comment, unsigned int divisor, std::map values, std::vector& fields) { - if (m_partType != pt_template && partType == pt_template) + if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance if (divisor != 0 || values.empty() == false) return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field @@ -706,7 +709,7 @@ result_t NumberDataField::derive(std::string name, std::string comment, unsigned int divisor, std::map values, std::vector& fields) { - if (m_partType != pt_template && partType == pt_template) + if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance if (name.empty() == true) name = m_name; @@ -840,7 +843,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment, unsigned int divisor, std::map values, std::vector& fields) { - if (m_partType != pt_template && partType == pt_template) + if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance if (name.empty() == true) name = m_name; @@ -911,9 +914,17 @@ DataFieldSet::~DataFieldSet() } } -unsigned char DataFieldSet::getNextOffset() +unsigned char DataFieldSet::getNextOffset(PartType partType) { - return m_fields.back()->getNextOffset(); + return 0; + + for (std::vector::reverse_iterator it = m_fields.rbegin(); it < m_fields.rend(); it++) { + SingleDataField* field = *it; + if (partType == pt_any || partType == field->getPartType()) + return field->getNextOffset(partType); + } + + return 0; } result_t DataFieldSet::derive(std::string name, std::string comment, diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 747f9a8b..c2fa4ec4 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -28,7 +28,7 @@ /** the message part in which a data field is stored. */ enum PartType { - pt_template, // special part type for templates (relative offset) + pt_any, // stored in any data (master or slave, relative offset) pt_masterData, // stored in master data pt_slaveData, // stored in slave data }; @@ -112,9 +112,10 @@ public: 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. + * @param partType the message part for which to get the offset, or @a pt_any for any. * @return the offset to the first symbol in the message part for a field following this field. */ - virtual unsigned char getNextOffset() = 0; + virtual unsigned char getNextOffset(PartType partType=pt_any) = 0; /** * @brief Derives a new DataField from this field. * @param name the field name. @@ -134,12 +135,12 @@ public: * @brief Get the field name. * @return the field name. */ - const std::string getName() { return m_name; } + std::string getName() const { return m_name; } /** * @brief Get the field comment. * @return the field comment. */ - const std::string getComment() { return m_comment; } + std::string getComment() const { 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. @@ -204,9 +205,14 @@ public: * @brief Get the value unit. * @return the value unit. */ - const std::string getUnit() { return m_unit; } + std::string getUnit() const { return m_unit; } + /** + * @brief Get the message part in which the field is stored. + * @return the message part in which the field is stored. + */ + PartType getPartType() const { return m_partType; } // @copydoc - virtual unsigned char getNextOffset(); + virtual unsigned char getNextOffset(PartType partType=pt_any); /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -470,7 +476,7 @@ public: */ virtual ~DataFieldSet(); // @copydoc - virtual unsigned char getNextOffset(); + virtual unsigned char getNextOffset(PartType partType=pt_any); // @copydoc virtual result_t derive(std::string name, std::string comment, std::string unit, const PartType partType, unsigned char offset, From 64e353737c27419c38eb659b472dd6f5f4c3169a Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 09:58:51 +0100 Subject: [PATCH 07/15] added check for prepare, print error pos --- src/lib/ebus/test/test_message.cpp | 61 +++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index fe4a9723..322e95e9 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -33,31 +33,58 @@ void verify(bool expectFailMatch, std::string type, std::string input, << std::endl; } else if (match == true) - std::cout << " " << type << " >" << input << "< OK" << std::endl; + std::cout << " " << type << " match >" << input << "< OK" << std::endl; else - std::cout << " " << type << " >" << input << "< error: got >" << gotStr + std::cout << " " << type << " match >" << input << "< error: got >" << gotStr << "<, expected >" << expectStr << "<" << std::endl; } +void printErrorPos(std::vector::iterator it, const std::vector::iterator end, std::vector::iterator pos) +{ + std::cout << "Errroneous item is here:" << std::endl; + bool first = true; + int cnt = 0; + if (pos > it) + pos--; + while (it != end) { + if (first == true) + first = false; + else { + std::cout << ';'; + if (it <= pos) { + cnt++; + } + } + if (it < pos) { + cnt += (*it).length(); + } + std::cout << (*it++); + } + std::cout << std::endl; + std::cout << std::setw(cnt) << " " << std::setw(0) << "^" << std::endl; +} + int main() { // message= [type];class;name;[comment];[QQ];ZZ;id;fields... // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] std::string checks[][5] = { // "message", "flags" - {";;first;;;fe;0700;x;;bda", "26.10.2014", "10fe07000426100014", "00", ""}, - {";;first;;;15;b509;id;x;;bda", "26.10.2014", "10fe07000426100014", "00", ""}, + {";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610001451", "00", ""}, + {";;first;;;15;b5090400;date;1;bda", "26.10.2014", "ff15b50904040026100014cc", "00", ""}, }; std::map templates; Message* message = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { std::string check[5] = checks[i]; std::istringstream isstr(check[0]); - std::string expectStr = check[1]; + std::string inputStr = check[1]; SymbolString mstr = SymbolString(check[2], false); SymbolString sstr = SymbolString(check[3], false); std::string flags = check[4]; bool failedCreate = flags.find('c') != std::string::npos; + bool failedPrepare = flags.find('p') != std::string::npos; + bool failedPrepareMatch = flags.find('P') != std::string::npos; std::string item; std::vector entries; @@ -81,6 +108,7 @@ int main() if (result != RESULT_OK) { std::cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << std::endl; + printErrorPos(entries.begin(), entries.end(), it); continue; } if (message == NULL) { @@ -93,11 +121,26 @@ int main() } std::cout << "\"" << check[0] << "\": create OK" << std::endl; - std::istringstream input(expectStr); - result = message->prepare(SYN, mstr, input); - if (result != RESULT_OK) - std::cout << " prepare >" << expectStr << "< error: " + std::istringstream input(inputStr); + SymbolString writeMstr = SymbolString(); + result = message->prepare(0xff, writeMstr, input); + if (failedPrepare == true) { + if (result == RESULT_OK) + std::cout << "\"" << check[0] << "\": failed prepare error: unexpectedly succeeded" << std::endl; + else + std::cout << "\"" << check[0] << "\": failed prepare OK" << std::endl; + continue; + } + + if (result != RESULT_OK) { + std::cout << " prepare >" << inputStr << "< error: " << getResultCode(result) << std::endl; + continue; + } + std::cout << " prepare >" << inputStr << "< OK" << std::endl; + + bool match = writeMstr==mstr; + verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); delete message; message = NULL; From 9ba0036191a7a21b5eeaf655a7be43dcc45bf374 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 09:59:31 +0100 Subject: [PATCH 08/15] added data length --- src/lib/ebus/message.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index b174e3b8..efa1d24e 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -139,11 +139,12 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa masterData.push_back(m_dstAddress, false); masterData.push_back(m_id[0], false); masterData.push_back(m_id[1], false); - masterData.push_back(m_id.size() - 2, false); // TODO adjust length + unsigned char addData = m_data->getNextOffset(pt_masterData); + masterData.push_back(m_id.size() - 2 + addData, false); for (size_t i=2; iwrite(input, masterData, slaveData, separator); + result_t result = m_data->write(input, masterData, slaveData, separator); // TODO m_id.size() - 2 if (result != RESULT_OK) return result; masterData.push_back(masterData.getCRC(), false, false); From 2317bd206fd4dd1d6dfa98d90fc78669de51c6a4 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 13:36:01 +0100 Subject: [PATCH 09/15] removed absolute positions, fix for part def --- src/lib/ebus/data.cpp | 201 +++++++++++++++----------------- src/lib/ebus/data.h | 158 ++++++++++++------------- src/lib/ebus/test/test_data.cpp | 60 ++++------ 3 files changed, 195 insertions(+), 224 deletions(-) mode change 100644 => 100755 src/lib/ebus/data.cpp diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp old mode 100644 new mode 100755 index b993330e..72bff285 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -132,13 +132,13 @@ result_t DataField::create(std::vector::iterator& it, std::string unit, comment; PartType partType; unsigned int divisor = 0; - unsigned char offset, length, offsetCnt = 0; + unsigned char length; const bool isTemplate = dstAddress == SYN; std::string token; if (it == end) break; - // name;[pos];type[;[divisor|values][;[unit][;[comment]]]] + // name;[m|s][len];type[;[divisor|values][;[unit][;[comment]]]] const std::string name = *it++; if (it == end) break; @@ -152,13 +152,13 @@ result_t DataField::create(std::vector::iterator& it, firstComment = comment; } if (dstAddress == BROADCAST || isMaster(dstAddress) - || (isTemplate == false && isSetMessage == true && posStr[0] != 0 && posStr[0] <= '9') + || (isTemplate == false && isSetMessage == true && (posStr[0] == 0 || posStr[0] <= '9')) || posStr[0] == 'm') { // master data partType = pt_masterData; if (posStr[0] == 'm') posStr++; } - else if ((isTemplate == false && isSetMessage == false && posStr[0] != 0 && posStr[0] <= '9') + else if ((isTemplate == false && isSetMessage == false && (posStr[0] == 0 || posStr[0] <= '9')) || posStr[0] == 's') { // slave data partType = pt_slaveData; if (posStr[0] == 's') @@ -173,33 +173,10 @@ result_t DataField::create(std::vector::iterator& it, } if (posStr[0] == 0) { - if (fields.empty() == false) - offset = fields.back()->getNextOffset(partType); - else - offset = 0; length = 0; } else { - offset = 0; - length = 0; - std::istringstream stream(posStr); - while (std::getline(stream, token, '-') != 0) { - if (++offsetCnt > 2) - return RESULT_ERR_INVALID_ARG; //invalid pos definition - - unsigned int pos = parseInt(token.c_str(), 10, 1, MAX_POS + 1, result) - 1; // input is 1-based - if (result != RESULT_OK) - break; - - if (offsetCnt == 1) - offset = pos; - else if (pos >= offset) - length = pos + 1 - offset; - else { // wrong order e.g. 4-3 - length = offset - (pos + 1); - offset = pos; - } - } + length = parseInt(posStr, 10, 1, MAX_POS, result); if (result != RESULT_OK) break; } @@ -271,14 +248,9 @@ result_t DataField::create(std::vector::iterator& it, break; } found = true; - result = ref->second->derive(name, comment, unit, partType, offset, divisor, values, fields); + result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); if (result != RESULT_OK) break; - offset = fields.back()->getNextOffset(partType); - } - if (offset > MAX_POS) { - result = RESULT_ERR_INVALID_ARG; // invalid pos definition - break; } if (found == true || result != RESULT_OK) break; @@ -301,10 +273,6 @@ result_t DataField::create(std::vector::iterator& it, useLength = numBytes; else if (useLength != numBytes) continue; // check for another one with same name but different length - if (offset + useLength > MAX_POS) { - result = RESULT_ERR_INVALID_ARG; // invalid pos definition - break; - } switch (dataType.type) { @@ -312,7 +280,7 @@ result_t DataField::create(std::vector::iterator& it, case bt_hexstr: case bt_dat: case bt_tim: - add = new StringDataField(name, comment, unit, dataType, partType, offset, useLength); + add = new StringDataField(name, comment, unit, dataType, partType, useLength); break; case bt_num: if (values.empty() == true && (dataType.flags & DAY) != 0) { @@ -326,7 +294,7 @@ result_t DataField::create(std::vector::iterator& it, else divisor *= dataType.divisor; - add = new NumberDataField(name, comment, unit, dataType, partType, offset, useLength, divisor); + add = new NumberDataField(name, comment, unit, dataType, partType, useLength, divisor); break; } if (values.begin()->first < dataType.minValueOrLength @@ -335,7 +303,7 @@ result_t DataField::create(std::vector::iterator& it, break; } - add = new ValueListDataField(name, comment, unit, dataType, partType, offset, useLength, values); + add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, values); break; } } @@ -362,31 +330,26 @@ result_t DataField::create(std::vector::iterator& it, } -unsigned char SingleDataField::getNextOffset(PartType partType) +bool SingleDataField::hasFullByteOffset() { - if (partType != pt_any && partType != m_partType) - return 0; - - unsigned char offset = m_offset + m_length; - if ((m_dataType.numBits % 8) != 0 - && m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) < 8) - offset--; // not all bits of last offset fully consumed - - return offset; + return m_length > 1 || (m_dataType.numBits % 8) == 0 + || m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) >= 8; } -result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData, - std::ostringstream& output, bool verbose, char separator) +result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, + bool verbose, char separator) { SymbolString& input = m_partType == pt_masterData ? masterData : slaveData; - unsigned char baseOffset; + unsigned char offset; switch (m_partType) { case pt_masterData: - baseOffset = 5; // skip QQ ZZ PB SB NN + offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: - baseOffset = 1; // skip NN + offset = 1 + slaveOffset; // skip NN break; default: return RESULT_ERR_INVALID_ARG; // invalid part type @@ -395,7 +358,7 @@ result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData if (verbose) output << m_name << "="; - result_t result = readSymbols(input, baseOffset, output); + result_t result = readSymbols(input, offset, output); if (result != RESULT_OK) return result; @@ -407,28 +370,30 @@ result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData return RESULT_OK; } -result_t SingleDataField::write(std::istringstream& input, SymbolString& masterData, - SymbolString& slaveData, char separator) +result_t SingleDataField::write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator) { SymbolString& output = m_partType == pt_masterData ? masterData : slaveData; - unsigned char baseOffset; + unsigned char offset; switch (m_partType) { case pt_masterData: - baseOffset = 5; // skip QQ ZZ PB SB NN + offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: - baseOffset = 1; // skip NN + offset = 1 + slaveOffset; // skip NN break; default: return RESULT_ERR_INVALID_ARG; } - return writeSymbols(input, baseOffset, output); + return writeSymbols(input, offset, output); } result_t StringDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -442,9 +407,8 @@ result_t StringDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; - fields.push_back(new StringDataField(name, comment, unit, m_dataType, partType, offset, m_length)); + fields.push_back(new StringDataField(name, comment, unit, m_dataType, partType, m_length)); return RESULT_OK; } @@ -452,20 +416,19 @@ result_t StringDataField::derive(std::string name, std::string comment, result_t StringDataField::readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch, last = 0; - if (baseOffset + end > input.size()) { + if (baseOffset + m_length > input.size()) { return RESULT_ERR_INVALID_ARG; } if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } - for (size_t offset = start, i = 0; offset != end; offset += incr, i++) { + 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 ch = input[baseOffset + offset]; @@ -495,6 +458,7 @@ result_t StringDataField::readSymbols(SymbolString& input, if (i == 0) { ch /= 6; // hours offset -= incr; // repeat for minutes + count++; } else ch = (ch % 6) * 10; // minutes @@ -520,20 +484,19 @@ result_t StringDataField::readSymbols(SymbolString& input, result_t StringDataField::writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned long int value = 0, last = 0; std::string token; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } result_t result; size_t i = 0; - for (size_t offset = start; offset != end; offset += incr, i++) { + for (size_t offset = start; i < count; offset += incr, i++) { switch (m_dataType.type) { case bt_hexstr: @@ -578,8 +541,9 @@ result_t StringDataField::writeSymbols(std::istringstream& input, return RESULT_ERR_INVALID_ARG; // invalid time part if (m_length == 1) { // truncated time if (i == 0) { - offset -= incr; // repeat for minutes last = value; + offset -= incr; // repeat for minutes + count++; continue; } if ((value % 10) != 0) @@ -620,21 +584,20 @@ result_t StringDataField::writeSymbols(std::istringstream& input, result_t NumericDataField::readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch; - if (baseOffset + end > input.size()) + if (baseOffset + m_length > input.size()) return RESULT_ERR_INVALID_ARG; // not enough data available if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } value = 0; - for (size_t offset = start, exp = 1; offset != end; offset += incr) { + for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { ch = input[baseOffset + offset]; if ((m_dataType.flags & BCD) != 0) { if (ch == m_dataType.replacement) { @@ -665,13 +628,12 @@ result_t NumericDataField::readRawValue(SymbolString& input, result_t NumericDataField::writeRawValue(unsigned int value, unsigned char baseOffset, SymbolString& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } @@ -680,7 +642,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, value &= (1 << m_dataType.numBits) - 1; value <<= m_bitOffset; } - for (size_t offset = start, exp = 1; offset != end; offset += incr) { + for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { if ((m_dataType.flags & BCD) != 0) { if (value == m_dataType.replacement) ch = m_dataType.replacement; @@ -705,7 +667,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, result_t NumberDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -717,7 +679,6 @@ result_t NumberDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; if (divisor == 0) divisor = m_divisor; else @@ -726,10 +687,10 @@ result_t NumberDataField::derive(std::string name, std::string comment, if (divisor != 1) return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field - fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, offset, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); } else - fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, offset, m_length, divisor)); + fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, divisor)); return RESULT_OK; } @@ -839,7 +800,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, result_t ValueListDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -851,7 +812,6 @@ result_t ValueListDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; if (divisor != 0 && divisor != 1) return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field @@ -863,7 +823,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment, else values = m_values; - fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, offset, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); return RESULT_OK; } @@ -914,21 +874,27 @@ DataFieldSet::~DataFieldSet() } } -unsigned char DataFieldSet::getNextOffset(PartType partType) +unsigned char DataFieldSet::getLength(PartType partType) { - return 0; + unsigned char length = 0; - for (std::vector::reverse_iterator it = m_fields.rbegin(); it < m_fields.rend(); it++) { + bool previousFullByteOffset[] = { true, true, true }; + for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; - if (partType == pt_any || partType == field->getPartType()) - return field->getNextOffset(partType); + if (field->getPartType() == partType) { + length += field->getLength(partType); + if (previousFullByteOffset[partType] == false) { + length--; + } + previousFullByteOffset[partType] = field->hasFullByteOffset(); + } } - return 0; + return length; } result_t DataFieldSet::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -936,7 +902,7 @@ result_t DataFieldSet::derive(std::string name, std::string comment, return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { - result_t result = (*it)->derive("", "", "", partType, offset, divisor, values, fields); + result_t result = (*it)->derive("", "", "", partType, divisor, values, fields); if (result != RESULT_OK) return result; } @@ -944,23 +910,34 @@ result_t DataFieldSet::derive(std::string name, std::string comment, return RESULT_OK; } -result_t DataFieldSet::read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, - bool verbose, char separator) +result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, bool verbose, char separator) { if (verbose) output << m_name << "={ "; bool first = true; + unsigned char offsets[] = { 0, masterOffset, slaveOffset }; + bool previousFullByteOffset[] = { true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { if (first) first = false; else output << separator; - result_t result = (*it)->read(masterData, slaveData, output, verbose); + SingleDataField* field = *it; + PartType partType = field->getPartType(); + if (previousFullByteOffset[partType] == false) { + offsets[partType]--; + } + result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator); if (result != RESULT_OK) return result; + + offsets[partType] += field->getLength(partType); + previousFullByteOffset[partType] = field->hasFullByteOffset(); } if (verbose) { @@ -972,24 +949,36 @@ result_t DataFieldSet::read(SymbolString& masterData, SymbolString& slaveData, s return RESULT_OK; } -result_t DataFieldSet::write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, +result_t DataFieldSet::write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, char separator) { std::string token; + unsigned char offsets[] = { 0, masterOffset, slaveOffset }; + bool previousFullByteOffset[] = { true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + SingleDataField* field = *it; + PartType partType = field->getPartType(); + if (previousFullByteOffset[partType] == false) { + offsets[partType]--; + } result_t result; if (m_fields.size() > 1) { if (std::getline(input, token, separator) == 0) return RESULT_ERR_INVALID_ARG; // incomplete std::istringstream single(token); - result = (*it)->write(single, masterData, slaveData); + result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); } else - result = (*it)->write(input, masterData, slaveData); + result = (*it)->write(input, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); if (result != RESULT_OK) return result; + + offsets[partType] += field->getLength(partType); + previousFullByteOffset[partType] = field->hasFullByteOffset(); } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index c2fa4ec4..083df206 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -28,7 +28,7 @@ /** the message part in which a data field is stored. */ enum PartType { - pt_any, // stored in any data (master or slave, relative offset) + pt_any, // stored in any data (master or slave) pt_masterData, // stored in master data pt_slaveData, // stored in slave data }; @@ -53,7 +53,7 @@ const unsigned int DAY = 0x20; // forced value list defaulting to week days /** the structure for defining field types with their properties. */ typedef struct { const char* name; // field identifier - const unsigned int numBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag BCD) + const unsigned int numBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD) const BaseType type; // base data type const unsigned int flags; // flags (e.g. @a BCD) const unsigned int replacement; // replacement value (fill-up value for @a bt_str / @a bt_hexstr, no replacement if equal to @a minValueOrLength for @a bt_num) @@ -111,24 +111,23 @@ public: const std::map templates, DataField*& returnField, 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. - * @param partType the message part for which to get the offset, or @a pt_any for any. - * @return the offset to the first symbol in the message part for a field following this field. + * @brief Returns the length of this field (or contained fields) in bytes. + * @param partType the message part of the contained fields to limit the length calculation to. + * @return the length of this field (or contained fields) in bytes. */ - virtual unsigned char getNextOffset(PartType partType=pt_any) = 0; + virtual unsigned char getLength(PartType partType) = 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). * @param fields the @a std::vector to which created @a SingleDataField instances shall be added. */ virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) = 0; /** @@ -151,7 +150,9 @@ public: * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, bool verbose=false, char separator=';') = 0; /** * @brief Writes the value to the master or slave @a SymbolString. @@ -161,7 +162,9 @@ public: * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, char separator=';') = 0; protected: @@ -188,15 +191,14 @@ public: * @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) + const unsigned char length) : DataField(name, comment), m_unit(unit), m_dataType(dataType), m_partType(partType), - m_offset(offset), m_length(length) {} + m_length(length) {} /** * @brief Destructor. */ @@ -212,44 +214,61 @@ public: */ PartType getPartType() const { return m_partType; } // @copydoc - virtual unsigned char getNextOffset(PartType partType=pt_any); + virtual unsigned char getLength(PartType partType) { return partType == m_partType ? m_length : 0; }; + // re-use same position as previous field as not all bits of fully consumed yet + /** + * @brief Get whether this field uses a full byte offset. + * @return true if this field uses a full byte offset, false if this field + * only consumes a part of a byte and a subsequent field may re-use the same offset. + */ + bool hasFullByteOffset(); /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. + * @param masterOffset the extra offset for reading master data. * @param slaveData the unescaped slave data @a SymbolString for reading binary data. + * @param slaveOffset the extra offset for reading slave 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). * @return @a RESULT_OK on success, or an error code. */ - virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, - bool verbose=false, char separator=';'); + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, + bool verbose, char separator); /** * @brief Writes the value to the master or slave @a SymbolString. * @param input the @a std::istringstream to parse the formatted value from. * @param masterData the unescaped master data @a SymbolString for writing binary data. + * @param masterOffset the extra offset for writing master data. * @param slaveData the unescaped slave data @a SymbolString for writing binary data. + * @param slaveOffset the extra offset for writing slave data. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, - char separator=';'); + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator); protected: /** * @brief Internal method for reading the field from a @a SymbolString. * @param input the unescaped @a SymbolString to read the binary value from. + * @param offset the offset in the @a SymbolString. * @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, unsigned char baseOffset, std::ostringstream& output) = 0; + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output) = 0; /** * @brief Internal method for writing the field to a @a SymbolString. * @param input the @a std::istringstream to parse the formatted value from. + * @param offset the offset in the @a SymbolString. * @param output the unescaped @a SymbolString to write the binary value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) = 0; + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output) = 0; /** the value unit. */ const std::string m_unit; @@ -257,8 +276,6 @@ protected: 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; @@ -279,29 +296,28 @@ public: * @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. */ 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) {} + const unsigned char length) + : SingleDataField(name, comment, unit, dataType, partType, length) {} /** * @brief Destructor. */ virtual ~StringDataField() {} // @copydoc virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields); protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); }; @@ -320,15 +336,13 @@ public: * @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. */ 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 unsigned char bitOffset) - : SingleDataField(name, comment, unit, dataType, partType, offset, length), + const unsigned char length, const unsigned char bitOffset) + : SingleDataField(name, comment, unit, dataType, partType, length), m_bitOffset(bitOffset) {} /** * @brief Destructor. @@ -340,17 +354,19 @@ 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. + * @param offset the offset in the @a SymbolString. * @param value the variable in which to store the raw value. * @return @a RESULT_OK on success, or an error code. */ - result_t readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value); + result_t readRawValue(SymbolString& input, const unsigned char offset, unsigned int& value); /** * @brief Internal method for writing the raw value to a @a SymbolString. * @param value the raw value to write. + * @param offset the offset in the @a SymbolString. * @param output the unescaped @a SymbolString to write the binary value to. * @return @a RESULT_OK on success, or an error code. */ - result_t writeRawValue(unsigned int value, unsigned char baseOffset, SymbolString& output); + result_t writeRawValue(unsigned int value, const unsigned char offset, SymbolString& output); /** the offset to the first bit in the binary value. */ const unsigned char m_bitOffset; @@ -372,33 +388,31 @@ public: * @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 divisor the extra divisor to apply on the value, or 1 for none. */ 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 unsigned int divisor) - : NumericDataField(name, comment, unit, dataType, partType, offset, length, + const unsigned char length, const unsigned int divisor) + : NumericDataField(name, comment, unit, dataType, partType, length, (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), m_divisor(divisor) {} /** * @brief Destructor. */ virtual ~NumberDataField() {} + // @copydoc + virtual result_t derive(std::string name, std::string comment, + std::string unit, const PartType partType, + unsigned int divisor, std::map values, + std::vector& fields); protected: // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); - // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); /** the combined divisor to apply on the value, or 1 for none. */ const unsigned int m_divisor; @@ -420,33 +434,31 @@ public: * @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 values the value=text assignments. */ 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 std::map values) - : NumericDataField(name, comment, unit, dataType, partType, offset, length, + const unsigned char length, const std::map values) + : NumericDataField(name, comment, unit, dataType, partType, length, (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), m_values(values) {} /** * @brief Destructor. */ virtual ~ValueListDataField() {} + // @copydoc + virtual result_t derive(std::string name, std::string comment, + std::string unit, const PartType partType, unsigned int divisor, + std::map values, + std::vector& fields); protected: // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); - // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); /** the value=text assignments. */ std::map m_values; @@ -476,10 +488,10 @@ public: */ virtual ~DataFieldSet(); // @copydoc - virtual unsigned char getNextOffset(PartType partType=pt_any); + virtual unsigned char getLength(PartType partType); // @copydoc virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields); /** @@ -499,26 +511,16 @@ public: * @return the number of available @a SingleDataField instances. */ 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 @a std::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 @a 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 @a std::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 @a RESULT_OK on success, or an error code. - */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, - char separator=';'); + // @copydoc + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, + bool verbose, char separator); + // @copydoc + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator); protected: diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index a689a3b7..c40d8704 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -42,22 +42,22 @@ void verify(bool expectFailMatch, std::string type, std::string input, int main() { std::string checks[][5] = { - //name;[pos];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags - {"x;1-10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;1-10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, - {"x;1-10;str", " ", "10fe07000a20202020202020202020", "00", ""}, - {"x;1-11;str", "", "10fe07000a20202020202020202020", "00", "rW"}, + //name;[len];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags + {"x;10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, + {"x;10;str", " ", "10fe07000a20202020202020202020", "00", ""}, + {"x;11;str", "", "10fe07000a20202020202020202020", "00", "rW"}, {"x;;hex", "20", "10fe07000120", "00", ""}, - {"x;1-10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;1-11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, + {"x;10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, {"x;;bda", "26.10.2014","10fe07000426100014", "00", ""}, {"x;;bda", "01.01.2000","10fe07000401010000", "00", ""}, {"x;;bda", "31.12.2099","10fe07000431120099", "00", ""}, {"x;;bda", "", "10fe07000432100014", "00", "rw"}, - {"x;1-3;bda","26.10.2014","10fe070003261014", "00", ""}, - {"x;1-3;bda","01.01.2000","10fe070003010100", "00", ""}, - {"x;1-3;bda","31.12.2099","10fe070003311299", "00", ""}, - {"x;1-3;bda","", "10fe070003321299", "00", "rw"}, + {"x;3;bda","26.10.2014","10fe070003261014", "00", ""}, + {"x;3;bda","01.01.2000","10fe070003010100", "00", ""}, + {"x;3;bda","31.12.2099","10fe070003311299", "00", ""}, + {"x;3;bda","", "10fe070003321299", "00", "rw"}, {"x;;bti", "21:04:58", "10fe070003580421", "00", ""}, {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, @@ -84,15 +84,11 @@ int main() {"x;;bcd", "99", "10feffff0199", "00", ""}, {"x;;bcd", "-", "10feffff01ff", "00", ""}, {"x;;bcd", "", "10feffff019a", "00", "rw"}, - {"x;16;uch", "15", "10feffff11000102030405060708090a0b0c0d0e0f10", "00", "W"}, + {"x;16;str", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""}, {"x;17;uch", "", "10feffff00", "00", "c"}, - {"x;s3;uch", "2", "1025ffff0310111213", "0300010203", "W"}, - {"x;s3;uch", "2", "1025ffff00", "03000002", ""}, - {"x;3;uch", "2", "1025ffff03010101", "03000002", "W"}, - {"x;3;uch", "1", "1025ffff03010101", "03000002", "sW"}, - {"x;1;uch", "2", "1025ffff00", "0102", ""}, - {"x;1;uch", "1", "1025ffff0101", "00", "s"}, - {"x;s3;uch;;;;y;m2;uch", "2;3","1025ffff020003", "03000002", ""}, + {"x;s;uch", "0", "1025ffff0310111213", "0300010203", "W"}, + {"x;s;uch", "0", "1025ffff00", "0100", ""}, + {"x;s;uch;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""}, {"x;;uch", "38", "10feffff0126", "00", ""}, {"x;;uch", "0", "10feffff0100", "00", ""}, {"x;;uch", "254", "10feffff01fe", "00", ""}, @@ -161,10 +157,9 @@ int main() {"x;;b34;0=off,1=on","on", "10feffff0108", "00", ""}, {"x;;b34;0=off,1=on","off","10feffff0100", "00", ""}, {"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""}, - {"x;s3;uch","3","1050ffff00", "03000003", ""}, - {"x;s3;uch","3","1050ffff00", "020000", "rW"}, + {"x;s;uch","3","1050ffff00", "0103", ""}, {"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"}, - {"x;;bti;;;;y;;bda;;;;z;6;bdy", "21:04:58;26.10.2014;Sun","10fe07000758042126100614", "00", ""}, // combination + {"x;;bti;;;;y;;bda;;;;z;;bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610001406", "00", ""}, // combination {"x;;bi3;;;;y;;bi5", "1;-", "10feffff0108", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination @@ -173,25 +168,10 @@ int main() {"x;;bi3;;;;y;;bi5;;;;t;;uch", "-;-;9","10feffff020009", "00", "RW"}, // bit combination {"temp;;d2b;;°C;Aussentemperatur","","", "", "t"}, // template with relative pos {"x;;temp","18.004","10fe0700020112", "00", ""}, // reference to template - {"tempoff;2;d2b;;°C;Aussentemperatur","","", "", "t"},// template with offset pos - {"x;;tempoff","18.004","10fe070002ff0112", "00", "W"}, // reference to template {"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos - {"x;2;relrel","18.004;9.5","10fe070004ff011213", "00", "W"}, // reference to template struct - {"reloff;;d2b;;;;y;1;d1c","","", "", "t"}, // template struct with relative+offset pos - {"x;2;reloff","18.004;0.5","10fe070003130112", "00", "W"}, // reference to template struct - {"offrel;2;d2b;;;;y;;d1c","","", "", "t"}, // template struct with offset+relative pos - {"x;2;offrel","18.004;9.5","10fe070005fffe011213", "00", "W"}, // reference to template struct - {"offoff;2;d2b;;;;y;1;d1c","","", "", "t"}, // template struct with offset pos - {"x;2;offoff","18.004;9.5","10fe070004ff130112", "00", "W"}, // reference to template struct + {"x;;relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct {"trelrel;;temp,temp","","", "", "t"}, // template struct with relative pos and ref to templates {"x;;trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct - {"x;2;trelrel","18.004;19.008","10fe070005ff01120213", "00", "W"}, // reference to template struct - {"treloff;;temp,tempoff","","", "", "t"}, // template struct with relative+offset pos - {"x;2;treloff","18.004;19.008","10fe070006ff0112fe0213", "00", "W"}, // reference to template struct - {"toffrel;1;tempoff,temp","","", "", "t"}, // template struct with offset+relative pos - {"x;2;toffrel","18.004;19.008","10fe070003fffe01120213", "00", "W"}, // reference to template struct - {"toffoff;1;tempoff,tempoff","","", "", "t"}, // template struct with offset pos - {"x;2;toffoff","18.004;19.008","10fe070003fffe0112fd0213", "00", "W"}, // reference to template struct }; std::map templates; DataField* fields = NULL; @@ -261,7 +241,7 @@ int main() std::ostringstream output; SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false); SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false); - result = fields->read(mstr, sstr, output, verbose); + result = fields->read(mstr, 0, sstr, 0, output, verbose); if (failedRead == true) if (result == RESULT_OK) std::cout << " failed read " << fields->getName() << " >" @@ -280,7 +260,7 @@ int main() if (verbose == false) { std::istringstream input(expectStr); - result = fields->write(input, writeMstr, writeSstr); + result = fields->write(input, writeMstr, 0, writeSstr, 0); if (failedWrite == true) { if (result == RESULT_OK) std::cout << " failed write " << fields->getName() << " >" From e18d3af04f880d178248167c06e29947b1a5f8f8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 13:36:01 +0100 Subject: [PATCH 10/15] removed absolute positions, fix for part def --- src/lib/ebus/data.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/ebus/data.cpp diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp old mode 100755 new mode 100644 From 1f33218692131a48e875b599fef1f1d7f17a156c Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 13:36:01 +0100 Subject: [PATCH 11/15] removed absolute positions, fix for part def --- src/lib/ebus/message.cpp | 8 ++++---- src/lib/ebus/test/test_message.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index efa1d24e..2620398a 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -139,12 +139,12 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa masterData.push_back(m_dstAddress, false); masterData.push_back(m_id[0], false); masterData.push_back(m_id[1], false); - unsigned char addData = m_data->getNextOffset(pt_masterData); + unsigned char addData = m_data->getLength(pt_masterData); masterData.push_back(m_id.size() - 2 + addData, false); for (size_t i=2; iwrite(input, masterData, slaveData, separator); // TODO m_id.size() - 2 + result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator); if (result != RESULT_OK) return result; masterData.push_back(masterData.getCRC(), false, false); @@ -156,13 +156,13 @@ result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, char separator, bool answer) { if (m_isActiveMessage == true) { - result_t result = m_data->read(masterData, slaveData, output, false, separator); + result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); if (result != RESULT_OK) return result; } else if (answer == true) { std::istringstream input; // TODO create input from database of internal variables - result_t result = m_data->write(input, masterData, slaveData, separator); + result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator); if (result != RESULT_OK) return result; } diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 322e95e9..88021045 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -66,12 +66,12 @@ void printErrorPos(std::vector::iterator it, const std::vector templates; Message* message = NULL; From 24e46f5b449a7f2d9d08afccfccba1e2c0d78d60 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 19:17:30 +0100 Subject: [PATCH 12/15] store bit count separately, added ignored type (IGN), moved field length definition from part to type and allow adjusting length for bit types, added PartType masterDataID, simplfied --- src/lib/ebus/data.cpp | 332 +++++++++++++++++--------------- src/lib/ebus/data.h | 43 +++-- src/lib/ebus/test/test_data.cpp | 48 ++--- 3 files changed, 237 insertions(+), 186 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 72bff285..4ec7d05b 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -29,11 +29,12 @@ /** the known data field types. */ static const dataType_t dataTypes[] = { + {"IGN",16*8,bt_str, IGN|ADJ, 0, 1, 16, 0, 0}, // >= 1 byte ignored data {"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space {"HEX",16*8,bt_hexstr, ADJ, 0, 2, 47, 0, 0}, // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d - {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) + {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) {"BDA", 24, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) - {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) // TODO remove duplicate of BDA + {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) // TODO remove duplicate of BDA {"HDA", 24, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA {"BTI", 24, bt_tim, BCD|REV, 0, 8, 8, 0, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23) {"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b) @@ -52,41 +53,14 @@ static const dataType_t dataTypes[] = { {"D2C", 16, bt_num, SIG, 0x8000, 0x8001, 0x7fff, 16, 2}, // signed number (fraction 1/16), -2047.9 - +2047.9 {"ULG", 32, bt_num, LST, 0xffffffff, 0, 0xfffffffe, 1, 0}, // unsigned integer, 0 - 4294967294 {"SLG", 32, bt_num, SIG, 0x80000000, 0x80000001, 0xffffffff, 1, 0}, // signed integer, -2147483647 - +2147483647 - {"BI0", 1, bt_num, LST, 0, 0, 0x1, 1, 0}, // single bit 0 - {"BI1", 1, bt_num, LST, 0, 0, 0x1, 1, 1}, // single bit 1 - {"BI2", 1, bt_num, LST, 0, 0, 0x1, 1, 2}, // single bit 2 - {"BI3", 1, bt_num, LST, 0, 0, 0x1, 1, 3}, // single bit 3 - {"BI4", 1, bt_num, LST, 0, 0, 0x1, 1, 4}, // single bit 4 - {"BI5", 1, bt_num, LST, 0, 0, 0x1, 1, 5}, // single bit 5 - {"BI6", 1, bt_num, LST, 0, 0, 0x1, 1, 6}, // single bit 6 - {"BI7", 1, bt_num, LST, 0, 0, 0x1, 1, 7}, // single bit 7 - {"B01", 2, bt_num, LST, 0, 0, 0x3, 1, 0}, // two bits 0-1 - {"B12", 2, bt_num, LST, 0, 0, 0x3, 1, 1}, // two bits 1-2 - {"B23", 2, bt_num, LST, 0, 0, 0x3, 1, 2}, // two bits 2-3 - {"B34", 2, bt_num, LST, 0, 0, 0x3, 1, 3}, // two bits 3-4 - {"B45", 2, bt_num, LST, 0, 0, 0x3, 1, 4}, // two bits 4-5 - {"B56", 2, bt_num, LST, 0, 0, 0x3, 1, 5}, // two bits 5-6 - {"B67", 2, bt_num, LST, 0, 0, 0x3, 1, 6}, // two bits 6-7 - {"B02", 3, bt_num, LST, 0, 0, 0x7, 1, 0}, // three bits 0-2 - {"B13", 3, bt_num, LST, 0, 0, 0x7, 1, 1}, // three bits 1-3 - {"B24", 3, bt_num, LST, 0, 0, 0x7, 1, 2}, // three bits 2-4 - {"B35", 3, bt_num, LST, 0, 0, 0x7, 1, 3}, // three bits 3-5 - {"B46", 3, bt_num, LST, 0, 0, 0x7, 1, 4}, // three bits 4-6 - {"B57", 3, bt_num, LST, 0, 0, 0x7, 1, 5}, // three bits 5-7 - {"B03", 4, bt_num, LST, 0, 0, 0xf, 1, 0}, // four bits 0-3 - {"B14", 4, bt_num, LST, 0, 0, 0xf, 1, 1}, // four bits 1-4 - {"B25", 4, bt_num, LST, 0, 0, 0xf, 1, 2}, // four bits 2-5 - {"B36", 4, bt_num, LST, 0, 0, 0xf, 1, 3}, // four bits 3-6 - {"B47", 4, bt_num, LST, 0, 0, 0xf, 1, 4}, // four bits 4-7 - {"B04", 5, bt_num, LST, 0, 0, 0x1f, 1, 0}, // five bits 0-4 - {"B15", 5, bt_num, LST, 0, 0, 0x1f, 1, 1}, // five bits 1-5 - {"B26", 5, bt_num, LST, 0, 0, 0x1f, 1, 2}, // five bits 2-6 - {"B37", 5, bt_num, LST, 0, 0, 0x1f, 1, 3}, // five bits 3-7 - {"B05", 6, bt_num, LST, 0, 0, 0x3f, 1, 0}, // six bits 0-5 - {"B16", 6, bt_num, LST, 0, 0, 0x3f, 1, 1}, // six bits 1-6 - {"B27", 6, bt_num, LST, 0, 0, 0x3f, 1, 2}, // six bits 2-7 - {"B06", 7, bt_num, LST, 0, 0, 0x7f, 1, 0}, // seven bits 0-6 - {"B17", 7, bt_num, LST, 0, 0, 0x7f, 1, 1}, // seven bits 1-7 + {"BI0", 7, bt_num, ADJ|LST, 0, 0, 0xef, 1, 0}, // bit 0 (up to 7 bits until bit 6) + {"BI1", 7, bt_num, ADJ|LST, 0, 0, 0x7f, 1, 1}, // bit 1 (up to 7 bits until bit 7) + {"BI2", 6, bt_num, ADJ|LST, 0, 0, 0x3f, 1, 2}, // bit 2 (up to 6 bits until bit 7) + {"BI3", 5, bt_num, ADJ|LST, 0, 0, 0x1f, 1, 3}, // bit 3 (up to 5 bits until bit 7) + {"BI4", 4, bt_num, ADJ|LST, 0, 0, 0x0f, 1, 4}, // bit 4 (up to 4 bits until bit 7) + {"BI5", 3, bt_num, ADJ|LST, 0, 0, 0x07, 1, 5}, // bit 5 (up to 3 bits until bit 7) + {"BI6", 2, bt_num, ADJ|LST, 0, 0, 0x03, 1, 6}, // bit 6 (up to 2 bits until bit 7) + {"BI7", 1, bt_num, ADJ|LST, 0, 0, 0x01, 1, 7}, // bit 7 }; @@ -132,18 +106,17 @@ result_t DataField::create(std::vector::iterator& it, std::string unit, comment; PartType partType; unsigned int divisor = 0; - unsigned char length; const bool isTemplate = dstAddress == SYN; std::string token; if (it == end) break; - // name;[m|s][len];type[;[divisor|values][;[unit][;[comment]]]] + // name;part;type[:len][;[divisor|values][;[unit][;[comment]]]] const std::string name = *it++; if (it == end) break; - const char* posStr = (*it++).c_str(); + const char* partStr = (*it++).c_str(); if (it == end) break; @@ -151,18 +124,17 @@ result_t DataField::create(std::vector::iterator& it, firstName = name; firstComment = comment; } - if (dstAddress == BROADCAST || isMaster(dstAddress) - || (isTemplate == false && isSetMessage == true && (posStr[0] == 0 || posStr[0] <= '9')) - || posStr[0] == 'm') { // master data - partType = pt_masterData; - if (posStr[0] == 'm') - posStr++; + if (isTemplate == false && strcasecmp(partStr, "I") == 0) { + partType = pt_masterDataID; } - else if ((isTemplate == false && isSetMessage == false && (posStr[0] == 0 || posStr[0] <= '9')) - || posStr[0] == 's') { // slave data + else if (dstAddress == BROADCAST || isMaster(dstAddress) + || (isTemplate == false && isSetMessage == true && partStr[0] == 0) + || strcasecmp(partStr, "M") == 0) { // master data + partType = pt_masterData; + } + else if ((isTemplate == false && isSetMessage == false && partStr[0] == 0) + || strcasecmp(partStr, "S") == 0) { // slave data partType = pt_slaveData; - if (posStr[0] == 's') - posStr++; } else if (isTemplate) { partType = pt_any; @@ -172,17 +144,10 @@ result_t DataField::create(std::vector::iterator& it, break; } - if (posStr[0] == 0) { - length = 0; - } - else { - length = parseInt(posStr, 10, 1, MAX_POS, result); - if (result != RESULT_OK) - break; - } - - const char* typeStr = (*it++).c_str(); - if (typeStr[0] == 0) { + std::string typeStr = *it++; + if (typeStr.empty() == true) { + if (name.empty() == false || partStr[0] != 0) + result = RESULT_ERR_INVALID_ARG; break; } @@ -190,7 +155,7 @@ result_t DataField::create(std::vector::iterator& it, if (it != end) { std::string divisorStr = *it++; if (divisorStr.empty() == false) { - if (divisorStr.find_first_not_of("0123456789") == std::string::npos) { + if (divisorStr.find('=') == std::string::npos) { divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result); if (result != RESULT_OK) break; @@ -231,47 +196,73 @@ result_t DataField::create(std::vector::iterator& it, comment.clear(); } - // check for reference(s) to templates - if (templates.empty() == false) { - std::istringstream stream(typeStr); - bool found = false; - while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { - std::map< std::string, DataField*>::const_iterator ref = templates.find(token); - if (ref == templates.end()) { - if (found == false) - break; // fallback to direct definition - result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition - break; + size_t pos = typeStr.find(':'); + unsigned char length; + if (pos == std::string::npos) { + length = 0; + // check for reference(s) to templates + if (templates.empty() == false) { + std::istringstream stream(typeStr); + bool found = false; + std::string lengthStr; + while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { + std::map::const_iterator ref = templates.find(token); + if (ref == templates.end()) { + if (found == false) + break; // fallback to direct definition + result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition + break; + } + found = true; + result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); + if (result != RESULT_OK) + break; } - if (length > 1) { - result = RESULT_ERR_INVALID_ARG; // different length not possible for derivation - break; - } - found = true; - result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); - if (result != RESULT_OK) - break; + if (found == true || result != RESULT_OK) + break; // TODO check for found == true } - if (found == true || result != RESULT_OK) - break; } + else { + length = parseInt(typeStr.substr(pos+1).c_str(), 10, 1, MAX_POS, result); + if (result != RESULT_OK) + break; + typeStr = typeStr.substr(0, pos); + } + SingleDataField* add = NULL; + const char* typeName = typeStr.c_str(); for (size_t i = 0; result == RESULT_OK && add == NULL && i < sizeof(dataTypes) / sizeof(dataTypes[0]); i++) { dataType_t dataType = dataTypes[i]; - if (strcasecmp(typeStr, dataType.name) == 0) { - unsigned char numBytes = (dataType.numBits + 7) / 8; - unsigned char useLength = length; - if ((dataType.flags & ADJ) != 0) { - if (useLength == 0) - useLength = 1; // minimum length defaults to 1 - else if (useLength > numBytes) { + if (strcasecmp(typeName, dataType.name) == 0) { + unsigned char bitCount = dataType.maxBits; + unsigned char useLength = (bitCount + 7) / 8; + if ((dataType.flags & ADJ) != 0) { // adjustable length + if ((bitCount % 8) != 0) { + if (length == 0) { + useLength = 1; // default length: 1 byte + bitCount = 1; // default count: 1 bit + } + else if (length > bitCount) { + result = RESULT_ERR_INVALID_ARG; // invalid length + break; + } + else { + bitCount = length; + useLength = (length + 7) / 8; + } + } + else if (length == 0) { + useLength = 1; // default length: 1 byte + } + else if (length <= useLength) { + useLength = length; + } + else { result = RESULT_ERR_INVALID_ARG; // invalid length break; } } - else if (useLength == 0) - useLength = numBytes; - else if (useLength != numBytes) + else if (length > 0 && length != useLength) continue; // check for another one with same name but different length switch (dataType.type) @@ -294,7 +285,7 @@ result_t DataField::create(std::vector::iterator& it, else divisor *= dataType.divisor; - add = new NumberDataField(name, comment, unit, dataType, partType, useLength, divisor); + add = new NumberDataField(name, comment, unit, dataType, partType, useLength, bitCount, divisor); break; } if (values.begin()->first < dataType.minValueOrLength @@ -303,7 +294,7 @@ result_t DataField::create(std::vector::iterator& it, break; } - add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, values); + add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, bitCount, values); break; } } @@ -330,22 +321,17 @@ result_t DataField::create(std::vector::iterator& it, } -bool SingleDataField::hasFullByteOffset() -{ - return m_length > 1 || (m_dataType.numBits % 8) == 0 - || m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) >= 8; -} - result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, std::ostringstream& output, bool verbose, char separator) { - SymbolString& input = m_partType == pt_masterData ? masterData : slaveData; + SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData; unsigned char offset; switch (m_partType) { case pt_masterData: + case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -355,7 +341,14 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff return RESULT_ERR_INVALID_ARG; // invalid part type } - if (verbose) + if (isIgnored() == true) { + if (offset + m_length > input.size()) { + return RESULT_ERR_INVALID_ARG; + } + return RESULT_OK; + } + + if (verbose == true) output << m_name << "="; result_t result = readSymbols(input, offset, output); @@ -375,11 +368,12 @@ result_t SingleDataField::write(std::istringstream& input, SymbolString& slaveData, unsigned char slaveOffset, char separator) { - SymbolString& output = m_partType == pt_masterData ? masterData : slaveData; + SymbolString& output = m_partType != pt_slaveData ? masterData : slaveData; unsigned char offset; switch (m_partType) { case pt_masterData: + case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -423,6 +417,7 @@ result_t StringDataField::readSymbols(SymbolString& input, if (baseOffset + m_length > input.size()) { return RESULT_ERR_INVALID_ARG; } + if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) start = m_length - 1; incr = -1; @@ -494,6 +489,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input, incr = -1; } + if (isIgnored() == true) { + for (size_t offset = start, i = 0; i < count; offset += incr, i++) { + output[baseOffset + offset] = m_dataType.replacement; // fill up with replacement + } + return RESULT_OK; + } result_t result; size_t i = 0; for (size_t offset = start; i < count; offset += incr, i++) { @@ -581,6 +582,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input, } +bool NumericDataField::hasFullByteOffset(bool after) +{ + return m_length > 1 || (m_bitCount % 8) == 0 + || (after == true && m_bitOffset + (m_bitCount % 8) >= 8); +} + result_t NumericDataField::readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value) { @@ -619,9 +626,10 @@ result_t NumericDataField::readRawValue(SymbolString& input, if ((m_dataType.flags & BCD) == 0) { value >>= m_bitOffset; - if ((m_dataType.numBits % 8) != 0) - value &= (1 << m_dataType.numBits) - 1; + if ((m_bitCount % 8) != 0) + value &= (1 << m_bitCount) - 1; } + return RESULT_OK; } @@ -638,8 +646,9 @@ result_t NumericDataField::writeRawValue(unsigned int value, } if ((m_dataType.flags & BCD) == 0) { - if ((m_dataType.numBits % 8) != 0) - value &= (1 << m_dataType.numBits) - 1; + if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0) + return RESULT_ERR_INVALID_ARG; + value <<= m_bitOffset; } for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { @@ -656,7 +665,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, ch = (value / exp) & 0xff; exp = exp << 8; } - if (offset == start && (m_dataType.numBits % 8) != 0 && baseOffset + offset < output.size()) + if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size()) output[baseOffset + offset] |= ch; else output[baseOffset + offset] = ch; @@ -687,10 +696,10 @@ result_t NumberDataField::derive(std::string name, std::string comment, if (divisor != 1) return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field - fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values)); } else - fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, divisor)); + fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, divisor)); return RESULT_OK; } @@ -710,27 +719,27 @@ result_t NumberDataField::readSymbols(SymbolString& input, return RESULT_OK; } - bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_dataType.numBits - 1))) != 0; - if (m_dataType.numBits == 32) { + bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_bitCount - 1))) != 0; + if (m_bitCount == 32) { if (negative == false) { if (m_divisor <= 1) output << static_cast(value); else - output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) << std::fixed << static_cast(value / (float) m_divisor); return RESULT_OK; } signedValue = (int) value; // negative signed value } else if (negative) // negative signed value - signedValue = (int) value - (1 << m_dataType.numBits); + signedValue = (int) value - (1 << m_bitCount); else signedValue = (int) value; if (m_divisor <= 1) output << static_cast(signedValue); else - output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) << std::fixed << static_cast(signedValue / (float) m_divisor); return RESULT_OK; @@ -742,18 +751,17 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, unsigned int value; const char* str = input.str().c_str(); - if (strcasecmp(str, NULL_VALUE) == 0) - // replacement value - value = m_dataType.replacement; + if (isIgnored() == true || strcasecmp(str, NULL_VALUE) == 0) + value = m_dataType.replacement; // replacement value else if (str == NULL || *str == 0) - return RESULT_ERR_INVALID_ARG; // input too short + return RESULT_ERR_INVALID_ARG; // input too short//TODO LENGTH_SEPARATOR else { char* strEnd = NULL; if (m_divisor <= 1) { if ((m_dataType.flags & SIG) != 0) { int signedValue = strtol(str, &strEnd, 10); - if (signedValue < 0 && m_dataType.numBits != 32) - value = (unsigned int) (signedValue + (1 << m_dataType.numBits)); + if (signedValue < 0 && m_bitCount != 32) + value = (unsigned int) (signedValue + (1 << m_bitCount)); else value = (unsigned int) signedValue; } @@ -771,8 +779,8 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, if ((m_dataType.flags & SIG) != 0) { if (dvalue < -(1LL << (8 * m_length)) || dvalue >= (1LL << (8 * m_length))) return RESULT_ERR_INVALID_ARG; // value out of range - if (dvalue < 0 && m_dataType.numBits != 32) - value = (unsigned int) (dvalue + (1 << m_dataType.numBits)); + if (dvalue < 0 && m_bitCount != 32) + value = (unsigned int) (dvalue + (1 << m_bitCount)); else value = (unsigned int) dvalue; } @@ -784,7 +792,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, } if ((m_dataType.flags & SIG) != 0) { // signed value - if ((value & (1 << (m_dataType.numBits - 1))) != 0) { // negative signed value + if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value if (value < m_dataType.minValueOrLength) return RESULT_ERR_INVALID_ARG; // value out of range } @@ -823,7 +831,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment, else values = m_values; - fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values)); return RESULT_OK; } @@ -854,14 +862,17 @@ result_t ValueListDataField::readSymbols(SymbolString& input, result_t ValueListDataField::writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) { + if (isIgnored() == true) + return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value + const char* str = input.str().c_str(); for (std::map::iterator it = m_values.begin(); it != m_values.end(); it++) if (it->second.compare(str) == 0) return writeRawValue(it->first, baseOffset, output); - if (strcasecmp(str, NULL_VALUE) == 0) // replacement value - return writeRawValue(m_dataType.replacement, baseOffset, output); + if (strcasecmp(str, NULL_VALUE) == 0) + return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value return RESULT_ERR_INVALID_ARG; // value assignment not found } @@ -878,15 +889,17 @@ unsigned char DataFieldSet::getLength(PartType partType) { unsigned char length = 0; - bool previousFullByteOffset[] = { true, true, true }; + bool previousFullByteOffset[] = { true, true, true, true }; + for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; if (field->getPartType() == partType) { - length += field->getLength(partType); - if (previousFullByteOffset[partType] == false) { + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) length--; - } - previousFullByteOffset[partType] = field->hasFullByteOffset(); + + length += field->getLength(partType); + + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } } @@ -918,29 +931,38 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset output << m_name << "={ "; bool first = true; - unsigned char offsets[] = { 0, masterOffset, slaveOffset }; - bool previousFullByteOffset[] = { true, true, true }; + unsigned char offsets[4]; + memset(offsets, 0, sizeof(offsets)); + offsets[pt_masterData] = masterOffset; + offsets[pt_slaveData] = slaveOffset; + bool previousFullByteOffset[] = { true, true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { - if (first) - first = false; - else - output << separator; - SingleDataField* field = *it; + bool ignored = field->isIgnored(); PartType partType = field->getPartType(); - if (previousFullByteOffset[partType] == false) { - offsets[partType]--; + + if (ignored == false) { + if (first) + first = false; + else + output << separator; } + if (partType == pt_masterDataID) + partType = pt_masterData; + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) + offsets[partType]--; + result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator); if (result != RESULT_OK) return result; offsets[partType] += field->getLength(partType); - previousFullByteOffset[partType] = field->hasFullByteOffset(); + + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } - if (verbose) { + if (verbose == true) { if (m_comment.length() > 0) output << " [" << m_comment << "]"; output << "}"; @@ -956,18 +978,28 @@ result_t DataFieldSet::write(std::istringstream& input, { std::string token; - unsigned char offsets[] = { 0, masterOffset, slaveOffset }; - bool previousFullByteOffset[] = { true, true, true }; + unsigned char offsets[4]; + memset(offsets, 0, sizeof(offsets)); + offsets[pt_masterData] = masterOffset; + offsets[pt_slaveData] = slaveOffset; + bool previousFullByteOffset[] = { true, true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; + bool ignored = field->isIgnored(); PartType partType = field->getPartType(); - if (previousFullByteOffset[partType] == false) { + + if (partType == pt_masterDataID) + partType = pt_masterData; + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) offsets[partType]--; - } + result_t result; if (m_fields.size() > 1) { - if (std::getline(input, token, separator) == 0) + if (ignored == true) + token.clear(); + else if (std::getline(input, token, separator) == 0) return RESULT_ERR_INVALID_ARG; // incomplete + std::istringstream single(token); result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); } @@ -978,7 +1010,7 @@ result_t DataFieldSet::write(std::istringstream& input, return result; offsets[partType] += field->getLength(partType); - previousFullByteOffset[partType] = field->hasFullByteOffset(); + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 083df206..c6533dab 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -28,9 +28,10 @@ /** the message part in which a data field is stored. */ enum PartType { - pt_any, // stored in any data (master or slave) - pt_masterData, // stored in master data - pt_slaveData, // stored in slave data + pt_any, // stored in any data (master or slave) + pt_masterData, // stored in master data + pt_masterDataID, // stored in master data and also used as message ID part + pt_slaveData, // stored in slave data }; /** the available base data types. */ @@ -49,11 +50,12 @@ const unsigned int REV = 0x04; // reverted binary representation (most significa const unsigned int SIG = 0x08; // signed value const unsigned int LST = 0x10; // value list is possible (without applied divisor) const unsigned int DAY = 0x20; // forced value list defaulting to week days +const unsigned int IGN = 0x40; // ignore value during read and write /** the structure for defining field types with their properties. */ typedef struct { const char* name; // field identifier - const unsigned int numBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD) + const unsigned int maxBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD) const BaseType type; // base data type const unsigned int flags; // flags (e.g. @a BCD) const unsigned int replacement; // replacement value (fill-up value for @a bt_str / @a bt_hexstr, no replacement if equal to @a minValueOrLength for @a bt_num) @@ -208,6 +210,11 @@ public: * @return the value unit. */ std::string getUnit() const { return m_unit; } + /** + * @brief Get whether this field is ignored. + * @return whether this field is ignored. + */ + bool isIgnored() const { return (m_dataType.flags & IGN) != 0; } /** * @brief Get the message part in which the field is stored. * @return the message part in which the field is stored. @@ -218,10 +225,11 @@ public: // re-use same position as previous field as not all bits of fully consumed yet /** * @brief Get whether this field uses a full byte offset. + * @param after @p true to check after consuming the bits, false to check before. * @return true if this field uses a full byte offset, false if this field * only consumes a part of a byte and a subsequent field may re-use the same offset. */ - bool hasFullByteOffset(); + virtual bool hasFullByteOffset(bool after) { return true; } /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -337,17 +345,20 @@ public: * @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 bitCount the number of bits in the binary value. * @param bitOffset the offset to the first bit in the binary value. */ NumericDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const unsigned char bitOffset) + const unsigned char length, const unsigned char bitCount, const unsigned char bitOffset) : SingleDataField(name, comment, unit, dataType, partType, length), - m_bitOffset(bitOffset) {} + m_bitCount(bitCount), m_bitOffset(bitOffset) {} /** * @brief Destructor. */ virtual ~NumericDataField() {} + // @copydoc + virtual bool hasFullByteOffset(bool after); protected: @@ -368,9 +379,13 @@ protected: */ result_t writeRawValue(unsigned int value, const unsigned char offset, SymbolString& output); + /** the number of bits in the binary value. */ + const unsigned char m_bitCount; + /** the offset to the first bit in the binary value. */ const unsigned char m_bitOffset; + }; @@ -393,9 +408,10 @@ public: */ NumberDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const unsigned int divisor) - : NumericDataField(name, comment, unit, dataType, partType, length, - (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), + const unsigned char length, const unsigned char bitCount, + const unsigned int divisor) + : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, + (dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0), m_divisor(divisor) {} /** * @brief Destructor. @@ -439,9 +455,10 @@ public: */ ValueListDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const std::map values) - : NumericDataField(name, comment, unit, dataType, partType, length, - (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), + const unsigned char length, const unsigned char bitCount, + const std::map values) + : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, + (dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0), m_values(values) {} /** * @brief Destructor. diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index c40d8704..0775085c 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -43,21 +43,23 @@ int main() { std::string checks[][5] = { //name;[len];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags - {"x;10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, - {"x;10;str", " ", "10fe07000a20202020202020202020", "00", ""}, - {"x;11;str", "", "10fe07000a20202020202020202020", "00", "rW"}, + {"x;;ign:10", "", "10fe07000a00000000000000000000", "00", ""}, + {"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;str:10", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, + {"x;;str:10", " ", "10fe07000a20202020202020202020", "00", ""}, + {"x;;str:11", "", "10fe07000a20202020202020202020", "00", "rW"}, {"x;;hex", "20", "10fe07000120", "00", ""}, - {"x;10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, + {"x;;hex:10", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, {"x;;bda", "26.10.2014","10fe07000426100014", "00", ""}, {"x;;bda", "01.01.2000","10fe07000401010000", "00", ""}, {"x;;bda", "31.12.2099","10fe07000431120099", "00", ""}, {"x;;bda", "", "10fe07000432100014", "00", "rw"}, - {"x;3;bda","26.10.2014","10fe070003261014", "00", ""}, - {"x;3;bda","01.01.2000","10fe070003010100", "00", ""}, - {"x;3;bda","31.12.2099","10fe070003311299", "00", ""}, - {"x;3;bda","", "10fe070003321299", "00", "rw"}, + {"x;;bda:3","26.10.2014","10fe070003261014", "00", ""}, + {"x;;bda:3","01.01.2000","10fe070003010100", "00", ""}, + {"x;;bda:3","31.12.2099","10fe070003311299", "00", ""}, + {"x;;bda:3","", "10fe070003321299", "00", "rw"}, {"x;;bti", "21:04:58", "10fe070003580421", "00", ""}, {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, @@ -84,8 +86,8 @@ int main() {"x;;bcd", "99", "10feffff0199", "00", ""}, {"x;;bcd", "-", "10feffff01ff", "00", ""}, {"x;;bcd", "", "10feffff019a", "00", "rw"}, - {"x;16;str", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""}, - {"x;17;uch", "", "10feffff00", "00", "c"}, + {"x;;str:16", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""}, + {"x;;uch:17", "", "10feffff00", "00", "c"}, {"x;s;uch", "0", "1025ffff0310111213", "0300010203", "W"}, {"x;s;uch", "0", "1025ffff00", "0100", ""}, {"x;s;uch;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""}, @@ -148,14 +150,15 @@ int main() {"x;;bi3", "-", "10feffff0100", "00", ""}, {"x;;bi3;0=off,1=on","on", "10feffff0108", "00", ""}, {"x;;bi3;0=off,1=on","off","10feffff0100", "00", ""}, - {"x;;b34", "1", "10feffff0108", "00", ""}, - {"x;;b34", "-", "10feffff0100", "00", ""}, - {"x;;b34", "3", "10feffff0118", "00", ""}, - {"x;;b34;1=on","on", "10feffff0108", "00", ""}, - {"x;;b34;1=on","-", "10feffff0100", "00", ""}, - {"x;;b34;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""}, - {"x;;b34;0=off,1=on","on", "10feffff0108", "00", ""}, - {"x;;b34;0=off,1=on","off","10feffff0100", "00", ""}, + {"x;;bi3:2", "1", "10feffff0108", "00", ""}, + {"x;;bi3:2", "1", "10feffff01ef", "00", "W"}, + {"x;;bi3:2", "-", "10feffff0100", "00", ""}, + {"x;;bi3:2", "3", "10feffff0118", "00", ""}, + {"x;;bi3:2;1=on","on", "10feffff0108", "00", ""}, + {"x;;bi3:2;1=on","-", "10feffff0100", "00", ""}, + {"x;;bi3:2;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""}, + {"x;;bi3:2;0=off,1=on","on", "10feffff0108", "00", ""}, + {"x;;bi3:2;0=off,1=on","off","10feffff0100", "00", ""}, {"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""}, {"x;s;uch","3","1050ffff00", "0103", ""}, {"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"}, @@ -164,8 +167,8 @@ int main() {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;-", "10feffff0100", "00", ""}, // bit combination - {"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination, auto pos incr - {"x;;bi3;;;;y;;bi5;;;;t;;uch", "-;-;9","10feffff020009", "00", "RW"}, // bit combination + {"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination + {"x;;bi6:2;;;;y;;bi0:2;;;;t;;uch", "2;1;9","10feffff03800109", "00", ""}, // bit combination {"temp;;d2b;;°C;Aussentemperatur","","", "", "t"}, // template with relative pos {"x;;temp","18.004","10fe0700020112", "00", ""}, // reference to template {"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos @@ -202,7 +205,6 @@ int main() } std::vector::iterator it = entries.begin(); result_t result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate ? SYN : mstr[1]); - if (failedCreate == true) { if (result == RESULT_OK) std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl; From f509d68912bdb9bb4c61d9be8bb2ee7a67c37076 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 20:42:39 +0100 Subject: [PATCH 13/15] write weekday in BDA/32 and HDA/32, added constant, small fixes, added test cases for HDA --- src/lib/ebus/data.cpp | 69 ++++++++++++++++++++++----------- src/lib/ebus/test/test_data.cpp | 20 ++++++---- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 4ec7d05b..7d77c04a 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +//include #include /** the known data field types. */ @@ -32,15 +32,15 @@ static const dataType_t dataTypes[] = { {"IGN",16*8,bt_str, IGN|ADJ, 0, 1, 16, 0, 0}, // >= 1 byte ignored data {"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space {"HEX",16*8,bt_hexstr, ADJ, 0, 2, 47, 0, 0}, // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d - {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) + {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x00 - Sun=0x06) {"BDA", 24, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) - {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) // TODO remove duplicate of BDA + {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x01 - Sun=0x07)) {"HDA", 24, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA {"BTI", 24, bt_tim, BCD|REV, 0, 8, 8, 0, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23) {"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b) {"TTM", 8, bt_tim, 0, 0x90, 5, 5, 0, 0}, // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer) - {"BDY", 8, bt_num, DAY|LST, 0x07, 0, 6, 1, 0}, // weekday, "Mon" - "Sun" - {"HDY", 8, bt_num, DAY|LST, 0x00, 1, 7, 1, 0}, // weekday, "Mon" - "Sun" + {"BDY", 8, bt_num, DAY|LST, 0x07, 0, 6, 1, 0}, // weekday, "Mon" - "Sun" (0x00 - 0x06) [ebus type] + {"HDY", 8, bt_num, DAY|LST, 0x00, 1, 7, 1, 0}, // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type] {"BCD", 8, bt_num, BCD|LST, 0xff, 0, 0x99, 1, 0}, // unsigned decimal in BCD, 0 - 99 {"UCH", 8, bt_num, LST, 0xff, 0, 0xfe, 1, 0}, // unsigned integer, 0 - 254 {"SCH", 8, bt_num, SIG, 0x80, 0x81, 0x7f, 1, 0}, // signed integer, -127 - +127 @@ -69,6 +69,7 @@ static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" #define FIELD_SEPARATOR ';' #define VALUE_SEPARATOR ',' +#define LENGTH_SEPARATOR ':' #define NULL_VALUE "-" #define MAX_POS 16 @@ -183,8 +184,7 @@ result_t DataField::create(std::vector::iterator& it, unit = ""; else { unit = *it++; - - if (unit.length() == 1 && unit[0] == '-') + if (strcasecmp(unit.c_str(), NULL_VALUE) == 0) unit.clear(); } @@ -192,11 +192,11 @@ result_t DataField::create(std::vector::iterator& it, comment = ""; else { comment = *it++; - if (comment.length() == 1 && comment[0] == '-') + if (strcasecmp(comment.c_str(), NULL_VALUE) == 0) comment.clear(); } - size_t pos = typeStr.find(':'); + size_t pos = typeStr.find(LENGTH_SEPARATOR); unsigned char length; if (pos == std::string::npos) { length = 0; @@ -218,8 +218,10 @@ result_t DataField::create(std::vector::iterator& it, if (result != RESULT_OK) break; } - if (found == true || result != RESULT_OK) - break; // TODO check for found == true + if (result != RESULT_OK) + break; + if (found == true) + continue; // go to next definition } } else { @@ -427,7 +429,7 @@ result_t StringDataField::readSymbols(SymbolString& input, if (m_length == 4 && i == 2 && m_dataType.type == bt_dat) continue; // skip weekday in between ch = input[baseOffset + offset]; - if ((m_dataType.flags & BCD) != 0) { + if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) { if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) return RESULT_ERR_INVALID_ARG; // invalid BCD ch = (ch >> 4) * 10 + (ch & 0x0f); @@ -481,7 +483,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, { size_t start = 0, count = m_length; int incr = 1; - unsigned long int value = 0, last = 0; + unsigned long int value = 0, last = 0, lastLast = 0; std::string token; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) @@ -524,21 +526,41 @@ result_t StringDataField::writeSymbols(std::istringstream& input, continue; // skip weekday in between if (input.eof() == true || std::getline(input, token, '.') == 0) return RESULT_ERR_INVALID_ARG; // incomplete - value = parseInt(token.c_str(), 10, 0, 9999, result); + value = parseInt(token.c_str(), 10, 0, 2099, result); if (result != RESULT_OK) return result; // invalid date part - if (i + 1 == m_length && value >= 2000) - value -= 2000; - else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) + if (i + 1 == m_length) { + if (m_length == 4) { + // calculate local week day + struct tm t; + t.tm_min = t.tm_sec = 0; + t.tm_hour = 12; + t.tm_mday = lastLast; + t.tm_mon = last-1; // January=0 + t.tm_year = (value < 100 ? value + 2000 : value) - 1900; + t.tm_isdst = 0; // automatic + if (mktime(&t) < 0) + return RESULT_ERR_INVALID_ARG; // invalid date + unsigned char daysSinceSunday = (unsigned char)t.tm_wday; // Sun=0 + if ((m_dataType.flags & BCD) != 0) + output[baseOffset + offset - incr] = (6+daysSinceSunday) % 7; // Sun=0x06 + else + output[baseOffset + offset - incr] = (daysSinceSunday==0 ? 7 : daysSinceSunday); // Sun=0x07 + } + if (value >= 2000) + value -= 2000; + else if (value > 99) + return RESULT_ERR_INVALID_ARG; // invalid year + } else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) return RESULT_ERR_INVALID_ARG; // invalid date part break; case bt_tim: - if (input.eof() == true || std::getline(input, token, ':') == 0) + if (input.eof() == true || std::getline(input, token, LENGTH_SEPARATOR) == 0) return RESULT_ERR_INVALID_ARG; // incomplete value = parseInt(token.c_str(), 10, 0, 59, result); if (result != RESULT_OK) return result; // invalid time part - if ((i == 0 && value > 24) || (i > 0 && ( last == 24 && value > 0) )) + if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) )) return RESULT_ERR_INVALID_ARG; // invalid time part if (m_length == 1) { // truncated time if (i == 0) { @@ -564,15 +586,16 @@ result_t StringDataField::writeSymbols(std::istringstream& input, } break; } - if ((m_dataType.flags & BCD) != 0) { + lastLast = last; + last = value; + if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) { if (value > 99) return RESULT_ERR_INVALID_ARG; // invalid BCD - value = (value / 10) << 4 | (value % 10); + value = ((value / 10) << 4) | (value % 10); } if (value > 0xff) return RESULT_ERR_INVALID_ARG; // value out of range output[baseOffset + offset] = (unsigned char)value; - last = value; } if (i < m_length) @@ -754,7 +777,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, if (isIgnored() == true || strcasecmp(str, NULL_VALUE) == 0) value = m_dataType.replacement; // replacement value else if (str == NULL || *str == 0) - return RESULT_ERR_INVALID_ARG; // input too short//TODO LENGTH_SEPARATOR + return RESULT_ERR_INVALID_ARG; // input too short else { char* strEnd = NULL; if (m_divisor <= 1) { diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 0775085c..1d6602a1 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -52,14 +52,17 @@ int main() {"x;;hex", "20", "10fe07000120", "00", ""}, {"x;;hex:10", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, {"x;;hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, - {"x;;bda", "26.10.2014","10fe07000426100014", "00", ""}, - {"x;;bda", "01.01.2000","10fe07000401010000", "00", ""}, - {"x;;bda", "31.12.2099","10fe07000431120099", "00", ""}, + {"x;;bda", "26.10.2014","10fe07000426100614", "00", ""}, // Sunday + {"x;;hda", "26.10.2014","10fe07000426100714", "00", ""}, // Sunday + {"x;;bda", "01.01.2000","10fe07000401010500", "00", ""}, // Saturday + {"x;;hda", "01.01.2000","10fe07000401010600", "00", ""}, // Saturday + {"x;;bda", "31.12.2099","10fe07000431120399", "00", ""}, // Thursday + {"x;;hda", "31.12.2099","10fe07000431120499", "00", ""}, // Thursday {"x;;bda", "", "10fe07000432100014", "00", "rw"}, - {"x;;bda:3","26.10.2014","10fe070003261014", "00", ""}, - {"x;;bda:3","01.01.2000","10fe070003010100", "00", ""}, - {"x;;bda:3","31.12.2099","10fe070003311299", "00", ""}, - {"x;;bda:3","", "10fe070003321299", "00", "rw"}, + {"x;;bda:3", "26.10.2014","10fe070003261014", "00", ""}, + {"x;;bda:3", "01.01.2000","10fe070003010100", "00", ""}, + {"x;;bda:3", "31.12.2099","10fe070003311299", "00", ""}, + {"x;;bda:3", "", "10fe070003321299", "00", "rw"}, {"x;;bti", "21:04:58", "10fe070003580421", "00", ""}, {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, @@ -162,7 +165,7 @@ int main() {"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""}, {"x;s;uch","3","1050ffff00", "0103", ""}, {"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"}, - {"x;;bti;;;;y;;bda;;;;z;;bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610001406", "00", ""}, // combination + {"x;;bti;;;;y;;bda;;;;z;;bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610061406", "00", ""}, // combination {"x;;bi3;;;;y;;bi5", "1;-", "10feffff0108", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination @@ -175,6 +178,7 @@ int main() {"x;;relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct {"trelrel;;temp,temp","","", "", "t"}, // template struct with relative pos and ref to templates {"x;;trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct + {"x;;temp;;;;y;;d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def }; std::map templates; DataField* fields = NULL; From 3a34267bee0c7530d14ad796c1a6591540ed0670 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 20:56:53 +0100 Subject: [PATCH 14/15] using namespace std; --- src/lib/ebus/data.cpp | 135 +++++++++++++++-------------- src/lib/ebus/data.h | 132 ++++++++++++++-------------- src/lib/ebus/message.cpp | 24 ++--- src/lib/ebus/message.h | 38 ++++---- src/lib/ebus/result.cpp | 4 + src/lib/ebus/symbol.cpp | 14 +-- src/lib/ebus/symbol.h | 10 ++- src/lib/ebus/test/test_data.cpp | 102 +++++++++++----------- src/lib/ebus/test/test_message.cpp | 85 +++++++++--------- src/lib/ebus/test/test_symbol.cpp | 27 +++--- 10 files changed, 294 insertions(+), 277 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 7d77c04a..7a845899 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -24,9 +24,10 @@ #include #include #include -//include #include +using namespace std; + /** the known data field types. */ static const dataType_t dataTypes[] = { {"IGN",16*8,bt_str, IGN|ADJ, 0, 1, 16, 0, 0}, // >= 1 byte ignored data @@ -94,26 +95,26 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co return ret; } -result_t DataField::create(std::vector::iterator& it, - const std::vector::iterator end, - const std::map< std::string, DataField*> templates, +result_t DataField::create(vector::iterator& it, + const vector::iterator end, + const map< string, DataField*> templates, DataField*& returnField, const bool isSetMessage, const unsigned char dstAddress) { - std::vector fields; - std::string firstName, firstComment; + vector fields; + string firstName, firstComment; result_t result = RESULT_OK; while (it != end && result == RESULT_OK) { - std::string unit, comment; + string unit, comment; PartType partType; unsigned int divisor = 0; const bool isTemplate = dstAddress == SYN; - std::string token; + string token; if (it == end) break; // name;part;type[:len][;[divisor|values][;[unit][;[comment]]]] - const std::string name = *it++; + const string name = *it++; if (it == end) break; @@ -145,25 +146,25 @@ result_t DataField::create(std::vector::iterator& it, break; } - std::string typeStr = *it++; + string typeStr = *it++; if (typeStr.empty() == true) { if (name.empty() == false || partStr[0] != 0) result = RESULT_ERR_INVALID_ARG; break; } - std::map values; + map values; if (it != end) { - std::string divisorStr = *it++; + string divisorStr = *it++; if (divisorStr.empty() == false) { - if (divisorStr.find('=') == std::string::npos) { + if (divisorStr.find('=') == string::npos) { divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result); if (result != RESULT_OK) break; } else { - std::istringstream stream(divisorStr); - while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { + istringstream stream(divisorStr); + while (getline(stream, token, VALUE_SEPARATOR) != 0) { const char* str = token.c_str(); char* strEnd = NULL; unsigned int id = strtoul(str, &strEnd, 10); @@ -172,7 +173,7 @@ result_t DataField::create(std::vector::iterator& it, break; } - values[id] = std::string(strEnd + 1); + values[id] = string(strEnd + 1); } if (result != RESULT_OK) break; @@ -198,15 +199,15 @@ result_t DataField::create(std::vector::iterator& it, size_t pos = typeStr.find(LENGTH_SEPARATOR); unsigned char length; - if (pos == std::string::npos) { + if (pos == string::npos) { length = 0; // check for reference(s) to templates if (templates.empty() == false) { - std::istringstream stream(typeStr); + istringstream stream(typeStr); bool found = false; - std::string lengthStr; - while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { - std::map::const_iterator ref = templates.find(token); + string lengthStr; + while (getline(stream, token, VALUE_SEPARATOR) != 0) { + map::const_iterator ref = templates.find(token); if (ref == templates.end()) { if (found == false) break; // fallback to direct definition @@ -325,7 +326,7 @@ result_t DataField::create(std::vector::iterator& it, result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, - std::ostringstream& output, + ostringstream& output, bool verbose, char separator) { SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData; @@ -365,7 +366,7 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff return RESULT_OK; } -result_t SingleDataField::write(std::istringstream& input, +result_t SingleDataField::write(istringstream& input, SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, char separator) @@ -388,10 +389,10 @@ result_t SingleDataField::write(std::istringstream& input, } -result_t StringDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields) +result_t StringDataField::derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields) { if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance @@ -410,7 +411,7 @@ result_t StringDataField::derive(std::string name, std::string comment, } result_t StringDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, std::ostringstream& output) + unsigned char baseOffset, ostringstream& output) { size_t start = 0, count = m_length; int incr = 1; @@ -439,8 +440,8 @@ result_t StringDataField::readSymbols(SymbolString& input, case bt_hexstr: if (i > 0) output << ' '; - output << std::nouppercase << std::setw(2) << std::hex - << std::setfill('0') << static_cast(ch); + output << nouppercase << setw(2) << hex << setfill('0') + << static_cast(ch); break; case bt_dat: if (i + 1 == m_length) @@ -448,7 +449,7 @@ result_t StringDataField::readSymbols(SymbolString& input, else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12)) return RESULT_ERR_INVALID_ARG; // invalid date else - output << std::setw(2) << std::setfill('0') << static_cast(ch) << "."; + output << setw(2) << setfill('0') << static_cast(ch) << "."; break; case bt_tim: if (m_length == 1) { // truncated time @@ -464,7 +465,7 @@ result_t StringDataField::readSymbols(SymbolString& input, return RESULT_ERR_INVALID_ARG; // invalid time if (i > 0) output << ":"; - output << std::setw(2) << std::setfill('0') << static_cast(ch); + output << setw(2) << setfill('0') << static_cast(ch); break; default: if (ch < 0x20) @@ -478,13 +479,13 @@ result_t StringDataField::readSymbols(SymbolString& input, return RESULT_OK; } -result_t StringDataField::writeSymbols(std::istringstream& input, +result_t StringDataField::writeSymbols(istringstream& input, unsigned char baseOffset, SymbolString& output) { size_t start = 0, count = m_length; int incr = 1; unsigned long int value = 0, last = 0, lastLast = 0; - std::string token; + string token; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) start = m_length - 1; @@ -524,7 +525,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, case bt_dat: if (m_length == 4 && i == 2) continue; // skip weekday in between - if (input.eof() == true || std::getline(input, token, '.') == 0) + if (input.eof() == true || getline(input, token, '.') == 0) return RESULT_ERR_INVALID_ARG; // incomplete value = parseInt(token.c_str(), 10, 0, 2099, result); if (result != RESULT_OK) @@ -555,7 +556,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input, return RESULT_ERR_INVALID_ARG; // invalid date part break; case bt_tim: - if (input.eof() == true || std::getline(input, token, LENGTH_SEPARATOR) == 0) + if (input.eof() == true || getline(input, token, LENGTH_SEPARATOR) == 0) return RESULT_ERR_INVALID_ARG; // incomplete value = parseInt(token.c_str(), 10, 0, 59, result); if (result != RESULT_OK) @@ -698,10 +699,10 @@ result_t NumericDataField::writeRawValue(unsigned int value, } -result_t NumberDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields) +result_t NumberDataField::derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields) { if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance @@ -728,7 +729,7 @@ result_t NumberDataField::derive(std::string name, std::string comment, } result_t NumberDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, std::ostringstream& output) + unsigned char baseOffset, ostringstream& output) { unsigned int value = 0; int signedValue; @@ -748,8 +749,8 @@ result_t NumberDataField::readSymbols(SymbolString& input, if (m_divisor <= 1) output << static_cast(value); else - output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) - << std::fixed << static_cast(value / (float) m_divisor); + output << setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + << fixed << static_cast(value / (float) m_divisor); return RESULT_OK; } signedValue = (int) value; // negative signed value @@ -762,13 +763,13 @@ result_t NumberDataField::readSymbols(SymbolString& input, if (m_divisor <= 1) output << static_cast(signedValue); else - output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) - << std::fixed << static_cast(signedValue / (float) m_divisor); + output << setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + << fixed << static_cast(signedValue / (float) m_divisor); return RESULT_OK; } -result_t NumberDataField::writeSymbols(std::istringstream& input, +result_t NumberDataField::writeSymbols(istringstream& input, unsigned char baseOffset, SymbolString& output) { unsigned int value; @@ -830,10 +831,10 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, } -result_t ValueListDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields) +result_t ValueListDataField::derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields) { if (m_partType != pt_any && partType == pt_any) return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance @@ -860,7 +861,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment, } result_t ValueListDataField::readSymbols(SymbolString& input, - unsigned char baseOffset, std::ostringstream& output) + unsigned char baseOffset, ostringstream& output) { unsigned int value = 0; @@ -868,7 +869,7 @@ result_t ValueListDataField::readSymbols(SymbolString& input, if (result != RESULT_OK) return result; - std::map::iterator it = m_values.find(value); + map::iterator it = m_values.find(value); if (it != m_values.end()) { output << it->second; return RESULT_OK; @@ -882,7 +883,7 @@ result_t ValueListDataField::readSymbols(SymbolString& input, return RESULT_ERR_INVALID_ARG; // value assignment not found } -result_t ValueListDataField::writeSymbols(std::istringstream& input, +result_t ValueListDataField::writeSymbols(istringstream& input, unsigned char baseOffset, SymbolString& output) { if (isIgnored() == true) @@ -890,7 +891,7 @@ result_t ValueListDataField::writeSymbols(std::istringstream& input, const char* str = input.str().c_str(); - for (std::map::iterator it = m_values.begin(); it != m_values.end(); it++) + for (map::iterator it = m_values.begin(); it != m_values.end(); it++) if (it->second.compare(str) == 0) return writeRawValue(it->first, baseOffset, output); @@ -914,7 +915,7 @@ unsigned char DataFieldSet::getLength(PartType partType) bool previousFullByteOffset[] = { true, true, true, true }; - for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; if (field->getPartType() == partType) { if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) @@ -929,15 +930,15 @@ unsigned char DataFieldSet::getLength(PartType partType) return length; } -result_t DataFieldSet::derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields) +result_t DataFieldSet::derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields) { if (values.empty() == false) return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive - for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { result_t result = (*it)->derive("", "", "", partType, divisor, values, fields); if (result != RESULT_OK) return result; @@ -948,7 +949,7 @@ result_t DataFieldSet::derive(std::string name, std::string comment, result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, - std::ostringstream& output, bool verbose, char separator) + ostringstream& output, bool verbose, char separator) { if (verbose) output << m_name << "={ "; @@ -959,7 +960,7 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset offsets[pt_masterData] = masterOffset; offsets[pt_slaveData] = slaveOffset; bool previousFullByteOffset[] = { true, true, true, true }; - for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; bool ignored = field->isIgnored(); PartType partType = field->getPartType(); @@ -994,19 +995,19 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset return RESULT_OK; } -result_t DataFieldSet::write(std::istringstream& input, +result_t DataFieldSet::write(istringstream& input, SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, char separator) { - std::string token; + string token; unsigned char offsets[4]; memset(offsets, 0, sizeof(offsets)); offsets[pt_masterData] = masterOffset; offsets[pt_slaveData] = slaveOffset; bool previousFullByteOffset[] = { true, true, true, true }; - for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; bool ignored = field->isIgnored(); PartType partType = field->getPartType(); @@ -1020,10 +1021,10 @@ result_t DataFieldSet::write(std::istringstream& input, if (m_fields.size() > 1) { if (ignored == true) token.clear(); - else if (std::getline(input, token, separator) == 0) + else if (getline(input, token, separator) == 0) return RESULT_ERR_INVALID_ARG; // incomplete - std::istringstream single(token); + istringstream single(token); result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); } else diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index c6533dab..a9cf9579 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -26,6 +26,8 @@ #include #include +using namespace std; + /** the message part in which a data field is stored. */ enum PartType { pt_any, // stored in any data (master or slave) @@ -92,7 +94,7 @@ public: * @param name the field name. * @param comment the field comment. */ - DataField(const std::string name, const std::string comment) + DataField(const string name, const string comment) : m_name(name), m_comment(comment) {} /** * @brief Destructor. @@ -109,8 +111,8 @@ public: * @return @a RESULT_OK on success, or an error code. * Note: the caller needs to free the created instance. */ - static result_t create(std::vector::iterator& it, const std::vector::iterator end, - const std::map templates, DataField*& returnField, + static result_t create(vector::iterator& it, const vector::iterator end, + const map templates, DataField*& returnField, const bool isSetMessage=false, const unsigned char dstAddress=SYN); /** * @brief Returns the length of this field (or contained fields) in bytes. @@ -126,27 +128,27 @@ public: * @param partType 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). - * @param fields the @a std::vector to which created @a SingleDataField instances shall be added. + * @param fields the @a vector to which created @a SingleDataField instances shall be added. */ - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields) = 0; + virtual result_t derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields) = 0; /** * @brief Get the field name. * @return the field name. */ - std::string getName() const { return m_name; } + string getName() const { return m_name; } /** * @brief Get the field comment. * @return the field comment. */ - std::string getComment() const { return m_comment; } + string getComment() const { 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 @a std::ostringstream to append the formatted value to. + * @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 separator the separator character between multiple fields. @@ -154,17 +156,17 @@ public: */ virtual result_t read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, - std::ostringstream& output, + ostringstream& output, bool verbose=false, char separator=';') = 0; /** * @brief Writes the value to the master or slave @a SymbolString. - * @param input the @a std::istringstream to parse the formatted value from. + * @param input the @a 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 @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, + virtual result_t write(istringstream& input, SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, char separator=';') = 0; @@ -172,9 +174,9 @@ public: protected: /** the field name. */ - const std::string m_name; + const string m_name; /** the field comment. */ - const std::string m_comment; + const string m_comment; }; @@ -195,8 +197,8 @@ public: * @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. */ - SingleDataField(const std::string name, const std::string comment, - const std::string unit, const dataType_t dataType, const PartType partType, + SingleDataField(const string name, const string comment, + const string unit, const dataType_t dataType, const PartType partType, const unsigned char length) : DataField(name, comment), m_unit(unit), m_dataType(dataType), m_partType(partType), @@ -209,7 +211,7 @@ public: * @brief Get the value unit. * @return the value unit. */ - std::string getUnit() const { return m_unit; } + string getUnit() const { return m_unit; } /** * @brief Get whether this field is ignored. * @return whether this field is ignored. @@ -243,18 +245,18 @@ public: */ virtual result_t read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, - std::ostringstream& output, + ostringstream& output, bool verbose, char separator); /** * @brief Writes the value to the master or slave @a SymbolString. - * @param input the @a std::istringstream to parse the formatted value from. + * @param input the @a istringstream to parse the formatted value from. * @param masterData the unescaped master data @a SymbolString for writing binary data. * @param masterOffset the extra offset for writing master data. * @param slaveData the unescaped slave data @a SymbolString for writing binary data. * @param slaveOffset the extra offset for writing slave data. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, + virtual result_t write(istringstream& input, SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, char separator); @@ -268,18 +270,18 @@ 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, std::ostringstream& output) = 0; + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output) = 0; /** * @brief Internal method for writing the field to a @a SymbolString. - * @param input the @a std::istringstream to parse the formatted value from. + * @param input the @a istringstream to parse the formatted value from. * @param offset the offset in the @a SymbolString. * @param output the unescaped @a SymbolString to write the binary value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output) = 0; + virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output) = 0; /** the value unit. */ - const std::string m_unit; + const string m_unit; /** the data type definition. */ const dataType_t m_dataType; /** the message part in which the field is stored. */ @@ -306,8 +308,8 @@ public: * @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. */ - StringDataField(const std::string name, const std::string comment, - const std::string unit, const dataType_t dataType, const PartType partType, + StringDataField(const string name, const string comment, + const string unit, const dataType_t dataType, const PartType partType, const unsigned char length) : SingleDataField(name, comment, unit, dataType, partType, length) {} /** @@ -315,17 +317,17 @@ public: */ virtual ~StringDataField() {} // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields); protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); // @copydoc - virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); + virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); }; @@ -348,8 +350,8 @@ public: * @param bitCount the number of bits in the binary value. * @param bitOffset the offset to the first bit in the binary value. */ - NumericDataField(const std::string name, const std::string comment, - const std::string unit, const dataType_t dataType, const PartType partType, + NumericDataField(const string name, const string comment, + const string unit, const dataType_t dataType, const PartType partType, const unsigned char length, const unsigned char bitCount, const unsigned char bitOffset) : SingleDataField(name, comment, unit, dataType, partType, length), m_bitCount(bitCount), m_bitOffset(bitOffset) {} @@ -406,8 +408,8 @@ public: * @param length the number of symbols in the message part in which the field is stored. * @param divisor the extra divisor to apply on the value, or 1 for none. */ - NumberDataField(const std::string name, const std::string comment, - const std::string unit, const dataType_t dataType, const PartType partType, + NumberDataField(const string name, const string comment, + const string unit, const dataType_t dataType, const PartType partType, const unsigned char length, const unsigned char bitCount, const unsigned int divisor) : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, @@ -418,17 +420,17 @@ public: */ virtual ~NumberDataField() {} // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields); protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); // @copydoc - virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); + virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); /** the combined divisor to apply on the value, or 1 for none. */ const unsigned int m_divisor; @@ -453,10 +455,10 @@ public: * @param length the number of symbols in the message part in which the field is stored. * @param values the value=text assignments. */ - ValueListDataField(const std::string name, const std::string comment, - const std::string unit, const dataType_t dataType, const PartType partType, + ValueListDataField(const string name, const string comment, + const string unit, const dataType_t dataType, const PartType partType, const unsigned char length, const unsigned char bitCount, - const std::map values) + const map values) : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, (dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0), m_values(values) {} @@ -465,20 +467,20 @@ public: */ virtual ~ValueListDataField() {} // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned int divisor, - std::map values, - std::vector& fields); + virtual result_t derive(string name, string comment, + string unit, const PartType partType, unsigned int divisor, + map values, + vector& fields); protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, ostringstream& output); // @copydoc - virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); + virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); /** the value=text assignments. */ - std::map m_values; + map m_values; }; @@ -494,10 +496,10 @@ public: * @brief Constructs a new instance. * @param name the field name. * @param comment the field comment. - * @param fields the @a std::vector of @a SingleDataField instances part of this set. + * @param fields the @a vector of @a SingleDataField instances part of this set. */ - DataFieldSet(const std::string name, const std::string comment, - const std::vector fields) + DataFieldSet(const string name, const string comment, + const vector fields) : DataField(name, comment), m_fields(fields) {} /** @@ -507,10 +509,10 @@ public: // @copydoc virtual unsigned char getLength(PartType partType); // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t derive(string name, string comment, + string unit, const PartType partType, + unsigned int divisor, map values, + vector& fields); /** * @brief Returns the @a SingleDataField at the specified index. * @param index the index of the @a SingleDataField to return. @@ -531,18 +533,18 @@ public: // @copydoc virtual result_t read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, - std::ostringstream& output, + ostringstream& output, bool verbose, char separator); // @copydoc - virtual result_t write(std::istringstream& input, + virtual result_t write(istringstream& input, SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, char separator); protected: - /** the @a std::vector of @a SingleDataField instances part of this set. */ - std::vector m_fields; + /** the @a vector of @a SingleDataField instances part of this set. */ + vector m_fields; }; diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 2620398a..6bd69d92 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -25,8 +25,10 @@ #include #include -result_t Message::create(std::vector::iterator& it, const std::vector::iterator end, - const std::map templates, Message*& returnValue) +using namespace std; + +result_t Message::create(vector::iterator& it, const vector::iterator end, + const map templates, Message*& returnValue) { result_t result; // [type];class;name;[comment];[QQ];ZZ;id;fields... @@ -60,17 +62,17 @@ result_t Message::create(std::vector::iterator& it, const std::vect isSetMessage = false; } - std::string clazz = *it++; + string clazz = *it++; if (it == end) return RESULT_ERR_EOF; - std::string name = *it++; + string name = *it++; if (it == end) return RESULT_ERR_EOF; if (name.length() == 0) return RESULT_ERR_INVALID_ARG; // empty name - std::string comment = *it++; + string comment = *it++; if (it == end) return RESULT_ERR_EOF; @@ -98,9 +100,9 @@ result_t Message::create(std::vector::iterator& it, const std::vect if (isValidAddress(dstAddress) == false) return RESULT_ERR_INVALID_ARG; - std::istringstream input(*it++); // message id (PBSB + optional master data) - std::vector id; - std::string token; + istringstream input(*it++); // message id (PBSB + optional master data) + vector id; + string token; if (it == end) return RESULT_ERR_EOF; while (input.eof() == false) { @@ -131,7 +133,7 @@ result_t Message::create(std::vector::iterator& it, const std::vect return RESULT_OK; } -result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, std::istringstream& input, char separator) +result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator) { if (m_isActiveMessage == true) { masterData.clear(); @@ -153,7 +155,7 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa } result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, - std::ostringstream& output, char separator, bool answer) + ostringstream& output, char separator, bool answer) { if (m_isActiveMessage == true) { result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); @@ -161,7 +163,7 @@ result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, return result; } else if (answer == true) { - std::istringstream input; // TODO create input from database of internal variables + istringstream input; // TODO create input from database of internal variables result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator); if (result != RESULT_OK) return result; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 8d5aadda..4856f9bb 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -26,6 +26,8 @@ #include #include +using namespace std; + /** * @brief Base class for all kinds of bus messages. */ @@ -48,10 +50,10 @@ public: * @param data the @a DataField for encoding/decoding the message. * @param pollPriority the priority for polling, or 0 for no polling at all. */ - Message(const std::string clazz, const std::string name, const bool isSetMessage, - const bool isActiveMessage, const std::string comment, + Message(const string clazz, const string name, const bool isSetMessage, + const bool isActiveMessage, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, - const std::vector id, DataField* data, + const vector id, DataField* data, const unsigned int pollPriority) : m_class(clazz), m_name(name), m_isSetMessage(isSetMessage), m_isActiveMessage(isActiveMessage), m_comment(comment), @@ -70,18 +72,18 @@ public: * @return @a RESULT_OK on success, or an error code. * Note: the caller needs to free the created instance. */ - static result_t create(std::vector::iterator& it, const std::vector::iterator end, - const std::map templates, Message*& returnValue); + static result_t create(vector::iterator& it, const vector::iterator end, + const map templates, Message*& returnValue); /** * @brief Get the optional device class. * @return the optional device class. */ - std::string getClass() const { return m_class; } + string getClass() const { return m_class; } /** * @brief Get the message name (unique within the same class and type). * @return the message name (unique within the same class and type). */ - std::string getName() const { return m_name; } + string getName() const { return m_name; } /** * @brief Get whether this is a set message. * @return whether this is a set message. @@ -99,7 +101,7 @@ public: * @brief Get the comment. * @return the comment. */ - std::string getComment() const { return m_comment; } + string getComment() const { return m_comment; } /** * @brief Get the source address. * @return the source address, or @a SYN for any. @@ -114,39 +116,39 @@ public: * @brief Get the command ID bytes. * @return the primary, secondary, and optionally further command ID bytes. */ - std::vector getId() const { return m_id; } + vector getId() const { return m_id; } /** * @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 @a std::ostringstream to append the formatted value to. + * @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 separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - //result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, + //result_t read(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, // bool verbose=false, char separator=';') = 0; /** * @brief Writes the value to the master or slave @a SymbolString. - * @param input the @a std::istringstream to parse the formatted value from. + * @param input the @a 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 @a RESULT_OK on success, or an error code. */ result_t prepare(const unsigned char srcAddress, SymbolString& masterData, - std::istringstream& input, char separator=';'); + istringstream& input, char separator=';'); result_t handle(SymbolString& masterData, SymbolString& slaveData, - std::ostringstream& output, char separator=';', bool answer=false); + ostringstream& output, char separator=';', bool answer=false); private: /** the optional device class. */ - const std::string m_class; + const string m_class; /** the message name (unique within the same class and type). */ - const std::string m_name; + const string m_name; /** whether this is a set message. */ const bool m_isSetMessage; /** true if message can be initiated by the daemon itself and any other @@ -154,13 +156,13 @@ private: * other than the daemon. */ const bool m_isActiveMessage; /** the comment. */ - const std::string m_comment; + const string m_comment; /** the source address (optional if passive), or @a SYN for any. */ const unsigned char m_srcAddress; /** the destination address. */ const unsigned char m_dstAddress; /** the primary, secondary, and optionally further command ID bytes. */ - const std::vector m_id; + const vector m_id; /** the @a DataField for encoding/decoding the message. */ DataField* m_data; /** the priority for polling, or 0 for no polling at all. */ diff --git a/src/lib/ebus/result.cpp b/src/lib/ebus/result.cpp index eeb2787e..ac44d46d 100644 --- a/src/lib/ebus/result.cpp +++ b/src/lib/ebus/result.cpp @@ -18,8 +18,12 @@ */ #include "result.h" +#include + +using namespace std; const char* getResultCode(result_t resultCode) { +cout << "DEBUG error code: " << static_cast(resultCode) << endl; switch (resultCode) { case RESULT_ERR_SEND: return "ERR_SEND: send error"; case RESULT_ERR_EXTRA_DATA: return "ERR_EXTRA_DATA: received bytes > sent bytes"; diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index 9a979958..730003f6 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -22,6 +22,8 @@ #include #include +using namespace std; + /** * @brief CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1. */ @@ -46,7 +48,7 @@ static const unsigned char CRC_LOOKUP_TABLE[] = }; -SymbolString::SymbolString(const std::string str) +SymbolString::SymbolString(const string str) : m_unescapeState(0), m_crc(0) { // parse + escape @@ -58,7 +60,7 @@ SymbolString::SymbolString(const std::string str) push_back(m_crc, false, false); } -SymbolString::SymbolString(const std::string str, bool isEscaped) +SymbolString::SymbolString(const string str, bool isEscaped) : m_unescapeState(1), m_crc(0) { // parse + optionally unescape @@ -68,9 +70,9 @@ SymbolString::SymbolString(const std::string str, bool isEscaped) } } -const std::string SymbolString::getDataStr(const bool unescape) +const string SymbolString::getDataStr(const bool unescape) { - std::stringstream sstr; + stringstream sstr; bool previousEscape = false; for (size_t i = 0; i < m_data.size(); i++) { @@ -89,8 +91,8 @@ const std::string SymbolString::getDataStr(const bool unescape) previousEscape = true; // escape sequence not yet finished } else { - sstr << std::nouppercase << std::setw(2) << std::hex - << std::setfill('0') << static_cast(value); + sstr << nouppercase << setw(2) << hex + << setfill('0') << static_cast(value); } } diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index db48095f..e8b3b136 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -25,6 +25,8 @@ #include #include +using namespace std; + static const unsigned char ESC = 0xA9; // escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA static const unsigned char SYN = 0xAA; // synchronization symbol static const unsigned char ACK = 0x00; // positive acknowledge @@ -48,19 +50,19 @@ public: * @brief Creates a new escaped instance from an unescaped hex string and adds the calculated CRC. * @param str the unescaped hex string. */ - SymbolString(const std::string str); + SymbolString(const string str); /** * @brief Creates a new unescaped instance from a hex string. * @param isEscaped whether the hex string is escaped and shall be unescaped. * @param str the hex string. */ - SymbolString(const std::string str, const bool isEscaped); + SymbolString(const string str, const bool isEscaped); /** * @brief Returns the symbols as hex string. * @param unescape whether to unescape an escaped instance. * @return the symbols as hex string. */ - const std::string getDataStr(const bool unescape=true); + const string getDataStr(const bool unescape=true); /** * @brief Returns a reference to the symbol at the specified index. * @param index the index of the symbol to return. @@ -114,7 +116,7 @@ private: /** * @brief the string of bus symbols. */ - std::vector m_data; + vector m_data; /** * @brief 0 if the symbols in @a m_data are escaped, * 1 if the symbols in @a m_data are unescaped and the last symbol passed to @a push_back was a normal symbol, diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 1d6602a1..0591bf6b 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -21,27 +21,28 @@ #include #include -void verify(bool expectFailMatch, std::string type, std::string input, - bool match, std::string expectStr, std::string gotStr) +using namespace std; + +void verify(bool expectFailMatch, string type, string input, + bool match, string expectStr, string gotStr) { if (expectFailMatch == true) { if (match == true) - std::cout << " failed " << type << " match >" << input - << "< error: unexpectedly succeeded" << std::endl; + cout << " failed " << type << " match >" << input + << "< error: unexpectedly succeeded" << endl; else - std::cout << " failed " << type << " match >" << input << "< OK" - << std::endl; + cout << " failed " << type << " match >" << input << "< OK" << endl; } else if (match == true) - std::cout << " " << type << " match >" << input << "< OK" << std::endl; + cout << " " << type << " match >" << input << "< OK" << endl; else - std::cout << " " << type << " match >" << input << "< error: got >" << gotStr - << "<, expected >" << expectStr << "<" << std::endl; + cout << " " << type << " match >" << input << "< error: got >" + << gotStr << "<, expected >" << expectStr << "<" << endl; } int main() { - std::string checks[][5] = { + string checks[][5] = { //name;[len];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags {"x;;ign:10", "", "10fe07000a00000000000000000000", "00", ""}, {"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, @@ -180,60 +181,59 @@ int main() {"x;;trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct {"x;;temp;;;;y;;d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def }; - std::map templates; + map templates; DataField* fields = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { - std::string check[5] = checks[i]; - std::istringstream isstr(check[0]); - std::string expectStr = check[1]; + string check[5] = checks[i]; + istringstream isstr(check[0]); + string expectStr = check[1]; SymbolString mstr = SymbolString(check[2], false); SymbolString sstr = SymbolString(check[3], false); - std::string flags = check[4]; - bool isSet = flags.find('s') != std::string::npos; - bool failedCreate = flags.find('c') != std::string::npos; - bool failedRead = flags.find('r') != std::string::npos; - bool failedReadMatch = flags.find('R') != std::string::npos; - bool failedWrite = flags.find('w') != std::string::npos; - bool failedWriteMatch = flags.find('W') != std::string::npos; - bool verbose = flags.find('v') != std::string::npos; - bool isTemplate = flags.find('t') != std::string::npos; - std::string item; - std::vector entries; + string flags = check[4]; + bool isSet = flags.find('s') != string::npos; + bool failedCreate = flags.find('c') != string::npos; + bool failedRead = flags.find('r') != string::npos; + bool failedReadMatch = flags.find('R') != string::npos; + bool failedWrite = flags.find('w') != string::npos; + bool failedWriteMatch = flags.find('W') != string::npos; + bool verbose = flags.find('v') != string::npos; + bool isTemplate = flags.find('t') != string::npos; + string item; + vector entries; - while (std::getline(isstr, item, ';') != 0) + while (getline(isstr, item, ';') != 0) entries.push_back(item); if (fields != NULL) { delete fields; fields = NULL; } - std::vector::iterator it = entries.begin(); + vector::iterator it = entries.begin(); result_t result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate ? SYN : mstr[1]); if (failedCreate == true) { if (result == RESULT_OK) - std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl; + cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; else - std::cout << "\"" << check[0] << "\": failed create OK" << std::endl; + cout << "\"" << check[0] << "\": failed create OK" << endl; continue; } if (result != RESULT_OK) { - std::cout << "\"" << check[0] << "\": create error: " - << getResultCode(result) << std::endl; + cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl; continue; } if (fields == NULL) { - std::cout << "\"" << check[0] << "\": create error: NULL" << std::endl; + cout << "\"" << check[0] << "\": create error: NULL" << endl; continue; } if (it != entries.end()) { - std::cout << "\"" << check[0] << "\": create error: trailing input" << std::endl; + cout << "\"" << check[0] << "\": create error: trailing input" << endl; continue; } - std::cout << "\"" << check[0] << "\": create OK" << std::endl; + cout << "\"" << check[0] << "\": create OK" << endl; if (isTemplate) { // store new template - std::string name = fields->getName(); - std::map::iterator current = templates.find(name); + string name = fields->getName(); + map::iterator current = templates.find(name); if (current == templates.end()) { templates[name] = fields; } else { @@ -244,20 +244,20 @@ int main() continue; } - std::ostringstream output; + ostringstream output; SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false); SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false); result = fields->read(mstr, 0, sstr, 0, output, verbose); if (failedRead == true) if (result == RESULT_OK) - std::cout << " failed read " << fields->getName() << " >" - << check[2] << "< error: unexpectedly succeeded" << std::endl; + cout << " failed read " << fields->getName() << " >" + << check[2] << "< error: unexpectedly succeeded" << endl; else - std::cout << " failed read " << fields->getName() << " >" - << check[2] << "< OK" << std::endl; + cout << " failed read " << fields->getName() << " >" + << check[2] << "< OK" << endl; else if (result != RESULT_OK) { - std::cout << " read " << fields->getName() << " >" << check[2] << "< error: " - << getResultCode(result) << std::endl; + cout << " read " << fields->getName() << " >" << check[2] + << "< error: " << getResultCode(result) << endl; } else { bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0; @@ -265,19 +265,19 @@ int main() } if (verbose == false) { - std::istringstream input(expectStr); + istringstream input(expectStr); result = fields->write(input, writeMstr, 0, writeSstr, 0); if (failedWrite == true) { if (result == RESULT_OK) - std::cout << " failed write " << fields->getName() << " >" - << expectStr << "< error: unexpectedly succeeded" << std::endl; + cout << " failed write " << fields->getName() << " >" + << expectStr << "< error: unexpectedly succeeded" << endl; else - std::cout << " failed write " << fields->getName() << " >" - << expectStr << "< OK" << std::endl; + cout << " failed write " << fields->getName() << " >" + << expectStr << "< OK" << endl; } else if (result != RESULT_OK) { - std::cout << " write " << fields->getName() << " >" - << expectStr << "< error: " << getResultCode(result) << std::endl; + cout << " write " << fields->getName() << " >" << expectStr + << "< error: " << getResultCode(result) << endl; } else { bool match = mstr == writeMstr && sstr == writeSstr; @@ -288,7 +288,7 @@ int main() fields = NULL; } - for (std::map::iterator it = templates.begin(); it != templates.end(); it++) + for (map::iterator it = templates.begin(); it != templates.end(); it++) delete it->second; return 0; diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 88021045..1d402051 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -21,27 +21,28 @@ #include #include -void verify(bool expectFailMatch, std::string type, std::string input, - bool match, std::string expectStr, std::string gotStr) +using namespace std; + +void verify(bool expectFailMatch, string type, string input, + bool match, string expectStr, string gotStr) { if (expectFailMatch == true) { if (match == true) - std::cout << " failed " << type << " match >" << input - << "< error: unexpectedly succeeded" << std::endl; + cout << " failed " << type << " match >" << input + << "< error: unexpectedly succeeded" << endl; else - std::cout << " failed " << type << " match >" << input << "< OK" - << std::endl; + cout << " failed " << type << " match >" << input << "< OK" << endl; } else if (match == true) - std::cout << " " << type << " match >" << input << "< OK" << std::endl; + cout << " " << type << " match >" << input << "< OK" << endl; else - std::cout << " " << type << " match >" << input << "< error: got >" << gotStr - << "<, expected >" << expectStr << "<" << std::endl; + cout << " " << type << " match >" << input << "< error: got >" + << gotStr << "<, expected >" << expectStr << "<" << endl; } -void printErrorPos(std::vector::iterator it, const std::vector::iterator end, std::vector::iterator pos) +void printErrorPos(vector::iterator it, const vector::iterator end, vector::iterator pos) { - std::cout << "Errroneous item is here:" << std::endl; + cout << "Errroneous item is here:" << endl; bool first = true; int cnt = 0; if (pos > it) @@ -50,7 +51,7 @@ void printErrorPos(std::vector::iterator it, const std::vector::iterator it, const std::vector templates; + map templates; Message* message = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { - std::string check[5] = checks[i]; - std::istringstream isstr(check[0]); - std::string inputStr = check[1]; + string check[5] = checks[i]; + istringstream isstr(check[0]); + string inputStr = check[1]; SymbolString mstr = SymbolString(check[2], false); SymbolString sstr = SymbolString(check[3], false); - std::string flags = check[4]; - bool failedCreate = flags.find('c') != std::string::npos; - bool failedPrepare = flags.find('p') != std::string::npos; - bool failedPrepareMatch = flags.find('P') != std::string::npos; - std::string item; - std::vector entries; + string flags = check[4]; + bool failedCreate = flags.find('c') != string::npos; + bool failedPrepare = flags.find('p') != string::npos; + bool failedPrepareMatch = flags.find('P') != string::npos; + string item; + vector entries; - while (std::getline(isstr, item, ';') != 0) + while (getline(isstr, item, ';') != 0) entries.push_back(item); if (message != NULL) { delete message; message = NULL; } - std::vector::iterator it = entries.begin(); + vector::iterator it = entries.begin(); result_t result = Message::create(it, entries.end(), templates, message); if (failedCreate == true) { if (result == RESULT_OK) - std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl; + cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; else - std::cout << "\"" << check[0] << "\": failed create OK" << std::endl; + cout << "\"" << check[0] << "\": failed create OK" << endl; continue; } if (result != RESULT_OK) { - std::cout << "\"" << check[0] << "\": create error: " - << getResultCode(result) << std::endl; + cout << "\"" << check[0] << "\": create error: " + << getResultCode(result) << endl; printErrorPos(entries.begin(), entries.end(), it); continue; } if (message == NULL) { - std::cout << "\"" << check[0] << "\": create error: NULL" << std::endl; + cout << "\"" << check[0] << "\": create error: NULL" << endl; continue; } if (it != entries.end()) { - std::cout << "\"" << check[0] << "\": create error: trailing input" << std::endl; + cout << "\"" << check[0] << "\": create error: trailing input" << endl; continue; } - std::cout << "\"" << check[0] << "\": create OK" << std::endl; + cout << "\"" << check[0] << "\": create OK" << endl; - std::istringstream input(inputStr); + istringstream input(inputStr); SymbolString writeMstr = SymbolString(); result = message->prepare(0xff, writeMstr, input); if (failedPrepare == true) { if (result == RESULT_OK) - std::cout << "\"" << check[0] << "\": failed prepare error: unexpectedly succeeded" << std::endl; + cout << "\"" << check[0] << "\": failed prepare error: unexpectedly succeeded" << endl; else - std::cout << "\"" << check[0] << "\": failed prepare OK" << std::endl; + cout << "\"" << check[0] << "\": failed prepare OK" << endl; continue; } if (result != RESULT_OK) { - std::cout << " prepare >" << inputStr << "< error: " - << getResultCode(result) << std::endl; + cout << " prepare >" << inputStr << "< error: " + << getResultCode(result) << endl; continue; } - std::cout << " prepare >" << inputStr << "< OK" << std::endl; + cout << " prepare >" << inputStr << "< OK" << endl; bool match = writeMstr==mstr; verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); @@ -146,7 +147,7 @@ int main() message = NULL; } - for (std::map::iterator it = templates.begin(); it != templates.end(); it++) + for (map::iterator it = templates.begin(); it != templates.end(); it++) delete it->second; return 0; diff --git a/src/lib/ebus/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp index 0ca984a7..b91c3f6e 100644 --- a/src/lib/ebus/test/test_symbol.cpp +++ b/src/lib/ebus/test/test_symbol.cpp @@ -21,6 +21,8 @@ #include #include +using namespace std; + int main () { SymbolString sstr = SymbolString("10feb5050427a915aa"); @@ -30,29 +32,28 @@ int main () if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "ctor escaped successful." << std::endl; else - std::cout << "ctor escaped invalid: got " << gotStr - << ", expected " << expectStr << std::endl; + std::cout << "ctor escaped invalid: got " << gotStr << ", expected " + << expectStr << std::endl; unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77; if (gotCrc == expectCrc) std::cout << "CRC successful." << std::endl; else - std::cout << "CRC invalid: got 0x" - << std::nouppercase << std::setw(2) << std::hex - << std::setfill('0') << static_cast(gotCrc) - << ", expected 0x" - << std::nouppercase << std::setw(2) << std::hex - << std::setfill('0') << static_cast(expectCrc) - << std::endl; + std::cout << "CRC invalid: got 0x" << std::nouppercase << std::setw(2) + << std::hex << std::setfill('0') + << static_cast(gotCrc) << ", expected 0x" + << std::nouppercase << std::setw(2) << std::hex + << std::setfill('0') << static_cast(expectCrc) + << std::endl; gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77"; if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "unescape successful." << std::endl; else - std::cout << "unescape invalid: got " << gotStr - << ", expected " << expectStr << std::endl; + std::cout << "unescape invalid: got " << gotStr << ", expected " + << expectStr << std::endl; sstr = SymbolString("10feb5050427a90015a90177", true); @@ -61,8 +62,8 @@ int main () if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) std::cout << "ctor unescaped successful." << std::endl; else - std::cout << "ctor unescaped invalid: got " << gotStr - << ", expected " << expectStr << std::endl; + std::cout << "ctor unescaped invalid: got " << gotStr << ", expected " + << expectStr << std::endl; return 0; From aa443d1eb775850a9b2458dba9045d4d43e47fd7 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 22 Nov 2014 20:57:51 +0100 Subject: [PATCH 15/15] adjusted to included weekday on write --- src/lib/ebus/test/test_message.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 1d402051..58000e5b 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -71,8 +71,8 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610001451", "00", ""}, - {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610001445", "00", ""}, + {";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""}, + {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""}, }; map templates; Message* message = NULL;