From 6e0ddb1e8ba53cf4147d6c9116f2b8191668a36d Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 13:31:23 +0100 Subject: [PATCH 01/83] removed pt_masterDataID again --- src/lib/ebus/data.cpp | 19 +++++-------------- src/lib/ebus/data.h | 1 - 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 7a845899..6decd204 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -126,10 +126,7 @@ result_t DataField::create(vector::iterator& it, firstName = name; firstComment = comment; } - if (isTemplate == false && strcasecmp(partStr, "I") == 0) { - partType = pt_masterDataID; - } - else if (dstAddress == BROADCAST || isMaster(dstAddress) + if (dstAddress == BROADCAST || isMaster(dstAddress) || (isTemplate == false && isSetMessage == true && partStr[0] == 0) || strcasecmp(partStr, "M") == 0) { // master data partType = pt_masterData; @@ -334,7 +331,6 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff switch (m_partType) { case pt_masterData: - case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -376,7 +372,6 @@ result_t SingleDataField::write(istringstream& input, switch (m_partType) { case pt_masterData: - case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -955,11 +950,11 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset output << m_name << "={ "; bool first = true; - unsigned char offsets[4]; + unsigned char offsets[3]; memset(offsets, 0, sizeof(offsets)); offsets[pt_masterData] = masterOffset; offsets[pt_slaveData] = slaveOffset; - bool previousFullByteOffset[] = { true, true, true, true }; + bool previousFullByteOffset[] = { true, true, true }; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; bool ignored = field->isIgnored(); @@ -971,8 +966,6 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset else output << separator; } - if (partType == pt_masterDataID) - partType = pt_masterData; if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) offsets[partType]--; @@ -1002,18 +995,16 @@ result_t DataFieldSet::write(istringstream& input, { string token; - unsigned char offsets[4]; + unsigned char offsets[3]; memset(offsets, 0, sizeof(offsets)); offsets[pt_masterData] = masterOffset; offsets[pt_slaveData] = slaveOffset; - bool previousFullByteOffset[] = { true, true, true, true }; + bool previousFullByteOffset[] = { true, true, true }; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; bool ignored = field->isIgnored(); PartType partType = field->getPartType(); - if (partType == pt_masterDataID) - partType = pt_masterData; if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) offsets[partType]--; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index a9cf9579..0045488b 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -32,7 +32,6 @@ using namespace std; enum PartType { 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 }; From ea63e9d461dc37423d3030a45d2a9be77b9321cb Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 13:32:38 +0100 Subject: [PATCH 02/83] use result_t, added getMasterNumber(), documentation --- src/lib/ebus/symbol.cpp | 45 ++++++++++++++++++++++++++++++++++++++++- src/lib/ebus/symbol.h | 17 +++++++++++----- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index 730003f6..0ce1fbcb 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -99,7 +99,7 @@ const string SymbolString::getDataStr(const bool unescape) return sstr.str(); } -int SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) +result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) { if (m_unescapeState == 0) { // store escaped data if (isEscaped == false && value == ESC) { @@ -189,6 +189,49 @@ bool isMaster(unsigned char addr) { && ((addrLo == 0x0) || (addrLo == 0x1) || (addrLo == 0x3) || (addrLo == 0x7) || (addrLo == 0xF)); } +unsigned char getMasterNumber(unsigned char addr) { + unsigned char addrHi = (addr & 0xF0) >> 4; + unsigned char addrLo = (addr & 0x0F); + + unsigned char index; + switch (addrHi) + { + case 0x0: + index = 0; + break; + case 0x1: + index = 1; + break; + case 0x3: + index = 2; + break; + case 0x7: + index = 3; + break; + case 0xF: + index = 4; + break; + default: + return 0; + } + + switch (addrLo) + { + case 0x0: + return 5*index + 1; + case 0x1: + return 5*index + 2; + case 0x3: + return 5*index + 3; + case 0x7: + return 5*index + 4; + case 0xF: + return 5*index + 5; + default: + return 0; + } +} + bool isValidAddress(unsigned char addr, bool allowBroadcast) { return addr != SYN && addr != ESC && (allowBroadcast == true || addr != BROADCAST); } diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index e8b3b136..cd117362 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -20,6 +20,7 @@ #ifndef LIBEBUS_SYMBOL_H_ #define LIBEBUS_SYMBOL_H_ +#include "result.h" #include #include #include @@ -43,7 +44,6 @@ class SymbolString public: /** * @brief Creates a new unescaped empty instance. - * @param escaped whether to create an escaped instance. */ SymbolString() : m_unescapeState(1), m_crc(0) {} /** @@ -90,12 +90,12 @@ public: * RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received, * RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected. */ - int push_back(const unsigned char value, const bool isEscaped, const bool updateCRC=true); + result_t push_back(const unsigned char value, const bool isEscaped, const bool updateCRC=true); /** * @brief Returns the number of symbols in this symbol string. * @return the number of available symbols. */ - size_t size() const { return m_data.size(); } + unsigned char size() const { return (unsigned char)m_data.size(); } /** * @brief Returns the calculated CRC. * @return the calculated CRC. @@ -131,14 +131,21 @@ private: /** - * Returns whether the address is one of the 25 master addresses. + * @brief Returns whether the address is one of the 25 master addresses. * @param addr the address to check. * @return true if the specified address is a master address. */ bool isMaster(unsigned char addr); /** - * Returns whether the address is a valid bus address. + * @brief Returns the number of the master if the address is a valid bus address. + * @param addr the bus address. + * @return the number of the master if the address is a valid bus address (1 to 25), or 0. + */ +unsigned char getMasterNumber(unsigned char addr); + +/** + * @brief Returns whether the address is a valid bus address. * @param addr the address to check. * @param allowBroadcast whether to also allow @a addr to be the broadcast address (default true). * @return true if the specified address is a valid bus address. From d19d89a0b0738e3c7505a4e263a8c2f9b3a169fe Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 13:33:31 +0100 Subject: [PATCH 03/83] introduced MessageMap, nicer method names --- src/lib/ebus/message.cpp | 148 +++++++++++++++++++++++++---- src/lib/ebus/message.h | 87 ++++++++++++++--- src/lib/ebus/test/test_message.cpp | 44 +++++++-- 3 files changed, 238 insertions(+), 41 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 6bd69d92..7dff31b9 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -27,28 +27,50 @@ using namespace std; +Message::Message(const string clazz, const string name, const bool isSet, + const bool isActive, const string comment, + const unsigned char srcAddress, const unsigned char dstAddress, + const vector id, DataField* data, + const unsigned int pollPriority) + : m_class(clazz), m_name(name), m_isSet(isSet), + m_isActive(isActive), m_comment(comment), + m_srcAddress(srcAddress), m_dstAddress(dstAddress), + m_id(id), m_data(data), m_pollPriority(pollPriority) +{ + int exp = 7; + unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5); + if (isActive == true) + key |= 0x1fLL << (8 * exp--); + else + key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); + key |= (unsigned long long)dstAddress << (8 * exp--); + for (vector::const_iterator it=id.begin(); it::iterator& it, const vector::iterator end, const map templates, Message*& returnValue) { + // [type];[class];name;[comment];[QQ];ZZ;id;fields... result_t result; - // [type];class;name;[comment];[QQ];ZZ;id;fields... + bool isSet, isActive; + unsigned int pollPriority = 0; 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; + isActive = true; + isSet = true; } else if (str[0] == 'C' || str[0] == 'c') { - isActiveMessage = false; - isSetMessage = str[1] == 'W' || str[1] == 'w'; + isActive = false; + isSet = str[1] == 'W' || str[1] == 'w'; } else if (str[0] == 'P' || str[0] == 'p') { - isActiveMessage = true; - isSetMessage = false; + isActive = true; + isSet = false; if (str[1] == 0) pollPriority = 1; else { @@ -58,8 +80,8 @@ result_t Message::create(vector::iterator& it, const vector::ite return result; } } else { - isActiveMessage = true; - isSetMessage = false; + isActive = true; + isSet = false; } string clazz = *it++; @@ -80,7 +102,7 @@ result_t Message::create(vector::iterator& it, const vector::ite if (it == end) return RESULT_ERR_EOF; unsigned char srcAddress; - if (*str == 0 || isActiveMessage == true) + if (*str == 0 || isActive == true) srcAddress = SYN; // no specific source defined, or ignore for active message else { srcAddress = parseInt(str, 16, 0, 0xff, result); @@ -125,17 +147,17 @@ result_t Message::create(vector::iterator& it, const vector::ite return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID DataField* data = NULL; - result = DataField::create(it, end, templates, data, isSetMessage, dstAddress); + result = DataField::create(it, end, templates, data, isSet, dstAddress); if (result != RESULT_OK) return result; - returnValue = new Message(clazz, name, isSetMessage, isActiveMessage, comment, srcAddress, dstAddress, id, data, pollPriority); + returnValue = new Message(clazz, name, isSet, isActive, comment, srcAddress, dstAddress, id, data, pollPriority); return RESULT_OK; } result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator) { - if (m_isActiveMessage == true) { + if (m_isActive == true) { masterData.clear(); masterData.push_back(srcAddress, false); masterData.push_back(m_dstAddress, false); @@ -157,7 +179,7 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, char separator, bool answer) { - if (m_isActiveMessage == true) { + if (m_isActive == true) { result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); if (result != RESULT_OK) return result; @@ -170,3 +192,97 @@ result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, } return RESULT_OK; } + + +result_t MessageMap::add(Message* message) +{ + string key = message->getClass().append(";").append(message->getName()); + if (message->isActive() == true) + key.append(message->isSet() ? ";W" : ";R"); + else + key.append(";C"); + map::iterator nameIt = m_messagesByName.find(key); + if (nameIt != m_messagesByName.end()) + return RESULT_ERR_INVALID_ARG; // duplicate key + + if (message->isActive() == false) { + unsigned long long pkey = message->getKey(); + map::iterator keyIt = m_passiveMessagesByKey.find(pkey); + if (keyIt != m_passiveMessagesByKey.end()) + return RESULT_ERR_INVALID_ARG; // duplicate key + + unsigned char idLength = message->getId().size() - 2; + if (idLength > m_maxIdLength) + m_maxIdLength = idLength; + m_passiveMessagesByKey[pkey] = message; + } + + m_messagesByName[key] = message; + + return RESULT_OK; +} + +Message* MessageMap::find(const string clazz, const string name, const bool isActive, const bool isSet) +{ + string key = clazz; + for (int i=0; i<2; i++) { + key.append(";").append(name); + if (isActive == true) + key.append(isSet ? ";W" : ";R"); + else + key.append(";C"); + map::iterator it = m_messagesByName.find(key); + if (it != m_messagesByName.end()) + return it->second; + key.clear(); // try again without class name + } + + return NULL; +} + +Message* MessageMap::find(SymbolString master) { + if (master.size() < 5) + return NULL; + unsigned char maxIdLength = master[4]; + if (maxIdLength > m_maxIdLength) + maxIdLength = m_maxIdLength; + if (master.size() < 5+maxIdLength) + return NULL; + + unsigned long long sourceMask = 0x1fLL << (8 * 7); + for (int idLength=maxIdLength; idLength>=0; idLength--) { + int exp = 7; + unsigned long long key = (unsigned long long)idLength << (8 * exp + 5); + key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--); + key |= (unsigned long long)master[1] << (8 * exp--); + key |= (unsigned long long)master[2] << (8 * exp--); + key |= (unsigned long long)master[3] << (8 * exp--); + for (unsigned char i=0; i::iterator it = m_passiveMessagesByKey.find(key); + if (it != m_passiveMessagesByKey.end()) + return it->second; + + if ((key & sourceMask) != 0) { + key &= ~sourceMask; // try again without specific source master + it = m_passiveMessagesByKey.find(key); + if (it != m_passiveMessagesByKey.end()) + return it->second; + } + } + + return NULL; +} + +void MessageMap::clear() +{ + for (map::iterator it=m_messagesByName.begin(); it!=m_messagesByName.end(); it++) { + delete it->second; + it->second = NULL; + } + m_messagesByName.clear(); + m_passiveMessagesByKey.clear(); + m_maxIdLength = 0; +} + diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 4856f9bb..9e1d5b6b 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -25,11 +25,12 @@ #include "symbol.h" #include #include +#include using namespace std; /** - * @brief Base class for all kinds of bus messages. + * @brief Defines parameters of a message sent or received on the bus. */ class Message { @@ -39,8 +40,8 @@ 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 + * @param isSet whether this is a set message. + * @param isActive 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. @@ -50,15 +51,11 @@ 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 string clazz, const string name, const bool isSetMessage, - const bool isActiveMessage, const string comment, + Message(const string clazz, const string name, const bool isSet, + const bool isActive, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, const 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) {} + const unsigned int pollPriority); /** * @brief Destructor. */ @@ -88,7 +85,7 @@ public: * @brief Get whether this is a set message. * @return whether this is a set message. */ - bool isSetMessage() const { return m_isSetMessage; } + bool isSet() const { return m_isSet; } /** * @brief Get whether message can be initiated by the daemon itself and any other * participant. @@ -96,7 +93,7 @@ public: * participant, false if message can only be initiated by a participant * other than the daemon. */ - bool isActiveMessage() const { return m_isActiveMessage; } + bool isActive() const { return m_isActive; } /** * @brief Get the comment. * @return the comment. @@ -117,6 +114,11 @@ public: * @return the primary, secondary, and optionally further command ID bytes. */ vector getId() const { return m_id; } + /** + * @brief Returns the key for storing in @a MessageSet. + * @return the key for storing in @a MessageSet. + */ + unsigned long long getKey() { return m_key; } /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -142,7 +144,6 @@ public: result_t handle(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, char separator=';', bool answer=false); - private: /** the optional device class. */ @@ -150,11 +151,11 @@ private: /** the message name (unique within the same class and type). */ const string m_name; /** whether this is a set message. */ - const bool m_isSetMessage; + const bool m_isSet; /** 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; + const bool m_isActive; /** the comment. */ const string m_comment; /** the source address (optional if passive), or @a SYN for any. */ @@ -163,6 +164,8 @@ private: const unsigned char m_dstAddress; /** the primary, secondary, and optionally further command ID bytes. */ const vector m_id; + /** the key for storing in @a MessageSet. */ + unsigned long long m_key; /** the @a DataField for encoding/decoding the message. */ DataField* m_data; /** the priority for polling, or 0 for no polling at all. */ @@ -170,4 +173,58 @@ private: }; +/** + * @brief Holds a map of all known @a Message instances. + */ +class MessageMap +{ +public: + + /** + * @brief Constructs a new instance. + */ + MessageMap() : m_maxIdLength(0) {} + /** + * @brief Destructor. + */ + virtual ~MessageMap() { clear(); } + /** + * @brief Adds a @a Message instance to this set. + * @param message the @a Message instance to add. + * @return @a RESULT_OK on success, or an error code. + * Note: the caller may not free the created instance on success. + */ + result_t add(Message* message); + /** + * @brief Finds the @a Message instance for the specified class and name. + * @param master the master @a SymbolString for identifying the @a Message. + * @return the @a Message instance, or NULL. + * Note: the caller may not free the returned instance. + */ + Message* find(const string clazz, const string name, const bool isActive, const bool isSet); + /** + * @brief Finds the @a Message instance for the specified master data. + * @param master the master @a SymbolString for identifying the @a Message. + * @return the @a Message instance, or NULL. + * Note: the caller may not free the returned instance. + */ + Message* find(SymbolString master); + /** + * @brief Removes all @a Message instances. + */ + void clear(); + +private: + + /** the maximum ID length used by any of the known @a Message instances. */ + unsigned char m_maxIdLength; + + /** the known @a Message instances by class and name. */ + map m_messagesByName; + + /** the known passive @a Message instances by key. */ + map m_passiveMessagesByKey; + +}; + #endif // LIBEBUS_MESSAGE_H_ diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 58000e5b..5acb2bad 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -42,7 +42,7 @@ void verify(bool expectFailMatch, string type, string input, void printErrorPos(vector::iterator it, const vector::iterator end, vector::iterator pos) { - cout << "Errroneous item is here:" << endl; + cout << "Erroneous item is here:" << endl; bool first = true; int cnt = 0; if (pos > it) @@ -71,11 +71,13 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""}, + {"c;;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; + Message *message = NULL; + Message* deleteMessage = NULL; + MessageMap* messages = new MessageMap(); for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; istringstream isstr(check[0]); @@ -83,6 +85,7 @@ int main() SymbolString mstr = SymbolString(check[2], false); SymbolString sstr = SymbolString(check[3], false); string flags = check[4]; + bool dontMap = flags.find('m') != string::npos; bool failedCreate = flags.find('c') != string::npos; bool failedPrepare = flags.find('p') != string::npos; bool failedPrepareMatch = flags.find('P') != string::npos; @@ -92,12 +95,12 @@ int main() while (getline(isstr, item, ';') != 0) entries.push_back(item); - if (message != NULL) { - delete message; - message = NULL; + if (deleteMessage != NULL) { + delete deleteMessage; + deleteMessage = NULL; } vector::iterator it = entries.begin(); - result_t result = Message::create(it, entries.end(), templates, message); + result_t result = Message::create(it, entries.end(), templates, deleteMessage); if (failedCreate == true) { if (result == RESULT_OK) @@ -112,7 +115,7 @@ int main() printErrorPos(entries.begin(), entries.end(), it); continue; } - if (message == NULL) { + if (deleteMessage == NULL) { cout << "\"" << check[0] << "\": create error: NULL" << endl; continue; } @@ -122,6 +125,23 @@ int main() } cout << "\"" << check[0] << "\": create OK" << endl; + if (dontMap == false) { + result = messages->add(deleteMessage); + if (result != RESULT_OK) { + cout << "\"" << check[0] << "\": add error: " + << getResultCode(result) << endl; + continue; + } + cout << " map OK" << endl; + message = deleteMessage; + deleteMessage = NULL; + if (messages->find(mstr) == message) + cout << " find OK" << endl; + else + cout << " find error: NULL" << endl; + } + else + message = deleteMessage; istringstream input(inputStr); SymbolString writeMstr = SymbolString(); result = message->prepare(0xff, writeMstr, input); @@ -142,14 +162,18 @@ int main() bool match = writeMstr==mstr; verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); + } - delete message; - message = NULL; + if (deleteMessage != NULL) { + delete deleteMessage; + deleteMessage = NULL; } for (map::iterator it = templates.begin(); it != templates.end(); it++) delete it->second; + delete messages; + return 0; } From 42ee567e63d2ffbeb24684a685ec84018db62667 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:40:18 +0100 Subject: [PATCH 04/83] introduced DataFieldTemplates,a dded missing type HTI --- src/lib/ebus/data.cpp | 49 ++++++++++++++++++++++++++++++++++---- src/lib/ebus/data.h | 55 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 6decd204..1d0f6fce 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -38,6 +38,7 @@ static const dataType_t dataTypes[] = { {"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) + {"HTI", 24, bt_tim, 0, 0, 5, 5, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b) {"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" (0x00 - 0x06) [ebus type] @@ -97,7 +98,7 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co result_t DataField::create(vector::iterator& it, const vector::iterator end, - const map< string, DataField*> templates, + DataFieldTemplates* templates, DataField*& returnField, const bool isSetMessage, const unsigned char dstAddress) { @@ -199,20 +200,20 @@ result_t DataField::create(vector::iterator& it, if (pos == string::npos) { length = 0; // check for reference(s) to templates - if (templates.empty() == false) { + if (templates != NULL) { istringstream stream(typeStr); bool found = false; string lengthStr; while (getline(stream, token, VALUE_SEPARATOR) != 0) { - map::const_iterator ref = templates.find(token); - if (ref == templates.end()) { + DataField* templ = templates->get(token); + if (templ == NULL) { 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); + result = templ->derive(name, comment, unit, partType, divisor, values, fields); if (result != RESULT_OK) break; } @@ -1030,3 +1031,41 @@ result_t DataFieldSet::write(istringstream& input, return RESULT_OK; } + + +void DataFieldTemplates::clear() +{ + for (map::iterator it=m_fieldsByName.begin(); it!=m_fieldsByName.end(); it++) { + delete it->second; + it->second = NULL; + } + m_fieldsByName.clear(); +} + +result_t DataFieldTemplates::add(DataField* field, bool replace) +{ + string name = field->getName(); + map::iterator it = m_fieldsByName.find(name); + if (it != m_fieldsByName.end()) { + if (replace == false) + return RESULT_ERR_INVALID_ARG; // duplicate key + + delete it->second; + it->second = field; + + return RESULT_OK; + } + + m_fieldsByName[name] = field; + + return RESULT_OK; +} + +DataField* DataFieldTemplates::get(const string name) +{ + map::const_iterator ref = m_fieldsByName.find(name); + if (ref == m_fieldsByName.end()) + return NULL; + + return ref->second; +} diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 0045488b..874bbe61 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -79,6 +79,7 @@ typedef struct { unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL); +class DataFieldTemplates; class SingleDataField; /** @@ -103,7 +104,7 @@ public: * @brief Factory method for creating new instances. * @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 templates the @a DataFieldTemplates to be referenced by name, or NULL. * @param returnField the variable in which to store the created instance. * @param isSetMessage whether the field is part of a set message (default false). * @param dstAddress the destination bus address (default @a SYN for creating a template @a DataField). @@ -111,7 +112,7 @@ public: * Note: the caller needs to free the created instance. */ static result_t create(vector::iterator& it, const vector::iterator end, - const map templates, DataField*& returnField, + DataFieldTemplates* templates, DataField*& returnField, const bool isSetMessage=false, const unsigned char dstAddress=SYN); /** * @brief Returns the length of this field (or contained fields) in bytes. @@ -279,6 +280,8 @@ protected: */ virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output) = 0; +protected: + /** the value unit. */ const string m_unit; /** the data type definition. */ @@ -386,7 +389,6 @@ protected: /** the offset to the first bit in the binary value. */ const unsigned char m_bitOffset; - }; @@ -431,6 +433,8 @@ protected: // @copydoc virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); +private: + /** the combined divisor to apply on the value, or 1 for none. */ const unsigned int m_divisor; @@ -478,6 +482,8 @@ protected: // @copydoc virtual result_t writeSymbols(istringstream& input, const unsigned char offset, SymbolString& output); +private: + /** the value=text assignments. */ map m_values; @@ -540,7 +546,7 @@ public: SymbolString& slaveData, unsigned char slaveOffset, char separator); -protected: +private: /** the @a vector of @a SingleDataField instances part of this set. */ vector m_fields; @@ -548,4 +554,45 @@ protected: }; +/** + * @brief A map of template @a DataField instances. + */ +class DataFieldTemplates +{ +public: + + /** + * @brief Constructs a new instance. + */ + DataFieldTemplates() {} + /** + * @brief Destructor. + */ + virtual ~DataFieldTemplates() { clear(); } + /** + * @brief Removes all @a DataField instances. + */ + void clear(); + /** + * @brief Adds a template @a DataField instance to this map. + * @param field the @a DataField instance to add. + * @param replace whether replacing an already stored instance is allowed. + * @return @a RESULT_OK on success, or an error code. + * Note: the caller may not free the added instance on success. + */ + result_t add(DataField* message, bool replace=false); + /** + * @brief Gets the template @a DataField instance with the specified name. + * @return the template @a DataField instance, or NULL. + * Note: the caller may not free the returned instance. + */ + DataField* get(string name); + +private: + + /** the known template @a DataField instances by name. */ + map m_fieldsByName; + +}; + #endif // LIBEBUS_DATA_H_ From 2922d25539b964a762975224555aea05ceaf2be0 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:40:18 +0100 Subject: [PATCH 05/83] introduced DataFieldTemplates,a dded missing type HTI --- src/lib/ebus/message.cpp | 2 +- src/lib/ebus/message.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 7dff31b9..6b1dc1af 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -50,7 +50,7 @@ Message::Message(const string clazz, const string name, const bool isSet, } result_t Message::create(vector::iterator& it, const vector::iterator end, - const map templates, Message*& returnValue) + DataFieldTemplates* templates, Message*& returnValue) { // [type];[class];name;[comment];[QQ];ZZ;id;fields... result_t result; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 9e1d5b6b..195b8664 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -64,13 +64,13 @@ public: * @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 templates the @a DataFieldTemplates to be referenced by name, or NULL. * @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(vector::iterator& it, const vector::iterator end, - const map templates, Message*& returnValue); + DataFieldTemplates*, Message*& returnValue); /** * @brief Get the optional device class. * @return the optional device class. @@ -192,7 +192,7 @@ public: * @brief Adds a @a Message instance to this set. * @param message the @a Message instance to add. * @return @a RESULT_OK on success, or an error code. - * Note: the caller may not free the created instance on success. + * Note: the caller may not free the added instance on success. */ result_t add(Message* message); /** From 9a5fb321a65cb335f8aaa9fe926a454ac71f83fc Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:40:18 +0100 Subject: [PATCH 06/83] introduced DataFieldTemplates,a dded missing type HTI --- src/lib/ebus/data.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 1d0f6fce..7c1ee862 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -38,7 +38,7 @@ static const dataType_t dataTypes[] = { {"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) - {"HTI", 24, bt_tim, 0, 0, 5, 5, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b) + {"HTI", 24, bt_tim, 0, 0, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b) {"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" (0x00 - 0x06) [ebus type] @@ -426,7 +426,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 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) { + if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) { if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) return RESULT_ERR_INVALID_ARG; // invalid BCD ch = (ch >> 4) * 10 + (ch & 0x0f); @@ -585,7 +585,7 @@ result_t StringDataField::writeSymbols(istringstream& input, } lastLast = last; last = value; - if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat || (m_dataType.type == bt_tim && m_length > 2)) { + if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) { if (value > 99) return RESULT_ERR_INVALID_ARG; // invalid BCD value = ((value / 10) << 4) | (value % 10); From 97f050fb168c4861cdfc4cb268f67f939dde42f2 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:40:18 +0100 Subject: [PATCH 07/83] introduced DataFieldTemplates,a dded missing type HTI, switched to UTF8 encoding --- src/lib/ebus/test/test_data.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 0591bf6b..efb0f081 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -68,6 +68,7 @@ int main() {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, {"x;;bti", "", "10fe070003605923", "00", "rw"}, + {"x;;hti", "21:04:58", "10fe07000315043a", "00", ""}, {"x;;htm", "21:04", "10fe0700021504", "00", ""}, {"x;;htm", "00:00", "10fe0700020000", "00", ""}, {"x;;htm", "23:59", "10fe070002173b", "00", ""}, @@ -165,7 +166,7 @@ int main() {"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"}, + {"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","10fe0700085804212610061406", "00", ""}, // combination {"x;;bi3;;;;y;;bi5", "1;-", "10feffff0108", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination @@ -173,7 +174,7 @@ int main() {"x;;bi3;;;;y;;bi5", "-;-", "10feffff0100", "00", ""}, // 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 + {"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 {"x;;relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct @@ -181,7 +182,7 @@ 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 }; - map templates; + DataFieldTemplates* templates = new DataFieldTemplates(); DataField* fields = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; @@ -233,14 +234,13 @@ int main() if (isTemplate) { // store new template string name = fields->getName(); - map::iterator current = templates.find(name); - if (current == templates.end()) { - templates[name] = fields; - } else { - delete current->second; - current->second = fields; + result = templates->add(fields, true); + if (result == RESULT_OK) { + fields = NULL; + cout << " store template OK" << endl; } - fields = NULL; + else + cout << " store template error: " << getResultCode(result) << endl; continue; } @@ -288,8 +288,7 @@ int main() fields = NULL; } - for (map::iterator it = templates.begin(); it != templates.end(); it++) - delete it->second; + delete templates; return 0; From 4d68d443e4096c7d59e648b29a4803bf2e87ed7d Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:40:18 +0100 Subject: [PATCH 08/83] introduced DataFieldTemplates,a dded missing type HTI, added reading of "_types.csv" --- src/lib/ebus/test/test_message.cpp | 54 +++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 5acb2bad..1a80bc21 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -19,6 +19,7 @@ #include "message.h" #include +#include #include using namespace std; @@ -65,6 +66,51 @@ void printErrorPos(vector::iterator it, const vector::iterator e cout << setw(cnt) << " " << setw(0) << "^" << endl; } +bool readTemplates(string filename, DataFieldTemplates* templates) +{ + ifstream ifs; + ifs.open(filename.c_str(), ifstream::in); + if (ifs.is_open() == false) { + cerr << "error reading \"" << filename << endl; + return false; + } + + string line; + unsigned int lineNo = 0; + vector row; + string token; + while (getline(ifs, line) != 0) { + lineNo++; + istringstream isstr(line); + row.clear(); + while (getline(isstr, token, ';') != 0) + row.push_back(token); + + // skip empty and commented rows + if (row.empty() == true || row[0][0] == '#') + continue; + + DataField* field = NULL; + vector::iterator it = row.begin(); + result_t result = DataField::create(it, row.end(), templates, field); + if (result != RESULT_OK) { + cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; + printErrorPos(row.begin(), row.end(), it); + } else if (it != row.end()) + cout << "extra data in \"" << filename << "\" line " << static_cast(lineNo) << endl; + else { + result = templates->add(field, true); + if (result != RESULT_OK) { + cerr << "error adding template \"" << field->getName() << "\": " << getResultCode(result) << endl; + delete field; + } + } + } + + ifs.close(); + return true; +} + int main() { // message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields... @@ -74,7 +120,9 @@ int main() {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""}, {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""}, }; - map templates; + DataFieldTemplates* templates = new DataFieldTemplates(); + readTemplates("_types.csv", templates); + Message *message = NULL; Message* deleteMessage = NULL; MessageMap* messages = new MessageMap(); @@ -169,9 +217,7 @@ int main() deleteMessage = NULL; } - for (map::iterator it = templates.begin(); it != templates.end(); it++) - delete it->second; - + delete templates; delete messages; return 0; From 0068a5f8f7852bf7cfd134861166422dc7b9cc60 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 14:56:56 +0100 Subject: [PATCH 09/83] fix tests --- 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 1a80bc21..5f4901b9 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -117,8 +117,8 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""}, - {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""}, + {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "P"}, + {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, }; DataFieldTemplates* templates = new DataFieldTemplates(); readTemplates("_types.csv", templates); From da6a5563a6c309a977deaec243201db97d51ee76 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 15:18:30 +0100 Subject: [PATCH 10/83] fix for prepare() --- src/lib/ebus/message.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 6b1dc1af..60412223 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -172,8 +172,9 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa if (result != RESULT_OK) return result; masterData.push_back(masterData.getCRC(), false, false); + return RESULT_OK; } - return RESULT_OK; + return RESULT_ERR_INVALID_ARG; // prepare not possible } result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, From 59700b00840574c36f3b5f45e51b942aff7c9ba9 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 15:18:48 +0100 Subject: [PATCH 11/83] added some real examples --- src/lib/ebus/test/test_message.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 5f4901b9..3b7b2410 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -117,8 +117,11 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "P"}, + {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, + {"r;ehp;time;;;08;b5090d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, + {"r;ehp;date;;;08;b5090d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, + {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B50929BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, }; DataFieldTemplates* templates = new DataFieldTemplates(); readTemplates("_types.csv", templates); @@ -195,18 +198,18 @@ int main() result = message->prepare(0xff, writeMstr, input); if (failedPrepare == true) { if (result == RESULT_OK) - cout << "\"" << check[0] << "\": failed prepare error: unexpectedly succeeded" << endl; + cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; else - cout << "\"" << check[0] << "\": failed prepare OK" << endl; + cout << " \"" << inputStr << "\": failed prepare OK" << endl; continue; } if (result != RESULT_OK) { - cout << " prepare >" << inputStr << "< error: " + cout << " \"" << inputStr << "\": prepare error: " << getResultCode(result) << endl; continue; } - cout << " prepare >" << inputStr << "< OK" << endl; + cout << " \"" << inputStr << "\": prepare OK" << endl; bool match = writeMstr==mstr; verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); From 4141f8e0918a03acee69ca52e552d7d077537e08 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:23:43 +0100 Subject: [PATCH 12/83] more result codes --- src/lib/ebus/result.cpp | 3 ++- src/lib/ebus/result.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/ebus/result.cpp b/src/lib/ebus/result.cpp index ac44d46d..4146db05 100644 --- a/src/lib/ebus/result.cpp +++ b/src/lib/ebus/result.cpp @@ -23,7 +23,6 @@ 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"; @@ -37,6 +36,8 @@ cout << "DEBUG error code: " << static_cast(resultCode) << endl; case RESULT_ERR_INVALID_ARG: return "ERR_INVALID_ARG: invalid argument specified"; case RESULT_ERR_DEVICE: return "ERR_DEVICE: generic device error"; case RESULT_ERR_EOF: return "ERR_EOF: end of input reached"; + case RESULT_ERR_FILENOTFOUND: return "ERR_FILENOTFOUND: file not found or not readable"; + case RESULT_ERR_DUPLICATE: return "ERR_DUPLICATE: duplicate entry"; default: if (resultCode >= 0) return "success"; diff --git a/src/lib/ebus/result.h b/src/lib/ebus/result.h index df1af2d2..1870a5da 100644 --- a/src/lib/ebus/result.h +++ b/src/lib/ebus/result.h @@ -41,6 +41,8 @@ static const int RESULT_ERR_ESC = -9; // invalid escape sequence receiv static const int RESULT_ERR_INVALID_ARG = -10; // invalid argument static const int RESULT_ERR_DEVICE = -11; // generic device error (usually fatal) static const int RESULT_ERR_EOF = -12; // end of input reached +static const int RESULT_ERR_FILENOTFOUND = -13;// file not found or not readable +static const int RESULT_ERR_DUPLICATE = -14; // duplicate entry /** type for result code. */ typedef int result_t; From 922217602bdd8f5b53ce10e4b0b44609bca11fb6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:25:48 +0100 Subject: [PATCH 13/83] added FileReader --- src/lib/ebus/data.cpp | 19 +++++++- src/lib/ebus/data.h | 72 +++++++++++++++++++++++++++++- src/lib/ebus/message.cpp | 17 ++++++- src/lib/ebus/message.h | 5 ++- src/lib/ebus/test/test_message.cpp | 59 +++++------------------- 5 files changed, 120 insertions(+), 52 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 7c1ee862..f619a757 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -69,7 +69,6 @@ static const dataType_t dataTypes[] = { /** the week day names. */ static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; -#define FIELD_SEPARATOR ';' #define VALUE_SEPARATOR ',' #define LENGTH_SEPARATOR ':' #define NULL_VALUE "-" @@ -1048,7 +1047,7 @@ result_t DataFieldTemplates::add(DataField* field, bool replace) map::iterator it = m_fieldsByName.find(name); if (it != m_fieldsByName.end()) { if (replace == false) - return RESULT_ERR_INVALID_ARG; // duplicate key + return RESULT_ERR_DUPLICATE; // duplicate key delete it->second; it->second = field; @@ -1061,6 +1060,21 @@ result_t DataFieldTemplates::add(DataField* field, bool replace) return RESULT_OK; } +result_t DataFieldTemplates::addFromFile(vector& row, void* arg) +{ + DataField* field = NULL; + vector::iterator it = row.begin(); + result_t result = DataField::create(it, row.end(), this, field); + if (result != RESULT_OK) + return result; + + result = add(field); + if (result != RESULT_OK) + delete field; + + return result; +} + DataField* DataFieldTemplates::get(const string name) { map::const_iterator ref = m_fieldsByName.find(name); @@ -1069,3 +1083,4 @@ DataField* DataFieldTemplates::get(const string name) return ref->second; } + diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 874bbe61..8117a9da 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -23,11 +23,16 @@ #include "symbol.h" #include "result.h" #include +#include +#include +#include #include #include using namespace std; +#define FIELD_SEPARATOR ';' + /** the message part in which a data field is stored. */ enum PartType { pt_any, // stored in any data (master or slave) @@ -554,10 +559,73 @@ private: }; +/** + * @brief An abstract class that support reading definitions from a file. + */ +template +class FileReader +{ +public: + + /** + * @brief Constructs a new instance. + */ + FileReader() {} + /** + * @brief Destructor. + */ + virtual ~FileReader() {} + /** + * @brief Reads the definitions from a file. + * @param filename the name (and path) of the file to read. + * @return @a RESULT_OK on success, or an error code. + */ + virtual result_t readFromFile(string filename, T arg=NULL) + { + ifstream ifs; + ifs.open(filename.c_str(), ifstream::in); + if (ifs.is_open() == false) + return RESULT_ERR_FILENOTFOUND; + + string line; + unsigned int lineNo = 0; + vector row; + string token; + while (getline(ifs, line) != 0) { + lineNo++; + // skip empty lines and comments + if (line.length() == 0 || line.substr(0, 1) == "#" || line.substr(0, 2) == "//") + continue; + istringstream isstr(line); + row.clear(); + while (getline(isstr, token, FIELD_SEPARATOR) != 0) + row.push_back(token); + + result_t result = addFromFile(row, arg); + if (result != RESULT_OK) { + cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; + ifs.close(); + return result; + } + } + + ifs.close(); + return RESULT_OK; + } + /** + * @brief Adds a definition that was read from a file. + * @param row the definition row read from the file. + * @return @a RESULT_OK on success, or an error code. + */ + virtual result_t addFromFile(vector& row, T arg) = 0; + +}; + + /** * @brief A map of template @a DataField instances. */ -class DataFieldTemplates +class DataFieldTemplates : public FileReader { public: @@ -581,6 +649,8 @@ public: * Note: the caller may not free the added instance on success. */ result_t add(DataField* message, bool replace=false); + // @copydoc + virtual result_t addFromFile(vector& row, void* arg); /** * @brief Gets the template @a DataField instance with the specified name. * @return the template @a DataField instance, or NULL. diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 60412223..ecdfc467 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -210,7 +210,7 @@ result_t MessageMap::add(Message* message) unsigned long long pkey = message->getKey(); map::iterator keyIt = m_passiveMessagesByKey.find(pkey); if (keyIt != m_passiveMessagesByKey.end()) - return RESULT_ERR_INVALID_ARG; // duplicate key + return RESULT_ERR_DUPLICATE; // duplicate key unsigned char idLength = message->getId().size() - 2; if (idLength > m_maxIdLength) @@ -223,6 +223,21 @@ result_t MessageMap::add(Message* message) return RESULT_OK; } +result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg) +{ + Message* message = NULL; + vector::iterator it = row.begin(); + result_t result = Message::create(it, row.end(), arg, message); + if (result != RESULT_OK) + return result; + + result = add(message); + if (result != RESULT_OK) + delete message; + + return result; +} + Message* MessageMap::find(const string clazz, const string name, const bool isActive, const bool isSet) { string key = clazz; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 195b8664..a373c668 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -176,7 +176,7 @@ private: /** * @brief Holds a map of all known @a Message instances. */ -class MessageMap +class MessageMap : public FileReader { public: @@ -195,6 +195,8 @@ public: * Note: the caller may not free the added instance on success. */ result_t add(Message* message); + // @copydoc + virtual result_t addFromFile(vector& row, DataFieldTemplates* arg); /** * @brief Finds the @a Message instance for the specified class and name. * @param master the master @a SymbolString for identifying the @a Message. @@ -214,6 +216,7 @@ public: */ void clear(); + private: /** the maximum ID length used by any of the known @a Message instances. */ diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 3b7b2410..389d845f 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -66,51 +66,6 @@ void printErrorPos(vector::iterator it, const vector::iterator e cout << setw(cnt) << " " << setw(0) << "^" << endl; } -bool readTemplates(string filename, DataFieldTemplates* templates) -{ - ifstream ifs; - ifs.open(filename.c_str(), ifstream::in); - if (ifs.is_open() == false) { - cerr << "error reading \"" << filename << endl; - return false; - } - - string line; - unsigned int lineNo = 0; - vector row; - string token; - while (getline(ifs, line) != 0) { - lineNo++; - istringstream isstr(line); - row.clear(); - while (getline(isstr, token, ';') != 0) - row.push_back(token); - - // skip empty and commented rows - if (row.empty() == true || row[0][0] == '#') - continue; - - DataField* field = NULL; - vector::iterator it = row.begin(); - result_t result = DataField::create(it, row.end(), templates, field); - if (result != RESULT_OK) { - cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; - printErrorPos(row.begin(), row.end(), it); - } else if (it != row.end()) - cout << "extra data in \"" << filename << "\" line " << static_cast(lineNo) << endl; - else { - result = templates->add(field, true); - if (result != RESULT_OK) { - cerr << "error adding template \"" << field->getName() << "\": " << getResultCode(result) << endl; - delete field; - } - } - } - - ifs.close(); - return true; -} - int main() { // message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields... @@ -124,11 +79,21 @@ int main() {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B50929BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, }; DataFieldTemplates* templates = new DataFieldTemplates(); - readTemplates("_types.csv", templates); + result_t result = templates->readFromFile("_types.csv"); + if (result == RESULT_OK) + cout << "read templates OK" << endl; + else + cout << "read templates error: " << getResultCode(result) << endl; + + MessageMap* messages = new MessageMap(); + result = messages->readFromFile("ehp00.csv", templates); + if (result == RESULT_OK) + cout << "read messages OK" << endl; + else + cout << "read messages error: " << getResultCode(result) << endl; Message *message = NULL; Message* deleteMessage = NULL; - MessageMap* messages = new MessageMap(); for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; istringstream isstr(check[0]); From 1a1d02b4180c98db848a745f5811ab7cdc622ef8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:26:15 +0100 Subject: [PATCH 14/83] fix for uninitialized member --- src/lib/utils/logger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils/logger.h b/src/lib/utils/logger.h index 3cde40c2..ed454fee 100644 --- a/src/lib/utils/logger.h +++ b/src/lib/utils/logger.h @@ -305,7 +305,7 @@ public: private: /** private constructor - singleton pattern */ - Logger() {} + Logger() : m_running(false) {} Logger(const Logger&); Logger& operator=(const Logger&); From 8b3f72211ee436d6d3fe8f6900db5b84d3224661 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:26:51 +0100 Subject: [PATCH 15/83] added message.h/cpp --- src/lib/ebus/Makefile.am | 2 ++ src/lib/ebus/test/Makefile.am | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am index 570375bf..6f67d137 100644 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -12,6 +12,8 @@ libebus_a_SOURCES = result.cpp \ data.h \ port.cpp \ port.h \ + message.cpp \ + message.h \ command.cpp \ command.h \ commands.cpp \ diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am index 55dff9aa..4f76723d 100644 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -6,6 +6,7 @@ AM_CXXFLAGS = -fpic \ noinst_PROGRAMS = test_port \ test_symbol \ test_data \ + test_message \ test_commands \ test_configfile \ test_decode \ @@ -20,6 +21,9 @@ test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_data_SOURCES = test_data.cpp test_data_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a +test_message_SOURCES = test_message.cpp +test_message_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a + test_commands_SOURCES = test_commands.cpp test_commands_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a From eb8fed70a3d8c5e915bbf55ead90a5d36c5cd921 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:52:10 +0100 Subject: [PATCH 16/83] removed unused files --- src/lib/ebus/command.cpp | 338 --------------------------------- src/lib/ebus/command.h | 64 ------- src/lib/ebus/commands.cpp | 260 -------------------------- src/lib/ebus/commands.h | 81 -------- src/lib/ebus/configfile.cpp | 121 ------------ src/lib/ebus/configfile.h | 132 ------------- src/lib/ebus/decode.cpp | 347 ---------------------------------- src/lib/ebus/decode.h | 286 ---------------------------- src/lib/ebus/encode.cpp | 364 ------------------------------------ src/lib/ebus/encode.h | 286 ---------------------------- 10 files changed, 2279 deletions(-) delete mode 100644 src/lib/ebus/command.cpp delete mode 100644 src/lib/ebus/command.h delete mode 100644 src/lib/ebus/commands.cpp delete mode 100644 src/lib/ebus/commands.h delete mode 100644 src/lib/ebus/configfile.cpp delete mode 100644 src/lib/ebus/configfile.h delete mode 100644 src/lib/ebus/decode.cpp delete mode 100644 src/lib/ebus/decode.h delete mode 100644 src/lib/ebus/encode.cpp delete mode 100644 src/lib/ebus/encode.h diff --git a/src/lib/ebus/command.cpp b/src/lib/ebus/command.cpp deleted file mode 100644 index 37fefaf4..00000000 --- a/src/lib/ebus/command.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "command.h" -#include "decode.h" -#include "encode.h" -#include -#include -#include -#include -#include -#include - -string Command::calcData() -{ - // encode - only first entry will be encoded - // ToDo: if more parts are needed, they will be implemented - encode(m_data, m_command[13], m_command[14]); - - if (m_error.length() > 0) - m_result = m_error; - - return m_result; -} - -string Command::calcResult(const cmd_t& cmd) -{ - int elements = strtol(m_command[9].c_str(), NULL, 10); - - if (cmd.size() > 3) { - bool found = false; - - for (size_t i = 3; i < cmd.size(); i++) { - int j; - - for (j = 0; j < elements; j++) { - if (m_command[10 + j*8] == cmd[i]) { - found = true; - break; - } - } - - if (found == true) { - found = false; - - // decode - calcSub(m_command[11 + j*8], m_command[12 + j*8], - m_command[13 + j*8], m_command[14 + j*8]); - } - - } - - } else { - for (int j = 0; j < elements; j++) { - - // decode - calcSub(m_command[11 + j*8], m_command[12 + j*8], - m_command[13 + j*8], m_command[14 + j*8]); - } - } - - if (m_error.length() > 0) - m_result = m_error; - - return m_result; -} - -void Command::calcSub(const string& part, const string& position, - const string& type, const string& factor) -{ - string data; - - // Master Data - if (strcasecmp(part.c_str(), "MD") == 0) { - // QQ ZZ PB SB NN - int md_pos = 10; - int md_len = strtol(m_command[7].c_str(), NULL, 10)*2; - data = m_data.substr(md_pos, md_len); - } - - // Slave Acknowledge - else if (strcasecmp(part.c_str(), "SA") == 0) { - // QQ ZZ PB SB NN + Dx + CRC - int sa_pos = 10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 2; - int sa_len = 2; - data = m_data.substr(sa_pos, sa_len); - } - - // Slave Data - else if (strcasecmp(part.c_str(), "SD") == 0) { - // QQ ZZ PB SB NN + Dx + CRC ACK NN - int sd_pos = 10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 6; - int sd_len = m_data.length() - (10 + (strtol(m_command[7].c_str(), NULL, 10)*2) + 6) - 4; - data = m_data.substr(sd_pos, sd_len); - } - - // Master Acknowledge - else if (strcasecmp(part.c_str(), "MA") == 0) { - // QQ ZZ PB SB NN + Dx + CRC ACK NN + Dx - int ma_pos = m_data.length() - 2; - int ma_len = 2; - data = m_data.substr(ma_pos, ma_len); - } - - decode(data, position, type, factor); -} - -void Command::decode(const string& data, const string& position, - const string& type, const string& factor) -{ - ostringstream result, value; - Decode* help = NULL; - - // prepare position - string token; - istringstream stream(position); - vector pos; - - while (getline(stream, token, ',') != 0) - pos.push_back(strtol(token.c_str(), NULL, 10)); - - if (strcasecmp(type.c_str(), "HEX") == 0) { - if (pos.size() <= 1 || pos[1] < pos[0]) - pos[1] = pos[0]; - - value << data.substr((pos[0]-1)*2, (pos[1]-pos[0]+1)*2); - help = new DecodeHEX(value.str()); - } - else if (strcasecmp(type.c_str(), "UCH") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeUCH(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "SCH") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeSCH(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "UIN") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2); - help = new DecodeUIN(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "SIN") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2); - help = new DecodeSIN(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "ULG") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2) << data.substr((pos[3]-1)*2, 2); - help = new DecodeULG(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "SLG") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2) << data.substr((pos[3]-1)*2, 2); - help = new DecodeSLG(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "FLT") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2); - help = new DecodeFLT(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "STR") == 0) { - if (pos.size() <= 1 || pos[1] < pos[0]) - pos[1] = pos[0]; - - value << data.substr((pos[0]-1)*2, (pos[1]-pos[0]+1)*2); - help = new DecodeSTR(value.str()); - } - else if (strcasecmp(type.c_str(), "BCD") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeBCD(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "D1B") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeD1B(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "D1C") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeD1C(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "D2B") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2); - help = new DecodeD2B(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "D2C") == 0) { - value << data.substr((pos[0]-1)*2, 2) << data.substr((pos[1]-1)*2, 2); - help = new DecodeD2C(value.str(), factor); - } - else if (strcasecmp(type.c_str(), "BDA") == 0) { - value << data.substr((pos[0]-1)*2, 2) - << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2); - help = new DecodeBDA(value.str()); - } - else if (strcasecmp(type.c_str(), "HDA") == 0) { - value << data.substr((pos[0]-1)*2, 2) - << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2); - help = new DecodeHDA(value.str()); - } - else if (strcasecmp(type.c_str(), "BTI") == 0) { - value << data.substr((pos[0]-1)*2, 2) - << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2); - help = new DecodeBTI(value.str()); - } - else if (strcasecmp(type.c_str(), "HTI") == 0) { - value << data.substr((pos[0]-1)*2, 2) - << data.substr((pos[1]-1)*2, 2) - << data.substr((pos[2]-1)*2, 2); - help = new DecodeHTI(value.str()); - } - else if (strcasecmp(type.c_str(), "BDY") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeBDY(value.str()); - } - else if (strcasecmp(type.c_str(), "HDY") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeHDY(value.str()); - } - else if (strcasecmp(type.c_str(), "TTM") == 0) { - value << data.substr((pos[0]-1)*2, 2); - help = new DecodeTTM(value.str()); - } - - if (help == NULL) { - result << "type '" << type.c_str() << "' not implemented!"; - m_error = result.str(); - } else { - result << help->decode(); - - if (m_result.length() > 0) - m_result += " "; - - m_result += result.str(); - } - - delete help; -} - -void Command::encode(const string& data, const string& type, - const string& factor) -{ - ostringstream result; - Encode* help = NULL; - - if (strcasecmp(type.c_str(), "HEX") == 0) { - help = new EncodeHEX(data); - } - else if (strcasecmp(type.c_str(), "UCH") == 0) { - help = new EncodeUCH(data, factor); - } - else if (strcasecmp(type.c_str(), "SCH") == 0) { - help = new EncodeSCH(data, factor); - } - else if (strcasecmp(type.c_str(), "UIN") == 0) { - help = new EncodeUIN(data, factor); - } - else if (strcasecmp(type.c_str(), "SIN") == 0) { - help = new EncodeSIN(data, factor); - } - else if (strcasecmp(type.c_str(), "ULG") == 0) { - help = new EncodeULG(data, factor); - } - else if (strcasecmp(type.c_str(), "SLG") == 0) { - help = new EncodeSLG(data, factor); - } - else if (strcasecmp(type.c_str(), "FLT") == 0) { - help = new EncodeSLG(data, factor); - } - else if (strcasecmp(type.c_str(), "STR") == 0) { - help = new EncodeSTR(data); - } - else if (strcasecmp(type.c_str(), "BCD") == 0) { - help = new EncodeBCD(data, factor); - } - else if (strcasecmp(type.c_str(), "D1B") == 0) { - help = new EncodeD1B(data, factor); - } - else if (strcasecmp(type.c_str(), "D1C") == 0) { - help = new EncodeD1C(data, factor); - } - else if (strcasecmp(type.c_str(), "D2B") == 0) { - help = new EncodeD2B(data, factor); - } - else if (strcasecmp(type.c_str(), "D2C") == 0) { - help = new EncodeD2C(data, factor); - } - else if (strcasecmp(type.c_str(), "BDA") == 0) { - help = new EncodeBDA(data); - } - else if (strcasecmp(type.c_str(), "HDA") == 0) { - help = new EncodeHDA(data); - } - else if (strcasecmp(type.c_str(), "BTI") == 0) { - help = new EncodeBTI(data); - } - else if (strcasecmp(type.c_str(), "HTI") == 0) { - help = new EncodeHTI(data); - } - else if (strcasecmp(type.c_str(), "BDY") == 0) { - help = new EncodeBDY(data); - } - else if (strcasecmp(type.c_str(), "HDY") == 0) { - help = new EncodeHDY(data); - } - else if (strcasecmp(type.c_str(), "TTM") == 0) { - help = new EncodeTTM(data); - } - - if (help == NULL) { - result << "type '" << type.c_str() << "' not implemented!"; - m_error = result.str(); - } else { - result << help->encode(); - - if (m_result.length() > 0) - m_result += " "; - - m_result += result.str(); - } - - delete help; -} - diff --git a/src/lib/ebus/command.h b/src/lib/ebus/command.h deleted file mode 100644 index b90a374a..00000000 --- a/src/lib/ebus/command.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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_COMMAND_H_ -#define LIBEBUS_COMMAND_H_ - -#include -#include - -using namespace std; - -typedef vector cmd_t; -typedef cmd_t::const_iterator cmdCI_t; - -class Command -{ - -public: - Command(int index, cmd_t command) : m_index(index), m_command(command) {} - Command(int index, cmd_t command, string data) - : m_index(index), m_command(command), m_data(data) {} - - cmd_t getCommand() const { return m_command; } - void setData(const string& data) { m_data = data; } - string getData() const { return m_data; } - string calcData(); - - string calcResult(const cmd_t& cmd); - -private: - int m_index; - cmd_t m_command; - string m_data; - string m_result; - string m_error; - - void calcSub(const string& part, const string& position, - const string& type, const string& factor); - - void decode(const string& data, const string& position, - const string& type, const string& factor); - - void encode(const string& data, const string& type, - const string& factor); - -}; - -#endif // LIBEBUS_COMMAND_H_ diff --git a/src/lib/ebus/commands.cpp b/src/lib/ebus/commands.cpp deleted file mode 100644 index 3f781799..00000000 --- a/src/lib/ebus/commands.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "commands.h" -#include -#include -#include -#include -#include -#include - -using namespace std; - -Commands::~Commands() -{ - for (mapCI_t iter = m_pollDB.begin(); iter != m_pollDB.end(); ++iter) - delete iter->second; - - m_pollDB.clear(); - - for (mapCI_t iter = m_cycDB.begin(); iter != m_cycDB.end(); ++iter) - delete iter->second; - - m_cycDB.clear(); - - m_cmdDB.clear(); -} - -void Commands::addCommand(const cmd_t& command) -{ - m_cmdDB.push_back(command); - - if (strcasecmp(command[0].c_str(),"C") == 0) { - Command* cmd = new Command(m_cmdDB.size()-1, command); - m_cycDB.insert(pair_t(m_cmdDB.size()-1, cmd)); - } - - if (strcasecmp(command[0].c_str(),"P") == 0) { - Command* cmd = new Command(m_cmdDB.size()-1, command); - m_pollDB.insert(pair_t(m_cmdDB.size()-1, cmd)); - } -} - -void Commands::printCommands() const -{ - if (m_cmdDB.size() == 0) - return; - - for (cmdDBCI_t i = m_cmdDB.begin(); i != m_cmdDB.end(); i++) { - printCommand(*i); - cout << endl; - } -} - -int Commands::findCommand(const string& data) const -{ - // no commands definend - if (m_cmdDB.size() == 0) - return -2; - - // preapre string for searching command - string token; - istringstream isstr(data); - vector cmd; - - // split stream - while (getline(isstr, token, ' ') != 0) - cmd.push_back(token); - - size_t index; - cmdDBCI_t i = m_cmdDB.begin(); - - // walk through commands - GET - if (strcasecmp(cmd[0].c_str(), "GET") == 0) { - for (index = 0; i != m_cmdDB.end(); i++, index++) { - - // empty line - if ((*i).size() == 0) - continue; - - if (((strcasecmp((*i)[0].c_str(), "R") == 0) - || (strcasecmp((*i)[0].c_str(), "P") == 0)) - && (strcasecmp((*i)[1].c_str(), cmd[1].c_str()) == 0) - && (strcasecmp((*i)[2].c_str(), cmd[2].c_str()) == 0)) - return index; - } - // walk through commands - SET, CYC - } else { - // correct type - if (strcasecmp(cmd[0].c_str(), "SET") == 0) - cmd[0] = "W"; - else if (strcasecmp(cmd[0].c_str(), "CYC") == 0) - cmd[0] = "C"; - - for (index = 0; i != m_cmdDB.end(); i++, index++) { - - // empty line - if ((*i).size() == 0) - continue; - - if (strcasecmp((*i)[0].c_str(), cmd[0].c_str()) == 0 && - strcasecmp((*i)[1].c_str(), cmd[1].c_str()) == 0 && - strcasecmp((*i)[2].c_str(), cmd[2].c_str()) == 0) - return index; - } - } - - // command not found - return -1; -} - -string Commands::getBusCommand(const int index) const -{ - cmd_t command = m_cmdDB.at(index); - string cmd; - stringstream sstr; - - if (strcasecmp(command[0].c_str(), "C") == 0) - cmd += command[4]; // QQ - - cmd += command[5]; // ZZ - cmd += command[6]; // PBSB - sstr << setw(2) << hex << setfill('0') << command[7]; - cmd += sstr.str(); // NN - cmd += command[8]; // Dx - - return cmd; -} - -int Commands::storeCycData(const string& data) const -{ - // no commands defined - if (m_cycDB.size() == 0) - return -2; - - // search skipped - string too short - if (data.length() < 10) - return -3; - - // prepare string for searching command - string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2)); - - mapCI_t iter = m_cycDB.begin(); - - // walk through commands - for (; iter != m_cycDB.end(); iter++) { - - string command = getBusCommand(iter->first); - - // skip wrong search string length - if (command.length() > search.length()) - continue; - - if (strcasecmp(command.c_str(), search.substr(0,command.length()).c_str()) == 0) { - iter->second->setData(data); - return iter->first; - } - } - - // command not found - return -1; -} - -string Commands::getCycData(int index) const -{ - mapCI_t iter = m_cycDB.find(index); - if (iter != m_cycDB.end()) - return iter->second->getData(); - else - return ""; -} - -int Commands::nextPollCommand() -{ - size_t index = 0; - - m_pollIndex++; - - if (m_pollIndex == m_pollDB.size()) - m_pollIndex = 0; - - mapCI_t iter = m_pollDB.begin(); - - for (; iter != m_pollDB.end(); iter++, index++) - if (index == m_pollIndex) - return iter->first; - - return -1; -} - -void Commands::storePollData(const string& data) const -{ - // prepare string for searching command - string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2)); - - mapCI_t iter = m_pollDB.begin(); - - // walk through commands - for (; iter != m_pollDB.end(); iter++) { - - string command = getBusCommand(iter->first); - - // skip wrong search string length - if (command.length() > search.length()) - continue; - - if (strcasecmp(command.c_str(), search.substr(0,command.length()).c_str()) == 0) - iter->second->setData(data); - - } -} - -string Commands::getPollData(const int index) const -{ - mapCI_t iter = m_pollDB.find(index); - if (iter != m_pollDB.end()) - return iter->second->getData(); - else - return ""; -} - -void Commands::storeScanData(const string& data) -{ - vector::const_iterator iter = m_scanDB.begin(); - bool found = false; - - // walk through scan data - for (; iter != m_scanDB.end(); iter++) - if (data == (*iter)) - found = true; - - if (found == false) - m_scanDB.push_back(data); -} - -void Commands::printCommand(const cmd_t& command) const -{ - if (command.size() == 0) - return; - - for (cmdCI_t i = command.begin(); i != command.end(); i++) - cout << *i << ';'; -} - diff --git a/src/lib/ebus/commands.h b/src/lib/ebus/commands.h deleted file mode 100644 index a696a955..00000000 --- a/src/lib/ebus/commands.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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_COMMANDS_H_ -#define LIBEBUS_COMMANDS_H_ - -#include "command.h" -#include -#include -#include - -using namespace std; - -typedef vector cmdDB_t; -typedef cmdDB_t::const_iterator cmdDBCI_t; - -typedef map map_t; -typedef map_t::const_iterator mapCI_t; -typedef pair pair_t; - -class Commands -{ - -public: - Commands() : m_pollIndex(-1) {} - ~Commands(); - - void addCommand(const cmd_t& command); - void printCommands() const; - - size_t sizeCmdDB() const { return m_cmdDB.size(); } - size_t sizeCycDB() const { return m_cycDB.size(); } - size_t sizePollDB() const { return m_pollDB.size(); } - size_t sizeScanDB() const { return m_scanDB.size(); } - - cmd_t const& operator[](const size_t& index) const { return m_cmdDB[index]; } - - int findCommand(const string& data) const; - - string getCmdType(const int index) const { return string(m_cmdDB.at(index)[0]); } - string getBusCommand(const int index) const; - - int storeCycData(const string& data) const; - string getCycData(int index) const; - - int nextPollCommand(); - void storePollData(const string& data) const; - string getPollData(const int index) const; - - void storeScanData(const string& data); - string getScanData(const int index) const { return m_scanDB[index]; } - -private: - cmdDB_t m_cmdDB; - map_t m_cycDB; - map_t m_pollDB; - size_t m_pollIndex; - vector m_scanDB; - - void printCommand(const cmd_t& command) const; - -}; - -#endif // LIBEBUS_COMMANDS_H_ - diff --git a/src/lib/ebus/configfile.cpp b/src/lib/ebus/configfile.cpp deleted file mode 100644 index 11019af0..00000000 --- a/src/lib/ebus/configfile.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "configfile.h" -#include -#include -#include - -using namespace std; - -void ConfigFileCSV::parse(istream& is, Commands& commands) -{ - string line; - - // read lines - while (getline(is, line) != 0) { - cmd_t row; - string column; - - istringstream isstr(line); - - // walk through columns - while (getline(isstr, column, ';') != 0) - row.push_back(column); - - // skip empty and commented rows - if (row.empty() == true || row[0][0] == '#') - continue; - - commands.addCommand(row); - } -}; - - -ConfigCommands::ConfigCommands(const string path, const FileType type) -{ - m_path = path; - m_configfile = NULL; - setType(type); - addFiles(m_path, m_extension); -} - -void ConfigCommands::setType(const FileType type) -{ - if (m_configfile != NULL) - delete m_configfile; - - switch (type) { - case ft_csv: - m_configfile = new ConfigFileCSV(); - m_extension = "csv"; - break; - }; -}; - -Commands* ConfigCommands::getCommands() -{ - Commands* commands = new Commands(); - vector::const_iterator i = m_files.begin(); - - for(; i != m_files.end(); i++) { - fstream file((*i).c_str(), ios::in); - - if(file.is_open() == true) { - m_configfile->parse(file, *commands); - file.close(); - } - } - return commands; -}; - -void ConfigCommands::addFiles(const string path, const string extension) -{ - DIR* dir = opendir(path.c_str()); - - if (dir == NULL) - return; - - dirent* d = readdir(dir); - - while (d != NULL) { - - if (d->d_type == DT_DIR) { - string fn = d->d_name; - - if (fn != "." && fn != "..") { - const string p = path + "/" + d->d_name; - addFiles(p, extension); - } - - } else if (d->d_type == DT_REG) { - string fn = d->d_name; - - if (fn.find(extension, (fn.length() - extension.length())) != string::npos) { - const string p = path + "/" + d->d_name; - m_files.push_back(p); - } - } - - d = readdir(dir); - } - - closedir(dir); -}; - diff --git a/src/lib/ebus/configfile.h b/src/lib/ebus/configfile.h deleted file mode 100644 index f6f37563..00000000 --- a/src/lib/ebus/configfile.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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_CONFIGFILE_H_ -#define LIBEBUS_CONFIGFILE_H_ - -#include "commands.h" -#include -#include - -using namespace std; - -/** \file configfile.h */ - -/** available file endings / types. */ -enum FileType { - ft_csv /*!< CSV */ -}; - -/** - * @brief base class for config files. - */ -class ConfigFile -{ - -public: - /** - * @brief destructor. - */ - virtual ~ConfigFile() {} - - /** - * @brief read input stream and stored data into commands - * @param is open input stream for reading. - * @param commands object as datastore. - */ - virtual void parse(istream& is, Commands& commands) = 0; - -}; - -/** - * @brief derived class for CSV config files. - */ -class ConfigFileCSV : public ConfigFile -{ - -public: - /** - * @brief destructor. - */ - ~ConfigFileCSV() {} - - /** - * @brief read input stream and stored data into commands - * @param is open input stream for reading. - * @param commands object as datastore. - */ - void parse(istream& is, Commands& commands); - -}; - -/** - * @brief class to parse configuration files and store into commands instance. - */ -class ConfigCommands -{ - -public: - /** - * @brief set file type and add recursive files from given path. - * @param path to configuration files. - * @param type to parse. - */ - ConfigCommands(const string path, const FileType type); - - /** - * @brief destructor. - */ - ~ConfigCommands() { delete m_configfile; } - - /** - * @brief setter for file type. - * @param type of files. - */ - void setType(const FileType type); - - /** - * @brief parse files for commands and store them into commands instance. - * @return a commands instance - */ - Commands* getCommands(); - -private: - /** the configfile instance */ - ConfigFile* m_configfile; - - /** main path for configuration files */ - string m_path; - - /** valid file extension */ - string m_extension; - - /** vector of configuration files */ - vector m_files; - - /** - * @brief parse path for given file extension. - * @param path to configuration files. - * @param extension with file type. - */ - void addFiles(const string path, const string extension); - -}; - -#endif // LIBEBUS_CONFIGFILE_H_ - diff --git a/src/lib/ebus/decode.cpp b/src/lib/ebus/decode.cpp deleted file mode 100644 index b86bed97..00000000 --- a/src/lib/ebus/decode.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "decode.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -Decode::Decode(const string& data, const string& factor) - : m_data(data) -{ - if ((factor.find_first_not_of("0123456789.") == string::npos) == true) - m_factor = static_cast(strtod(factor.c_str(), NULL)); - else - m_factor = 1.0; -} - - -string DecodeHEX::decode() -{ - ostringstream result; - - for (size_t i = 0; i < m_data.length()/2; i++) - result << m_data.substr(i*2, 2) << " "; - - return result.str().substr(0, result.str().length()-1); -} - -string DecodeUCH::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned short x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed << static_cast(x * m_factor); - - return result.str(); -} - -string DecodeSCH::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned short x; - ss >> x; - - ostringstream result; - if ((x & 0x80) == 0x80) - result << setprecision(3) << fixed - << static_cast(static_cast(- ( ((unsigned char) (~ x)) + 1) ) * m_factor); - else - result << setprecision(3) << fixed - << static_cast(static_cast(x) * m_factor); - - return result.str(); -} - -string DecodeUIN::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned short x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed << static_cast(x * m_factor); - - return result.str(); -} - -string DecodeSIN::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned short x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed << static_cast(static_cast(x) * m_factor); - - return result.str(); -} - -string DecodeULG::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned int x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed << static_cast(x * m_factor); - - return result.str(); -} - -string DecodeSLG::decode() -{ - stringstream ss; - ss << hex << m_data; - - unsigned int x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed <(static_cast(x) * m_factor); - - return result.str(); -} - -string DecodeFLT::decode() -{ - stringstream ss; - ss << hex << m_data; - - short x; - ss >> x; - - ostringstream result; - result << setprecision(3) << fixed << static_cast(x / 1000.0 * m_factor); - - return result.str(); -} - -string DecodeSTR::decode() -{ - ostringstream result; - - for (size_t i = 0; i <= m_data.length()/2; i++) { - char tmp = static_cast(strtol(m_data.substr(i*2, 2).c_str(), NULL, 16)); - if (tmp == 0x00) tmp = 0x20; - result << tmp; - } - - return result.str().substr(0, result.str().length()-1); -} - -string DecodeBCD::decode() -{ - ostringstream result; - unsigned char src = strtol(m_data.c_str(), NULL, 16); - - if ((src & 0x0F) > 0x09 || ((src >> 4) & 0x0F) > 0x09) - result << static_cast(0xFF); - else - result << static_cast(( ( ((src & 0xF0) >> 4) * 10) + (src & 0x0F) ) * m_factor); - - return result.str(); -} - -string DecodeD1B::decode() -{ - ostringstream result; - unsigned char src = strtol(m_data.c_str(), NULL, 16); - - if ((src & 0x80) == 0x80) - result << static_cast((- ( ((unsigned char) (~ src)) + 1) ) * m_factor); - else - result << static_cast(src * m_factor); - - return result.str(); -} - -string DecodeD1C::decode() -{ - ostringstream result; - unsigned char src = strtol(m_data.c_str(), NULL, 16); - - if (src > 0xC8) - result << static_cast(0xFF); - else - result << static_cast((src / 2.0) * m_factor); - - return result.str(); -} - -string DecodeD2B::decode() -{ - ostringstream result; - unsigned char src_lsb = static_cast(strtol(m_data.substr(0, 2).c_str(), NULL, 16)); - unsigned char src_msb = static_cast(strtol(m_data.substr(2, 2).c_str(), NULL, 16)); - - if ((src_msb & 0x80) == 0x80) - result << static_cast - ((- ( ((unsigned char) (~ src_msb)) + - ( ( ((unsigned char) (~ src_lsb)) + 1) / 256.0) ) ) * m_factor); - - else - result << static_cast((src_msb + (src_lsb / 256.0)) * m_factor); - - return result.str(); -} - -string DecodeD2C::decode() -{ - ostringstream result; - unsigned char src_lsb = static_cast(strtol(m_data.substr(0, 2).c_str(), NULL, 16)); - unsigned char src_msb = static_cast(strtol(m_data.substr(2, 2).c_str(), NULL, 16)); - - if ((src_msb & 0x80) == 0x80) - result << static_cast - ((- ( ( ( ((unsigned char) (~ src_msb)) * 16.0) ) + - ( ( ((unsigned char) (~ src_lsb)) & 0xF0) >> 4) + - ( ( ( ((unsigned char) (~ src_lsb)) & 0x0F) +1 ) / 16.0) ) ) * m_factor); - - else - result << static_cast(( (src_msb * 16.0) + ((src_lsb & 0xF0) >> 4) + - ((src_lsb & 0x0F) / 16.0) ) * m_factor); - - return result.str(); -} - -string DecodeBDA::decode() -{ - ostringstream result; - Decode* decode; - short array[3]; - for (int i = 0; i < 3; i++) { - decode = new DecodeBCD(m_data.substr(i*2, 2), "1.0"); - array[i] = static_cast(strtol(decode->decode().c_str(), NULL, 10)); - delete decode; - } - - result << setw(2) << setfill('0') << array[0] << "." - << setw(2) << setfill('0') << array[1] << "." - << array[2] + 2000; - - return result.str(); -} - -string DecodeHDA::decode() -{ - ostringstream result; - short dd = static_cast(strtol(m_data.substr(0, 2).c_str(), NULL, 16)); - short mm = static_cast(strtol(m_data.substr(2, 2).c_str(), NULL, 16)); - short yy = static_cast(strtol(m_data.substr(4, 2).c_str(), NULL, 16)); - - result << setw(2) << setfill('0') << dd << "." - << setw(2) << setfill('0') << mm << "." - << yy + 2000; - - return result.str(); -} - -string DecodeBTI::decode() -{ - ostringstream result; - Decode* decode; - short array[3]; - for (int i = 0; i < 3; i++) { - decode = new DecodeBCD(m_data.substr(i*2, 2), "1.0"); - array[i] = static_cast(strtol(decode->decode().c_str(), NULL, 10)); - delete decode; - } - - result << setw(2) << setfill('0') << array[0] << ":" - << setw(2) << setfill('0') << array[1] << ":" - << setw(2) << setfill('0') << array[2]; - - return result.str(); -} - -string DecodeHTI::decode() -{ - ostringstream result; - short hh = static_cast(strtol(m_data.substr(0, 2).c_str(), NULL, 16)); - short mm = static_cast(strtol(m_data.substr(2, 2).c_str(), NULL, 16)); - short ss = static_cast(strtol(m_data.substr(4, 2).c_str(), NULL, 16)); - - result << setw(2) << setfill('0') << hh << ":" - << setw(2) << setfill('0') << mm << ":" - << setw(2) << setfill('0') << ss; - - return result.str(); -} - -string DecodeBDY::decode() -{ - const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"}; - - ostringstream result; - short day = static_cast(strtol(m_data.c_str(), NULL, 16)); - - if (day < 0 || day > 6) - day = 7; - - result << days[day]; - - return result.str(); -} - -string DecodeHDY::decode() -{ - const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"}; - - ostringstream result; - short day = static_cast(strtol(m_data.c_str(), NULL, 16)) - 1; - - if (day < 0 || day > 6) - day = 7; - - result << days[day]; - - return result.str(); -} - -string DecodeTTM::decode() -{ - ostringstream result; - short hh = static_cast(strtol(m_data.c_str(), NULL, 16)) / 6; - short mm = static_cast(strtol(m_data.c_str(), NULL, 16)) % 6 * 10; - - result << setw(2) << setfill('0') << hh << ":" - << setw(2) << setfill('0') << mm; - - return result.str(); -} - diff --git a/src/lib/ebus/decode.h b/src/lib/ebus/decode.h deleted file mode 100644 index 73c8d2a4..00000000 --- a/src/lib/ebus/decode.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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_DECODE_H_ -#define LIBEBUS_DECODE_H_ - -#include - -using namespace std; - -class Decode -{ - -public: - Decode(const string& data, const string& factor = ""); - virtual ~Decode() {} - - virtual string decode() = 0; - -protected: - string m_data; - float m_factor; - -}; - - -class DecodeHEX : public Decode -{ - -public: - DecodeHEX(const string& data) : Decode(data) {} - ~DecodeHEX() {} - - string decode(); - -}; - -class DecodeUCH : public Decode -{ - -public: - DecodeUCH(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeUCH() {} - - string decode(); - -}; - -class DecodeSCH : public Decode -{ - -public: - DecodeSCH(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeSCH() {} - - string decode(); - -}; - -class DecodeUIN : public Decode -{ - -public: - DecodeUIN(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeUIN() {} - - string decode(); - -}; - -class DecodeSIN : public Decode -{ - -public: - DecodeSIN(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeSIN() {} - - string decode(); - -}; - -class DecodeULG : public Decode -{ - -public: - DecodeULG(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeULG() {} - - string decode(); - -}; - -class DecodeSLG : public Decode -{ - -public: - DecodeSLG(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeSLG() {} - - string decode(); - -}; - -class DecodeFLT : public Decode -{ - -public: - DecodeFLT(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeFLT() {} - - string decode(); - -}; - -class DecodeSTR : public Decode -{ - -public: - DecodeSTR(string data) : Decode(data) {} - ~DecodeSTR() {} - - string decode(); - -}; - -class DecodeBCD : public Decode -{ - -public: - DecodeBCD(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeBCD() {} - - string decode(); - -}; - -class DecodeD1B : public Decode -{ - -public: - DecodeD1B(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeD1B() {} - - string decode(); - -}; - -class DecodeD1C : public Decode -{ - -public: - DecodeD1C(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeD1C() {} - - string decode(); - -}; - -class DecodeD2B : public Decode -{ - -public: - DecodeD2B(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeD2B() {} - - string decode(); - -}; - -class DecodeD2C : public Decode -{ - -public: - DecodeD2C(const string& data, const string& factor) - : Decode(data, factor) {} - ~DecodeD2C() {} - - string decode(); - -}; - -class DecodeBDA : public Decode -{ - -public: - DecodeBDA(const string& data) : Decode(data) {} - ~DecodeBDA() {} - - string decode(); - -}; - -class DecodeHDA : public Decode -{ - -public: - DecodeHDA(const string& data) : Decode(data) {} - ~DecodeHDA() {} - - string decode(); - -}; - -class DecodeBTI : public Decode -{ - -public: - DecodeBTI(const string& data) : Decode(data) {} - ~DecodeBTI() {} - - string decode(); - -}; - -class DecodeHTI : public Decode -{ - -public: - DecodeHTI(const string& data) : Decode(data) {} - ~DecodeHTI() {} - - string decode(); - -}; - -class DecodeBDY : public Decode -{ - -public: - DecodeBDY(const string& data) : Decode(data) {} - ~DecodeBDY() {} - - string decode(); - -}; - -class DecodeHDY : public Decode -{ - -public: - DecodeHDY(const string& data) : Decode(data) {} - ~DecodeHDY() {} - - string decode(); - -}; - -class DecodeTTM : public Decode -{ - -public: - DecodeTTM(const string& data) : Decode(data) {} - ~DecodeTTM() {} - - string decode(); - -}; - -#endif // LIBEBUS_DECODE_H_ diff --git a/src/lib/ebus/encode.cpp b/src/lib/ebus/encode.cpp deleted file mode 100644 index 42b58dc2..00000000 --- a/src/lib/ebus/encode.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "encode.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -Encode::Encode(const string& data, const string& factor) - : m_data(data) -{ - if ((factor.find_first_not_of("0123456789.") == string::npos) == true) - m_factor = static_cast(strtod(factor.c_str(), NULL)); - else - m_factor = 1.0; -} - - -string EncodeHEX::encode() -{ - m_data.erase(remove_if(m_data.begin(), m_data.end(), ::isspace), m_data.end()); - - return m_data; -} - -string EncodeUCH::encode() -{ - ostringstream result; - unsigned short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - result << setw(2) << hex << setfill('0') << src; - - return result.str().substr(result.str().length()-2,2); -} - -string EncodeSCH::encode() -{ - ostringstream result; - short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src < -127 || src > 127) - result << setw(2) << hex << setfill('0') - << static_cast(0x80); - else - result << setw(2) << hex << setfill('0') - << static_cast(src); - - return result.str().substr(result.str().length()-2,2); -} - -string EncodeUIN::encode() -{ - ostringstream result; - unsigned short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - result << setw(4) << hex << setfill('0') << src; - - return result.str().substr(2,2) + result.str().substr(0,2); -} - -string EncodeSIN::encode() -{ - ostringstream result; - short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - result << setw(4) << hex << setfill('0') << src; - - return result.str().substr(2,2) + result.str().substr(0,2); -} - -string EncodeULG::encode() -{ - ostringstream result; - unsigned long src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - result << setw(8) << hex << setfill('0') << src; - - return result.str().substr(6,2) + result.str().substr(4,2) + - result.str().substr(2,2) + result.str().substr(0,2); -} - -string EncodeSLG::encode() -{ - ostringstream result; - int src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - result << setw(8) << hex << setfill('0') << src; - - return result.str().substr(6,2) + result.str().substr(4,2) + - result.str().substr(2,2) + result.str().substr(0,2); -} - -string EncodeFLT::encode() -{ - ostringstream result; - short src = static_cast(strtod(m_data.c_str(), NULL) * 1000.0 / m_factor); - result << setw(4) << hex << setfill('0') << src; - - return result.str().substr(2,2) + result.str().substr(0,2); -} - -string EncodeSTR::encode() -{ - ostringstream result; - - for (size_t i = 0; i < m_data.length(); i++) - result << setw(2) << hex << setfill('0') << static_cast(m_data[i]); - - return result.str(); -} - -string EncodeBCD::encode() -{ - ostringstream result; - short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src > 99) - result << setw(2) << hex << setfill('0') - << static_cast(0xFF); - else - result << setw(2) << hex << setfill('0') - << static_cast( ((src / 10) << 4) | (src % 10) ); - - return result.str().substr(result.str().length()-2,2); -} - -string EncodeD1B::encode() -{ - ostringstream result; - short src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src < -127 || src > 127) - result << setw(2) << hex << setfill('0') - << static_cast(0x80); - else - result << setw(2) << hex << setfill('0') - << static_cast(src); - - return result.str().substr(result.str().length()-2,2); -} - -string EncodeD1C::encode() -{ - ostringstream result; - float src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src < 0.0 || src > 100.0) - result << setw(2) << hex << setfill('0') - << static_cast(0xFF); - else - result << setw(2) << hex << setfill('0') - << static_cast(src * 2.0); - - return result.str(); -} - -string EncodeD2B::encode() -{ - ostringstream result; - float src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src < -127.999 || src > 127.999) { - result << setw(2) << hex << setfill('0') - << static_cast(0x80) - << setw(2) << hex << setfill('0') - << static_cast(0x00); - } else { - unsigned char tgt_lsb = static_cast((src - ((short) src)) * 256.0); - unsigned char tgt_msb; - - if (src < 0.0 && tgt_lsb != 0x00) - tgt_msb = static_cast((short) src - 1); - else - tgt_msb = static_cast((short) src); - - result << setw(2) << hex << setfill('0') - << static_cast(tgt_msb) - << setw(2) << hex << setfill('0') - << static_cast(tgt_lsb); - } - - return result.str(); -} - -string EncodeD2C::encode() -{ - ostringstream result; - float src = static_cast(strtod(m_data.c_str(), NULL) / m_factor); - - if (src < -2047.999 || src > 2047.999) { - result << setw(2) << hex << setfill('0') - << static_cast(0x80) - << setw(2) << hex << setfill('0') - << static_cast(0x00); - } else { - unsigned char tgt_lsb = static_cast( - ((unsigned char) ( ((short) src) % 16) << 4) + - ((unsigned char) ( (src - ((short) src)) * 16.0)) ); - - unsigned char tgt_msb; - - if (src < 0.0 && tgt_lsb != 0x00) - tgt_msb = static_cast((short) (src / 16.0) - 1); - else - tgt_msb = static_cast((short) src / 16.0); - - result << setw(2) << hex << setfill('0') - << static_cast(tgt_msb) - << setw(2) << hex << setfill('0') - << static_cast(tgt_lsb); - } - - return result.str(); -} - -string EncodeBDA::encode() -{ - // prepare data - string token; - istringstream stream(m_data); - vector data; - - while (getline(stream, token, '.') != 0) - data.push_back(token); - - ostringstream result; - result << setw(2) << dec << setfill('0') - << static_cast(strtod(data[0].c_str(), NULL)) - << setw(2) << dec << setfill('0') - << static_cast(strtod(data[1].c_str(), NULL)) - << setw(2) << dec << setfill('0') - << static_cast(strtod(data[2].c_str(), NULL) - 2000); - - return result.str(); -} - -string EncodeHDA::encode() -{ - // prepare data - string token; - istringstream stream(m_data); - vector data; - - while (getline(stream, token, '.') != 0) - data.push_back(token); - - ostringstream result; - result << setw(2) << hex << setfill('0') - << static_cast(strtod(data[0].c_str(), NULL)) - << setw(2) << hex << setfill('0') - << static_cast(strtod(data[1].c_str(), NULL)) - << setw(2) << hex << setfill('0') - << static_cast(strtod(data[2].c_str(), NULL) - 2000); - - return result.str(); -} - -string EncodeBTI::encode() -{ - // prepare data - string token; - istringstream stream(m_data); - vector data; - - while (getline(stream, token, ':') != 0) - data.push_back(token); - - ostringstream result; - result << setw(2) << dec << setfill('0') - << static_cast(strtod(data[0].c_str(), NULL)) - << setw(2) << dec << setfill('0') - << static_cast(strtod(data[1].c_str(), NULL)) - << setw(2) << dec << setfill('0') - << static_cast(strtod(data[2].c_str(), NULL)); - - return result.str(); -} - -string EncodeHTI::encode() -{ - // prepare data - string token; - istringstream stream(m_data); - vector data; - - while (getline(stream, token, ':') != 0) - data.push_back(token); - - ostringstream result; - result << setw(2) << hex << setfill('0') - << static_cast(strtod(data[0].c_str(), NULL)) - << setw(2) << hex << setfill('0') - << static_cast(strtod(data[1].c_str(), NULL)) - << setw(2) << hex << setfill('0') - << static_cast(strtod(data[2].c_str(), NULL)); - - return result.str(); -} - -string EncodeBDY::encode() -{ - const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"}; - short day = 7; - - for (short i = 0; i < 7; i++) - if (strcasecmp(days[i], m_data.c_str()) == 0) - day = i; - - ostringstream result; - result << setw(2) << hex << setfill('0') << day; - - return result.str(); -} - -string EncodeHDY::encode() -{ - const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Err"}; - short day = 8; - - for (short i = 0; i < 7; i++) - if (strcasecmp(days[i], m_data.c_str()) == 0) - day = i + 1; - - ostringstream result; - result << setw(2) << hex << setfill('0') << day; - - return result.str(); -} - -string EncodeTTM::encode() -{ - // prepare data - string token; - istringstream stream(m_data); - vector data; - - while (getline(stream, token, ':') != 0) - data.push_back(token); - - ostringstream result; - result << setw(2) << hex << setfill('0') - << static_cast( (strtod(data[0].c_str(), NULL) * 6) - + (strtod(data[1].c_str(), NULL) / 10) ); - - return result.str(); -} - diff --git a/src/lib/ebus/encode.h b/src/lib/ebus/encode.h deleted file mode 100644 index e5367086..00000000 --- a/src/lib/ebus/encode.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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_ENCODE_H_ -#define LIBEBUS_ENCODE_H_ - -#include - -using namespace std; - -class Encode -{ - -public: - Encode(const string& data, const string& factor = ""); - virtual ~Encode() {} - - virtual string encode() = 0; - -protected: - string m_data; - float m_factor; - -}; - - -class EncodeHEX : public Encode -{ - -public: - EncodeHEX(const string& data) : Encode(data) {} - ~EncodeHEX() {} - - string encode(); - -}; - -class EncodeUCH : public Encode -{ - -public: - EncodeUCH(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeUCH() {} - - string encode(); - -}; - -class EncodeSCH : public Encode -{ - -public: - EncodeSCH(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeSCH() {} - - string encode(); - -}; - -class EncodeUIN : public Encode -{ - -public: - EncodeUIN(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeUIN() {} - - string encode(); - -}; - -class EncodeSIN : public Encode -{ - -public: - EncodeSIN(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeSIN() {} - - string encode(); - -}; - -class EncodeULG : public Encode -{ - -public: - EncodeULG(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeULG() {} - - string encode(); - -}; - -class EncodeSLG : public Encode -{ - -public: - EncodeSLG(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeSLG() {} - - string encode(); - -}; - -class EncodeFLT : public Encode -{ - -public: - EncodeFLT(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeFLT() {} - - string encode(); - -}; - -class EncodeSTR : public Encode -{ - -public: - EncodeSTR(const string& data) : Encode(data) {} - ~EncodeSTR() {} - - string encode(); - -}; - -class EncodeBCD : public Encode -{ - -public: - EncodeBCD(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeBCD() {} - - string encode(); - -}; - -class EncodeD1B : public Encode -{ - -public: - EncodeD1B(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeD1B() {} - - string encode(); - -}; - -class EncodeD1C : public Encode -{ - -public: - EncodeD1C(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeD1C() {} - - string encode(); - -}; - -class EncodeD2B : public Encode -{ - -public: - EncodeD2B(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeD2B() {} - - string encode(); - -}; - -class EncodeD2C : public Encode -{ - -public: - EncodeD2C(const string& data, const string& factor) - : Encode(data, factor) {} - ~EncodeD2C() {} - - string encode(); - -}; - -class EncodeBDA : public Encode -{ - -public: - EncodeBDA(const string& data) : Encode(data) {} - ~EncodeBDA() {} - - string encode(); - -}; - -class EncodeHDA : public Encode -{ - -public: - EncodeHDA(const string& data) : Encode(data) {} - ~EncodeHDA() {} - - string encode(); - -}; - -class EncodeBTI : public Encode -{ - -public: - EncodeBTI(const string& data) : Encode(data) {} - ~EncodeBTI() {} - - string encode(); - -}; - -class EncodeHTI : public Encode -{ - -public: - EncodeHTI(const string& data) : Encode(data) {} - ~EncodeHTI() {} - - string encode(); - -}; - -class EncodeBDY : public Encode -{ - -public: - EncodeBDY(const string& data) : Encode(data) {} - ~EncodeBDY() {} - - string encode(); - -}; - -class EncodeHDY : public Encode -{ - -public: - EncodeHDY(const string& data) : Encode(data) {} - ~EncodeHDY() {} - - string encode(); - -}; - -class EncodeTTM : public Encode -{ - -public: - EncodeTTM(const string& data) : Encode(data) {} - ~EncodeTTM() {} - - string encode(); - -}; - -#endif // LIBEBUS_ENCODE_H_ From 02a04f00e2aee0f87d64a1c4ced3b076ec9b7268 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:53:40 +0100 Subject: [PATCH 17/83] removed unused files --- src/lib/ebus/Makefile.am | 12 +- src/lib/ebus/test/Makefile.am | 18 +- src/lib/ebus/test/test_commands.cpp | 86 ------- src/lib/ebus/test/test_configfile.cpp | 47 ---- src/lib/ebus/test/test_decode.cpp | 308 ------------------------- src/lib/ebus/test/test_encode.cpp | 309 -------------------------- 6 files changed, 2 insertions(+), 778 deletions(-) delete mode 100644 src/lib/ebus/test/test_commands.cpp delete mode 100644 src/lib/ebus/test/test_configfile.cpp delete mode 100644 src/lib/ebus/test/test_decode.cpp delete mode 100644 src/lib/ebus/test/test_encode.cpp diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am index 6f67d137..d8013f01 100644 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -13,17 +13,7 @@ libebus_a_SOURCES = result.cpp \ port.cpp \ port.h \ message.cpp \ - message.h \ - command.cpp \ - command.h \ - commands.cpp \ - commands.h \ - configfile.cpp \ - configfile.h \ - decode.cpp \ - decode.h \ - encode.cpp \ - encode.h + message.h distclean-local: -rm -f Makefile.in diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am index 4f76723d..56cdfd8c 100644 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -6,11 +6,7 @@ AM_CXXFLAGS = -fpic \ noinst_PROGRAMS = test_port \ test_symbol \ test_data \ - test_message \ - test_commands \ - test_configfile \ - test_decode \ - test_encode + test_message test_port_SOURCES = test_port.cpp test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a @@ -24,18 +20,6 @@ test_data_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_message_SOURCES = test_message.cpp test_message_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a -test_commands_SOURCES = test_commands.cpp -test_commands_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a - -test_configfile_SOURCES = test_configfile.cpp -test_configfile_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a - -test_decode_SOURCES = test_decode.cpp -test_decode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a - -test_encode_SOURCES = test_encode.cpp -test_encode_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a - distclean-local: -rm -f Makefile.in -rm -rf .libs diff --git a/src/lib/ebus/test/test_commands.cpp b/src/lib/ebus/test/test_commands.cpp deleted file mode 100644 index 6dc0a981..00000000 --- a/src/lib/ebus/test/test_commands.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "configfile.h" -#include "commands.h" -#include -#include -#include -#include -#include - -using namespace std; - -// will be part of cfg csv class -void readCSV(istream& is, Commands& commands){ - string line; - - // read lines - while (getline(is, line) != 0) { - vector row; - string column; - int count; - - count = 0; - - istringstream stream(line); - - // walk through columns - while (getline(stream, column, ';') != 0) { - row.push_back(column); - count++; - } - - commands.addCommand(row); - } -} - -int main() -{ - Commands* commands = ConfigCommands("test", ft_csv).getCommands(); - cout << "Commands: " << commands->sizeCmdDB() << endl; - - //~ string data("g ci password pin1"); - string data("s vwxmk DesiredTemp"); - - int index = commands->findCommand(data); - cout << "found at index: " << index << endl; - - // prepare data - string token; - istringstream stream(data); - vector cmd; - - // split stream - while (getline(stream, token, ' ') != 0) - cmd.push_back(token); - - //~ Command* command = new Command(index, (*commands)[index], "ff15b509030d2c0035000401000000cf00"); - Command* command = new Command(index, (*commands)[index], "19.0"); - - //~ string result = command->calcResult(cmd); - string result = command->calcData(); - cout << "result: " << result << endl; - - delete command; - - return 0; -} - - diff --git a/src/lib/ebus/test/test_configfile.cpp b/src/lib/ebus/test/test_configfile.cpp deleted file mode 100644 index df3d2ce9..00000000 --- a/src/lib/ebus/test/test_configfile.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "configfile.h" -#include -#include -#include -#include -#include - -using namespace std; - -int main() { - - string dir("test"); - ConfigCommands config(dir, ft_csv); - - Commands* commands = config.getCommands(); - - cout << "size: " << commands->sizeCmdDB() << endl; - - commands->findCommand("g ci Password"); - - cout << (*commands)[0][0] << endl; - - delete commands; - - return 0; -} - - diff --git a/src/lib/ebus/test/test_decode.cpp b/src/lib/ebus/test/test_decode.cpp deleted file mode 100644 index 346bda96..00000000 --- a/src/lib/ebus/test/test_decode.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "decode.h" -#include -#include - -using namespace std; - -int main() -{ - Decode* help_dec = NULL; - - cout << endl; - - // HEX - { - const char* hex[] = {"53706569636865722020"}; - for (size_t i = 0; i < sizeof(hex)/sizeof(hex[0]); i++) { - help_dec = new DecodeHEX(hex[i]); - cout << "DecodeHEX: " << setw(20) << hex[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // UCH - { - const char* uch[] = {"00", "01", "7f", "80", "fe", "ff", "a1"}; - for (size_t i = 0; i < sizeof(uch)/sizeof(uch[0]); i++) { - help_dec = new DecodeUCH(uch[i], "1.0"); - cout << "DecodeUCH: " << setw(20) << uch[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // SCH - { - const char* sch[] = {"00", "01", "7f", "80", "fe", "ff", "a1"}; - for (size_t i = 0; i < sizeof(sch)/sizeof(sch[0]); i++) { - help_dec = new DecodeSCH(sch[i], "1.0"); - cout << "DecodeSCH: " << setw(20) << sch[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // UIN - { - const char* uin[] = {"0000", "0001", "7fff", "8000", "fffe", "ffff", "a1b2"}; - for (size_t i = 0; i < sizeof(uin)/sizeof(uin[0]); i++) { - help_dec = new DecodeUIN(uin[i], "1.0"); - cout << "DecodeUIN: " << setw(20) << uin[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // SIN - { - const char* sin[] = {"0000", "0001", "7fff", "8000", "fffe", "ffff", "a1b2"}; - for (size_t i = 0; i < sizeof(sin)/sizeof(sin[0]); i++) { - help_dec = new DecodeSIN(sin[i], "1.0"); - cout << "DecodeSIN: " << setw(20) << sin[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // ULG - { - const char* ulg[] = {"00000000", "00000001", "7fffffff", "80000000", "fffffffe", "ffffffff", "a1b2c3d4"}; - for (size_t i = 0; i < sizeof(ulg)/sizeof(ulg[0]); i++) { - help_dec = new DecodeULG(ulg[i], "1.0"); - cout << "DecodeULG: " << setw(20) << ulg[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // SLG - { - const char* slg[] = {"00000000", "00000001", "7fffffff", "80000000", "fffffffe", "ffffffff", "a1b2c3d4"}; - for (size_t i = 0; i < sizeof(slg)/sizeof(slg[0]); i++) { - help_dec = new DecodeSLG(slg[i], "1.0"); - cout << "DecodeSLG: " << setw(20) << slg[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // FLT - { - const char* flt[] = {"0000", "081b", "2532", "2689", "0851"}; - for (size_t i = 0; i < sizeof(flt)/sizeof(flt[0]); i++) { - help_dec = new DecodeFLT(flt[i], "1.0"); - cout << "DecodeFLT: " << setw(20) << flt[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // STR - { - const char* str[] = {"53706569636865722020", "5644363030" }; - for (size_t i = 0; i < sizeof(str)/sizeof(str[0]); i++) { - help_dec = new DecodeSTR(str[i]); - cout << "DecodeSTR: " << setw(20) << str[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // BCD - { - const char* bcd[] = {"00", "01", "02", "03", "12", "99"}; - for (size_t i = 0; i < sizeof(bcd)/sizeof(bcd[0]); i++) { - help_dec = new DecodeBCD(bcd[i], "1.0"); - cout << "DecodeBCD: " << setw(20) << bcd[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // D1B - { - const char* d1b[] = {"00", "01", "7f", "81", "80"}; - for (size_t i = 0; i < sizeof(d1b)/sizeof(d1b[0]); i++) { - help_dec = new DecodeD1B(d1b[i], "1.0"); - cout << "DecodeD1B: " << setw(20) << d1b[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // D1C - { - const char* d1c[] = {"00", "64", "c8"}; - for (size_t i = 0; i < sizeof(d1c)/sizeof(d1c[0]); i++) { - help_dec = new DecodeD1C(d1c[i], "1.0"); - cout << "DecodeD1C: " << setw(20) << d1c[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // D2B - { - const char* d2b[] = {"0000", "0100", "ffff", "00ff", "0080", "0180", "ff7f"}; - for (size_t i = 0; i < sizeof(d2b)/sizeof(d2b[0]); i++) { - help_dec = new DecodeD2B(d2b[i], "1.0"); - cout << "DecodeD2B: " << setw(20) << d2b[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // D2C - { - const char* d2c[] = {"0000", "0100", "ffff", "f0ff", "0080", "0180", "ff7f"}; - for (size_t i = 0; i < sizeof(d2c)/sizeof(d2c[0]); i++) { - help_dec = new DecodeD2C(d2c[i], "1.0"); - cout << "DecodeD2C: " << setw(20) << d2c[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // BDA - { - const char* bda[] = {"171113", "220901"}; - for (size_t i = 0; i < sizeof(bda)/sizeof(bda[0]); i++) { - help_dec = new DecodeBDA(bda[i]); - cout << "DecodeBDA: " << setw(20) << bda[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // HDA - { - const char* hda[] = {"010101", "1f0c1b"}; - for (size_t i = 0; i < sizeof(hda)/sizeof(hda[0]); i++) { - help_dec = new DecodeHDA(hda[i]); - cout << "DecodeHDA: " << setw(20) << hda[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // BTI - { - const char* bti[] = {"010101", "174209", "235959"}; - for (size_t i = 0; i < sizeof(bti)/sizeof(bti[0]); i++) { - help_dec = new DecodeBTI(bti[i]); - cout << "DecodeBTI: " << setw(20) << bti[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // HTI - { - const char* hti[] = {"010101", "112a09", "173b3b"}; - for (size_t i = 0; i < sizeof(hti)/sizeof(hti[0]); i++) { - help_dec = new DecodeHTI(hti[i]); - cout << "DecodeHTI: " << setw(20) << hti[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // BDY - { - const char* bdy[] = {"01", "03", "06", "07"}; - for (size_t i = 0; i < sizeof(bdy)/sizeof(bdy[0]); i++) { - help_dec = new DecodeBDY(bdy[i]); - cout << "DecodeBDY: " << setw(20) << bdy[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // HDY - { - const char* hdy[] = {"01", "03", "07", "08"}; - for (size_t i = 0; i < sizeof(hdy)/sizeof(hdy[0]); i++) { - help_dec = new DecodeHDY(hdy[i]); - cout << "DecodeHDY: " << setw(20) << hdy[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - // TTM - { - const char* ttm[] = {"00", "23", "4f", "90"}; - for (size_t i = 0; i < sizeof(ttm)/sizeof(ttm[0]); i++) { - help_dec = new DecodeTTM(ttm[i]); - cout << "DecodeTTM: " << setw(20) << ttm[i] << " = " << help_dec->decode() << endl; - - delete help_dec; - } - - cout << endl; - } - - return 0; -} - - diff --git a/src/lib/ebus/test/test_encode.cpp b/src/lib/ebus/test/test_encode.cpp deleted file mode 100644 index 3e3bc887..00000000 --- a/src/lib/ebus/test/test_encode.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "encode.h" -#include -#include - -using namespace std; - -int main() -{ - Encode* help_enc = NULL; - - cout << endl; - - // HEX - { - const char* hex[] = {"53 70 65 69 63 68 65 72 20 20"}; - for (size_t i = 0; i < sizeof(hex)/sizeof(hex[0]); i++) { - help_enc = new EncodeHEX(hex[i]); - cout << "EncodeHEX: " << setw(20) << hex[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // UCH - { - const char* uch[] = {"0", "1", "127", "128", "254", "255", "161"}; - for (size_t i = 0; i < sizeof(uch)/sizeof(uch[0]); i++) { - help_enc = new EncodeUCH(uch[i], "1.0"); - cout << "EncodeUCH: " << setw(20) << uch[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // SCH - { - const char* sch[] = {"0", "1", "127", "-128", "-2", "-1", "-95"}; - for (size_t i = 0; i < sizeof(sch)/sizeof(sch[0]); i++) { - help_enc = new EncodeSCH(sch[i], "1.0"); - cout << "EncodeSCH: " << setw(20) << sch[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // UIN - { - const char* uin[] = {"0", "1", "32767", "32768", "65534", "65535", "41394"}; - for (size_t i = 0; i < sizeof(uin)/sizeof(uin[0]); i++) { - help_enc = new EncodeUIN(uin[i], "1.0"); - cout << "EncodeUIN: " << setw(20) << uin[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // SIN - { - const char* sin[] = {"0", "1", "32767", "-32768", "-2", "-1", "-24142"}; - for (size_t i = 0; i < sizeof(sin)/sizeof(sin[0]); i++) { - help_enc = new EncodeSIN(sin[i], "1.0"); - cout << "EncodeSIN: " << setw(20) << sin[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // ULG - { - const char* ulg[] = {"0", "1", "2147483647", "2147483648", "4294967294", "4294967295", "2712847316"}; - for (size_t i = 0; i < sizeof(ulg)/sizeof(ulg[0]); i++) { - help_enc = new EncodeULG(ulg[i], "1.0"); - cout << "EncodeULG: " << setw(20) << ulg[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // SLG - { - const char* slg[] = {"0", "1", "2147483647", "-2147483648", "-2", "-1", "-1582119980"}; - for (size_t i = 0; i < sizeof(slg)/sizeof(slg[0]); i++) { - help_enc = new EncodeSLG(slg[i], "1.0"); - cout << "EncodeSLG: " << setw(20) << slg[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // FLT - { - const char* flt[] = {"0.000", "2.075", "9.522", "9.865", "2.129"}; - for (size_t i = 0; i < sizeof(flt)/sizeof(flt[0]); i++) { - help_enc = new EncodeFLT(flt[i], "1.0"); - cout << "EncodeFLT: " << setw(20) << flt[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // STR - { - const char* str[] = {"Speicher ", "VD600" }; - for (size_t i = 0; i < sizeof(str)/sizeof(str[0]); i++) { - help_enc = new EncodeSTR(str[i]); - cout << "EncodeSTR: " << setw(20) << str[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // BCD - { - const char* bcd[] = {"0", "1", "2", "3", "12", "99"}; - for (size_t i = 0; i < sizeof(bcd)/sizeof(bcd[0]); i++) { - help_enc = new EncodeBCD(bcd[i], "1.0"); - cout << "EncodeBCD: " << setw(20) << bcd[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // D1B - { - const char* d1b[] = {"00", "01", "127", "-127", "-128"}; - for (size_t i = 0; i < sizeof(d1b)/sizeof(d1b[0]); i++) { - help_enc = new EncodeD1B(d1b[i], "1.0"); - cout << "EncodeD1B: " << setw(20) << d1b[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // D1C - { - const char* d1c[] = {"0", "50", "100"}; - for (size_t i = 0; i < sizeof(d1c)/sizeof(d1c[0]); i++) { - help_enc = new EncodeD1C(d1c[i], "1.0"); - cout << "EncodeD1C: " << setw(20) << d1c[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // D2B - { - const char* d2b[] = {"0", "0.00390625", "-0.00390625", "-1", "-128", "-127.99609375", "127.99609375"}; - for (size_t i = 0; i < sizeof(d2b)/sizeof(d2b[0]); i++) { - help_enc = new EncodeD2B(d2b[i], "1.0"); - cout << "EncodeD2B: " << setw(20) << d2b[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // D2C - { - const char* d2c[] = {"0", "0.0625", "-0.0625", "-1", "-2048", "-2047.9375", "2047.9375"}; - for (size_t i = 0; i < sizeof(d2c)/sizeof(d2c[0]); i++) { - help_enc = new EncodeD2C(d2c[i], "1.0"); - cout << "EncodeD2C: " << setw(20) << d2c[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // BDA - { - const char* bda[] = {"17.11.2013", "22.09.2001"}; - for (size_t i = 0; i < sizeof(bda)/sizeof(bda[0]); i++) { - help_enc = new EncodeBDA(bda[i]); - cout << "EncodeBDA: " << setw(20) << bda[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // HDA - { - const char* hda[] = {"01.01.2001", "31.12.2027"}; - for (size_t i = 0; i < sizeof(hda)/sizeof(hda[0]); i++) { - help_enc = new EncodeHDA(hda[i]); - cout << "EncodeHDA: " << setw(20) << hda[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // BTI - { - const char* bti[] = {"01:01:01", "17:42:09", "23:59:59"}; - for (size_t i = 0; i < sizeof(bti)/sizeof(bti[0]); i++) { - help_enc = new EncodeBTI(bti[i]); - cout << "EncodeBTI: " << setw(20) << bti[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // HTI - { - const char* hti[] = {"01:01:01", "17:42:09", "23:59:59"}; - for (size_t i = 0; i < sizeof(hti)/sizeof(hti[0]); i++) { - help_enc = new EncodeHTI(hti[i]); - cout << "EncodeHTI: " << setw(20) << hti[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // BDY - { - const char* bdy[] = {"Tue", "Thu", "Sun", "Err"}; - for (size_t i = 0; i < sizeof(bdy)/sizeof(bdy[0]); i++) { - help_enc = new EncodeBDY(bdy[i]); - cout << "EncodeBDY: " << setw(20) << bdy[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - - // HDY - { - const char* hdy[] = {"Mon", "Wed", "Sun", "Err"}; - for (size_t i = 0; i < sizeof(hdy)/sizeof(hdy[0]); i++) { - help_enc = new EncodeHDY(hdy[i]); - cout << "EncodeHDY: " << setw(20) << hdy[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - // TTM - { - const char* ttm[] = {"00:00", "05:50", "13:10", "24:00"}; - for (size_t i = 0; i < sizeof(ttm)/sizeof(ttm[0]); i++) { - help_enc = new EncodeTTM(ttm[i]); - cout << "EncodeTTM: " << setw(20) << ttm[i] << " = " << help_enc->encode() << endl; - - delete help_enc; - } - - cout << endl; - } - - return 0; -} - - From 7783af84c967129ad783f188d0bc0ed792d0ffe4 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 18:50:08 +0100 Subject: [PATCH 18/83] replaced by BusHandler --- src/ebusd/busloop.cpp | 700 ------------------------------------------ src/ebusd/busloop.h | 370 ---------------------- 2 files changed, 1070 deletions(-) delete mode 100644 src/ebusd/busloop.cpp delete mode 100644 src/ebusd/busloop.h diff --git a/src/ebusd/busloop.cpp b/src/ebusd/busloop.cpp deleted file mode 100644 index 06292767..00000000 --- a/src/ebusd/busloop.cpp +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 "busloop.h" -#include "logger.h" -#include "appl.h" -#include -#include - -using namespace std; - -extern Logger& L; -extern Appl& A; - -BusMessage::BusMessage(const string command, const bool poll, const bool scan) - : m_poll(poll), m_scan(scan), m_command(command), m_result(), m_resultCode(RESULT_OK) -{ - unsigned char dstAddress = m_command[1]; - - if (dstAddress == BROADCAST) - m_type = broadcast; - else if (isMaster(dstAddress) == true) - m_type = masterMaster; - else - m_type = masterSlave; - - pthread_mutex_init(&m_mutex, NULL); - pthread_cond_init(&m_cond, NULL); -} - -const string BusMessage::getMessageStr() -{ - string result; - - if (m_resultCode >= 0) { - if (m_type == masterSlave) { - result = m_command.getDataStr(); - result += "00"; - result += m_result.getDataStr(); - result += "00"; - } - else - result = "success"; - } - else - result = "error: "+string(getResultCodeCStr()); - - return result; -} - - -BusLoop::BusLoop(Commands* commands) - : m_commands(commands), m_running(true), m_lockCounter(0), - m_priorRetry(false), m_scan(false), m_scanFull(false), m_scanIndex(0) -{ - m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck")); - m_port->open(); - - if (m_port->isOpen() == false) - L.log(bus, error, "can't open %s", A.getOptVal("device")); - - m_dumpFile = A.getOptVal("dumpfile"); - m_dumpSize = A.getOptVal("dumpsize"); - m_dumping = A.getOptVal("dump"); - - m_logRawData = A.getOptVal("lograwdata"); - - m_pollInterval = A.getOptVal("pollinterval"); - - m_recvTimeout = A.getOptVal("recvtimeout"); - - m_sendRetries = A.getOptVal("sendretries"); - - m_lockRetries = A.getOptVal("lockretries"); - - m_acquireTime = A.getOptVal("acquiretime"); -} - -BusLoop::~BusLoop() -{ - if (m_port->isOpen() == true) - m_port->close(); - - delete m_port; -} - -void* BusLoop::run() -{ - int sendRetries = 0; - int lockRetries = 0; - - // polling - time_t pollStart, pollEnd; - time(&pollStart); - double pollDelta; - - for (;;) { - if (m_port->isOpen() == true) { - ssize_t numBytes; - - // add poll or scan command - if (m_commands->sizePollDB() > 0 || m_scan == true) { - // check polling delta - time(&pollEnd); - pollDelta = difftime(pollEnd, pollStart); - - // add new polling command to send - if (pollDelta >= m_pollInterval) { - if (m_scan == true) - addScanMessage(); - else - addPollMessage(); - - time(&pollStart); - } - } - - // read device - no timeout needed (AUTO-SYN) - numBytes = m_port->recv(0); - - if (numBytes < 0) { - L.log(bus, error, " ERR_DEVICE: generic device error"); - continue; - } - - // cycle bytes - collectCycData(numBytes); - - // send command - if (m_sstr.size() == 0 && m_lockCounter == 0 && m_busQueue.size() > 0) { - // acquire Bus - int busResult = acquireBus(); - - // send bus command - if (busResult == RESULT_BUS_ACQUIRED) { - BusMessage* message = sendCommand(); - L.log(bus, trace, " %s", message->getMessageStr().c_str()); - - if (message->isErrorResult() == true) { - if (sendRetries < m_sendRetries) { - sendRetries++; - L.log(bus, trace, " send retry %d", sendRetries); - message->setResult(string(), RESULT_OK); - } - else { - sendRetries = 0; - L.log(bus, event, " send retry failed", sendRetries); - - if (message->isPoll() == true) - delete m_busQueue.remove(); - else - message->sendSignal(); - } - } - else { - sendRetries = 0; - - if (message->isPoll() == true) { - if (message->isScan() == true) - m_commands->storeScanData(message->getMessageStr().c_str()); - else - m_commands->storePollData(message->getMessageStr().c_str()); // TODO use getResult() - delete message; - } - else - message->sendSignal(); - } - - lockRetries = 0; - m_lockCounter = A.getOptVal("lockcounter"); - } - else if (busResult == RESULT_ERR_BUS_LOST) { - L.log(bus, trace, " acquire bus failed"); - - if (lockRetries >= m_lockRetries) { - lockRetries = 0; - L.log(bus, event, " lock bus failed"); - - BusMessage* message = m_busQueue.remove(); - if (message->isPoll() == true) - delete message; - else - message->sendSignal(); - } - else { - lockRetries++; - L.log(bus, trace, " lock retry %d", lockRetries); - } - - m_lockCounter = A.getOptVal("lockcounter"); - } - - } - - } - else { - // TODO: define max reopen - sleep(10); - m_port->open(); - - if (m_port->isOpen() == false) - L.log(bus, error, "can't open %s", A.getOptVal("device")); - - } - - if (m_running == false) { - if (m_port->isOpen() == true) - m_port->close(); - - return NULL; - } - - } - - return NULL; -} - -int BusLoop::writeDumpFile(const char* byte) -{ - int ret = 0; - - ofstream fs(m_dumpFile.c_str(), ios::out | ios::binary | ios::app); - - if (fs == 0) - return -1; - - fs.write(byte, 1); - - if (fs.tellp() >= m_dumpSize * 1024) { - string oldfile; - oldfile += m_dumpFile; - oldfile += ".old"; - ret = rename(m_dumpFile.c_str(), oldfile.c_str()); - } - - fs.close(); - - return ret; -} - -unsigned char BusLoop::fetchByte() -{ - unsigned char byte; - - // fetch byte - byte = m_port->byte(); - - if (m_dumping == true) - writeDumpFile((const char*) &byte); - - if (m_logRawData == true) - L.log(bus, event, "%02x", byte); - - return byte; -} - -void BusLoop::collectCycData(const int numRecv) -{ - // cycle bytes - for (int i = 0; i < numRecv; i++) { - - // fetch byte - unsigned char byte = fetchByte(); - - if (byte == SYN) { - - // analyse cycle data - if (m_sstr.size() > 0) { - - analyseCycData(); - - if (m_sstr.size() == 1 && m_lockCounter == 0 && m_priorRetry == false) - m_lockCounter++; - - else if (m_lockCounter > 0) - m_lockCounter--; - - m_sstr.clear(); - } - - else if (m_lockCounter > 0) - m_lockCounter--; - - } - - // collect cycle data - else - m_sstr.push_back(byte, true, false); - } -} - -void BusLoop::analyseCycData() -{ - static bool skipfirst = false; - - if (skipfirst == true) { - L.log(cyc, trace, "%s", m_sstr.getDataStr().c_str()); - - int index = m_commands->storeCycData(m_sstr.getDataStr()); - - if (index == -1) { - L.log(cyc, debug, " command not found"); - } - else if (index == -2) { - L.log(cyc, debug, " no commands defined"); - } - else if (index == -3) { - L.log(cyc, debug, " search skipped - string too short"); - } - else { - string tmp; - tmp += (*m_commands)[index][1]; - tmp += " "; - tmp += (*m_commands)[index][2]; - L.log(cyc, event, " cycle [%4d] %s", index, tmp.c_str()); - } - - // collect Slave address - if (index != -3) - collectSlave(); - } - else - skipfirst = true; -} - -void BusLoop::collectSlave() -{ - vector::iterator it; - - for (int i = 0; i < 2; i++) { - bool found = false; - unsigned char mm = m_sstr[i]; - - if (i == 0) { - if (mm == 0xFF) - mm = 0x04; - else - mm += 0x05; - } - - for (it = m_slave.begin(); it != m_slave.end(); it++) - if ((*it) == mm) - found = true; - - if (found == false && isMaster(mm) == false && mm != BROADCAST) { - m_slave.push_back(mm); - L.log(bus, event, " new slave: %d %02x", m_slave.size(), m_slave.back()); - } - } -} - -int BusLoop::acquireBus() -{ - unsigned char recvByte, sendByte; - ssize_t numRecv, numSend; - - sendByte = m_busQueue.next()->getCommand()[0]; - - // send QQ - numSend = m_port->send(&sendByte); - if (numSend <= 0) { - L.log(bus, error, " ERR_SEND: send error"); - return RESULT_ERR_SEND; - } - - // wait ~4200 usec for receive - usleep(m_acquireTime); - - // receive 1 byte - must be QQ - numRecv = m_port->recv(0); - - if (numRecv < 0) { - L.log(bus, error, " ERR_DEVICE: generic device error"); - return RESULT_ERR_DEVICE; - } - - if (numRecv == 1) { - // fetch byte - recvByte = fetchByte(); - - // compare sent and received byte - if (sendByte == recvByte) { - L.log(bus, trace, " bus acquired"); - return RESULT_BUS_ACQUIRED; - } - - // collect cycle data - if (recvByte != SYN) - m_sstr.push_back(recvByte, true, false); - - // compare prior nibble for retry - if ((sendByte & 0x0F) == (recvByte & 0x0F)) { - m_priorRetry = true; - L.log(bus, trace, " bus prior retry"); - return RESULT_BUS_PRIOR_RETRY; - } - - L.log(bus, error, " ERR_BUS_LOST: lost bus arbitration"); - return RESULT_ERR_BUS_LOST; - } - - // cycle bytes - collectCycData(numRecv); - - L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); - return RESULT_ERR_EXTRA_DATA; -} - -BusMessage* BusLoop::sendCommand() -{ - unsigned char recvByte; - string result; - SymbolString slaveData; - int retval = RESULT_OK; - - BusMessage* message = m_busQueue.next(); - - // send ZZ PB SB NN Dx CRC - SymbolString command = message->getCommand(); - for (size_t i = 1; i < command.size(); i++) { - retval = sendByte(command[i]); - if (retval < 0) - goto on_exit; - } - - // BC -> send SYN - if (message->getType() == broadcast) { - sendByte(SYN); - goto on_exit; - } - - // receive ACK - retval = recvSlaveAck(recvByte); - if (retval < 0) - goto on_exit; - - // is slave ACK negative? - if (recvByte == NAK) { - - // send QQ ZZ PB SB NN Dx CRC again - for (size_t i = 0; i < command.size(); i++) { - retval = sendByte(command[i]); - if (retval < 0) - goto on_exit; - } - - // receive ACK - retval = recvSlaveAck(recvByte); - if (retval < 0) - goto on_exit; - - // is slave ACK negative? - if (recvByte == NAK) { - sendByte(SYN); - L.log(bus, error, " ERR_NAK: NAK received"); - retval = RESULT_ERR_NAK; - goto on_exit; - } - } - - // MM -> send SYN - if (message->getType() == masterMaster) { - sendByte(SYN); - goto on_exit; - } - - // receive NN, Dx, CRC - retval = recvSlaveData(slaveData); - - // are calculated and received CRC equal? - if (retval == RESULT_ERR_CRC) { - - // send NAK - retval = sendByte(NAK); - if (retval < 0) - goto on_exit; - - // receive NN, Dx, CRC - slaveData.clear(); - retval = recvSlaveData(slaveData); - - // are calculated and received CRC equal? - if (retval == RESULT_ERR_CRC) { - - // send NAK - retval = sendByte(NAK); - if (retval >= 0) - retval = RESULT_ERR_CRC; - } - } - - if (retval < 0) - goto on_exit; - - // send ACK - retval = sendByte(ACK); - if (retval == -1) { - L.log(bus, error, " ERR_ACK: ACK error"); - retval = RESULT_ERR_ACK; - goto on_exit; - } - - // MS -> send SYN - sendByte(SYN); - -on_exit: - - // empty receive buffer - while (m_port->size() != 0) - recvByte = fetchByte(); - - message->setResult(slaveData, retval); - - if (retval == RESULT_OK) - return m_busQueue.remove(); - else - return message; - -} - -int BusLoop::sendByte(const unsigned char sendByte) -{ - unsigned char recvByte; - ssize_t numRecv, numSend; - - numSend = m_port->send(&sendByte); - - // receive 1 byte - must be equal - numRecv = m_port->recv(RECV_TIMEOUT); - - if (numSend != numRecv) { - L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); - return RESULT_ERR_EXTRA_DATA; - } - - recvByte = fetchByte(); - - if (sendByte != recvByte) { - L.log(bus, error, " ERR_SEND: send error"); - return RESULT_ERR_SEND; - } - - return RESULT_OK; -} - -int BusLoop::recvSlaveAck(unsigned char& recvByte) -{ - ssize_t numRecv; - - // receive ACK - numRecv = m_port->recv(m_recvTimeout); - - if (numRecv > 1) { - L.log(bus, error, " ERR_EXTRA_DATA: received bytes > sent bytes"); - return RESULT_ERR_EXTRA_DATA; - } - else if (numRecv < 0) { - L.log(bus, error, " ERR_TIMEOUT: read timeout"); - return RESULT_ERR_TIMEOUT; - } - - recvByte = fetchByte(); - - // is received byte SYN? - if (recvByte == SYN) { - L.log(bus, error, " ERR_SYN: SYN received"); - return RESULT_ERR_SYN; - } - - return RESULT_OK; -} - -int BusLoop::recvSlaveData(SymbolString& result) -{ - unsigned char recvByte, calcCrc = 0; - ssize_t numRecv; - size_t NN = 0; - bool updateCrc = true; - int retval = 0; - - for (size_t i = 0, needed = 1; i < needed; i++) { - numRecv = m_port->recv(RECV_TIMEOUT); - if (numRecv < 0) { - L.log(bus, error, " ERR_TIMEOUT: read timeout"); - return RESULT_ERR_TIMEOUT; - } - - recvByte = fetchByte(); - retval = result.push_back(recvByte, true, updateCrc); - if (retval < 0) - return retval; - - if (retval == RESULT_IN_ESC) - needed++; - else if (result.size() == 1) { // NN received - NN = result[0]; - needed += NN; - } - else if (NN > 0 && result.size() == 1+NN) {// all data received - updateCrc = false; - calcCrc = result.getCRC(); - needed++; - } - } - - if (retval == RESULT_IN_ESC) { - L.log(bus, error, " ERR_ESC: invalid escape sequence received"); - return RESULT_ERR_ESC; - } - - if (updateCrc == true || calcCrc != result[result.size()-1]) { - L.log(bus, error, " ERR_CRC: CRC error"); - return RESULT_ERR_CRC; - } - - return RESULT_OK; -} - -void BusLoop::addPollMessage() -{ - int index = m_commands->nextPollCommand(); - if (index < 0) { - L.log(bus, error, "polling index out of range"); - } - else { - // TODO: implement as methode from class commands? - string tmp; - tmp += (*m_commands)[index][1]; - tmp += " "; - tmp += (*m_commands)[index][2]; - L.log(bus, event, " polling [%4d] %s", index, tmp.c_str()); - - string busCommand(A.getOptVal("address")); - busCommand += m_commands->getBusCommand(index); - transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); - - BusMessage* message = new BusMessage(busCommand, true, false); - L.log(bus, trace, " msg: %s", busCommand.c_str()); - - addMessage(message); - } -} - -void BusLoop::addScanMessage() -{ - string busCommand(A.getOptVal("address")); - stringstream sstr; - - if (m_scanFull == true) { - for (; m_scanIndex <= 0xFF; m_scanIndex++) { - if (isMaster(m_scanIndex) == false && m_scanIndex != SYN - && m_scanIndex != ESC && m_scanIndex != BROADCAST) { - sstr << nouppercase << setw(2) << setfill('0') - << hex << m_scanIndex; - break; - } - } - } - else { - sstr << nouppercase << setw(2) << setfill('0') - << hex << static_cast(m_slave[m_scanIndex]); - - if (m_scanIndex+1 >= m_slave.size()) - m_scan = false; - } - - if (m_scanIndex > 0xFF) - m_scan = false; - else { - m_scanIndex++; - - busCommand += sstr.str(); - busCommand += "070400"; - transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); - - L.log(bus, event, " scanning address %s", sstr.str().c_str()); - - - BusMessage* message = new BusMessage(busCommand, true, true); - L.log(bus, trace, " msg: %s", busCommand.c_str()); - - addMessage(message); - } -} diff --git a/src/ebusd/busloop.h b/src/ebusd/busloop.h deleted file mode 100644 index ec18ebc3..00000000 --- a/src/ebusd/busloop.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-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 BUSLOOP_H_ -#define BUSLOOP_H_ - -#include "commands.h" -#include "port.h" -#include "wqueue.h" -#include "thread.h" -#include "symbol.h" -#include "result.h" - -using namespace std; - -/** \file busloop.h */ - -/** the maximum time [us] allowed for retrieving a byte from an addressed slave */ -#define RECV_TIMEOUT 10000 - -/** possible bus command types */ -enum BusCommandType { - invalid, /*!< invalid command type */ - broadcast, /*!< broadcast */ - masterMaster, /*!< master - master */ - masterSlave /*!< master - slave */ -}; - -/** - * @brief class for data/message transfer between baseloop and busloop. - */ -class BusMessage -{ - -public: - /** - * @brief construct a new bus message instance and determine command type. - * @param command the command data to write on bus. - * @param poll true if message type is polling. - * @param scan true if message type is scanning. - */ - BusMessage(const string command, const bool poll, const bool scan); - - /** - * @brief destructor. - */ - ~BusMessage() - { - pthread_mutex_destroy(&m_mutex); - pthread_cond_destroy(&m_cond); - } - - /** - * @brief get the bus command type. - * @return the bus command type. - */ - BusCommandType getType() const { return m_type; } - - /** - * @brief get the command string. - * @return the command string. - */ - SymbolString getCommand() const { return m_command; } - - /** - * @brief get the result string. - * @return the result string. - */ - SymbolString getResult() const { return m_result; } - - /** - * @brief set the result string and result code. - * @param result the result string. - * @param resultCode the result code. - */ - void setResult(const SymbolString result, const int resultCode) - { m_result = result; m_resultCode = resultCode; } - - /** - * @brief return status of result code. - * @return true if result code is negativ. - */ - bool isErrorResult() const { return m_resultCode < 0; } - - /** - * @brief return output string of result code. - * @return the output string of result code. - */ - const char* getResultCodeCStr() const { return getResultCode(m_resultCode); } - - /** - * @brief return the message string or error result string. - * @return the message string or error result string. - */ - const string getMessageStr(); - - /** - * @brief return polling flag of message type. - * @return true if message type is polling. - */ - bool isPoll() const { return m_poll; } - - /** - * @brief return scanning flag of message type. - * @return true if message type is scanning. - */ - bool isScan() const { return m_scan; } - - /** - * @brief wait on notification. - */ - void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout - - /** - * @brief send notification. - */ - void sendSignal() { pthread_cond_signal(&m_cond); } - -private: - /** the bus command type */ - BusCommandType m_type; - - /** true if message is of type polling */ - bool m_poll; - - /** true if message is of type scanning */ - bool m_scan; - - /** the command string (master data) */ - SymbolString m_command; - - /** the result string (slave data) */ - SymbolString m_result; - - /** the result code of result string */ - int m_resultCode; - - /** mutex variable for exclusive lock */ - pthread_mutex_t m_mutex; - - /** condition variable for exclusive lock */ - pthread_cond_t m_cond; - -}; - -/** - * @brief class busloop which handle all bus activities. - */ -class BusLoop : public Thread -{ - -public: - /** - * @brief create a busloop instance and set the commands instance. - * @param commands the commands instance. - */ - BusLoop(Commands* commands); - - /** - * @brief destructor. - */ - ~BusLoop(); - - /** - * @brief endless loop for busloop instance. - * @return void pointer. - */ - void* run(); - - /** - * @brief shut down busloop. - */ - void stop() { m_running = false; } - - /** - * @brief add a new bus message to internal message queue. - * @param message the bus message. - */ - void addMessage(BusMessage* message) { m_busQueue.add(message); } - - /** - * @brief switch to new commands instance. - * @param commands reference of new loaded commands instance. - */ - void reload(Commands* commands) { m_commands = commands; } - - /** - * @brief scanning ebus do determine bus members. - * @param full if true a scan of all slave addresses will be done. - */ - void scan(const bool full=false) { m_scan = true; m_scanFull = full; m_scanIndex = 0; } - - /** - * @brief toggle (on/off) logging of raw data to logging system. - */ - void raw() { m_logRawData == true ? m_logRawData = false : m_logRawData = true ; } - - /** - * @brief set the name of dump file. - * @param dumpFile the file name of dump file. - */ - void setDumpFile(const string& dumpFile) { m_dumpFile = dumpFile; } - - /** - * @brief set the max size of dump file. - * @param dumpSize the max. size of the dump file, before switching. - */ - void setDumpSize(const long dumpSize) { m_dumpSize = dumpSize; } - - /** - * @brief toggle (on/off) dumping of raw bytes to a dump file. - */ - void dump() { m_dumping == true ? m_dumping = false : m_dumping = true ; } - -private: - /** the commands instance */ - Commands* m_commands; - - /** the port instance which control the ebus device */ - Port* m_port; - - /** the name of dump file*/ - string m_dumpFile; - - /** max. size of dump file */ - long m_dumpSize; - - /** true if dumping of raw bytes to file is enabled */ - bool m_dumping; - - /** true if logging of raw bytes is enabled */ - bool m_logRawData; - - /** true if this instance is running */ - bool m_running; - - /** bus access is not allowed if counter is greater than 0 */ - int m_lockCounter; - - /** if true, we lost bus acquire but same priority class. - * after next SYN sign we are allowed to try again to aquire bus. - */ - bool m_priorRetry; - - /** queue for bus messages */ - WQueue m_busQueue; - - /** string for cycle bus data */ - SymbolString m_sstr; - - /** number of send retries for one bus command */ - int m_sendRetries; - - /** number of lock retries (acquire bus) for one bus command */ - int m_lockRetries; - - /** time for receiving answer from slave [us] */ - long m_recvTimeout; - - /** waiting time for bus acquire [us] */ - long m_acquireTime; - - /** time between to polling commands [s] */ - double m_pollInterval; - - /** vector with collected slave addresses */ - vector m_slave; - - /** true if bus scanning for collected slave addresses is active */ - bool m_scan; - - /** true if bus scanning for all slave addresses is active */ - bool m_scanFull; - - /** internal index do get next scan command */ - size_t m_scanIndex; - - /** - * @brief write byte to dump file. - * @param byte to write - * @return -1 if dump file cannot opened or renaming of dump file failed. - */ - int writeDumpFile(const char* byte); - - /** - * @brief fetch next byte of device input buffer (dumping and raw logging). - * @return next byte of device. - */ - unsigned char fetchByte(); - - /** - * @brief collect cycle bytes. the analysis of collected bytes will be triggered after next SYN sign. - * @param numRecv the number of bytes to analyze. - */ - void collectCycData(const int numRecv); - - /** - * @brief the analyzing of collected bytes. collecting of slave address will be triggered. - */ - void analyseCycData(); - - /** - * @brief determine and collect slave addresses. - */ - void collectSlave(); - - /** - * @brief try to acquire bus for sending purpose. - * @return result code of bus acquiring. - */ - int acquireBus(); - - /** - * @brief handle sending of a bus command. - * @return a reference to sent bus message. - */ - BusMessage* sendCommand(); - - /** - * @brief send 1 byte to bus device. - * @param sendByte the byte to send. - * @return result code of byte sending. - */ - int sendByte(const unsigned char sendByte); - - /** - * @brief receive ACK from slave. - * @param reference for receive byte. - * @return result code of receiving byte. - */ - int recvSlaveAck(unsigned char& recvByte); - - /** - * @brief receive slave data block. - * @param reference for result string. - * @return result code of receiving slave data. - */ - int recvSlaveData(SymbolString& result); - - /** - * @brief add a polling bus message to internal message queue. - * @param message the bus message. - */ - void addPollMessage(); - - /** - * @brief add a scanning bus message to internal message queue. - * @param message the bus message. - */ - void addScanMessage(); - -}; - -#endif // BUSLOOP_H_ From b3b19d199e3e72c36a659af590b73555c14a13f8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 19:01:15 +0100 Subject: [PATCH 19/83] simplifed Thread and fixed some cleanup --- src/ebusd/network.cpp | 27 +++++------------ src/ebusd/network.h | 22 +++----------- src/lib/utils/logger.h | 13 +++----- src/lib/utils/thread.cpp | 44 +++++++++++++++------------ src/lib/utils/thread.h | 65 +++++++++++++++++++++++++++++----------- 5 files changed, 88 insertions(+), 83 deletions(-) mode change 100644 => 100755 src/ebusd/network.cpp mode change 100644 => 100755 src/ebusd/network.h mode change 100644 => 100755 src/lib/utils/logger.h mode change 100644 => 100755 src/lib/utils/thread.cpp mode change 100644 => 100755 src/lib/utils/thread.h diff --git a/src/ebusd/network.cpp b/src/ebusd/network.cpp old mode 100644 new mode 100755 index f202d22f..324c6bd7 --- a/src/ebusd/network.cpp +++ b/src/ebusd/network.cpp @@ -37,10 +37,8 @@ extern Appl& A; int Connection::m_ids = 0; -void* Connection::run() +void Connection::run() { - m_running = true; - int ret; struct timespec tdiff; @@ -142,15 +140,12 @@ void* Connection::run() } delete m_socket; - m_running = false; L.log(net, trace, "[%05d] connection closed", getID()); - - return NULL; } Network::Network(const bool local, WQueue* netQueue) - : m_netQueue(netQueue), m_listening(false), m_running(false) + : m_netQueue(netQueue), m_listening(false) { if (local == true) m_tcpServer = new TCPServer(A.getOptVal("port"), "127.0.0.1"); @@ -172,18 +167,16 @@ Network::~Network() delete connection; } - if (m_running == true) - stop(); + stop(); + join(); delete m_tcpServer; } -void* Network::run() +void Network::run() { if (m_listening == false) - return NULL; - - m_running = true; + return; int ret; struct timespec tdiff; @@ -239,8 +232,7 @@ void* Network::run() #ifdef HAVE_PPOLL // new data from notify if (fds[0].revents & POLLIN) { - m_running = false; - break; + return; } // new data from socket @@ -249,8 +241,7 @@ void* Network::run() #ifdef HAVE_PSELECT // new data from notify if (FD_ISSET(m_notify.notifyFD(), &readfds)) { - m_running = false; - break; + return; } // new data from socket @@ -272,8 +263,6 @@ void* Network::run() } } - - return NULL; } void Network::cleanConnections() diff --git a/src/ebusd/network.h b/src/ebusd/network.h old mode 100644 new mode 100755 index 35f6e47f..9a04b031 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -132,25 +132,18 @@ public: * @param netQueue the remote queue for network messages. */ Connection(TCPSocket* socket, WQueue* netQueue) - : m_socket(socket), m_netQueue(netQueue), m_running(false) + : m_socket(socket), m_netQueue(netQueue) { m_id = ++m_ids; } /** * @brief endless loop for connection instance. - * @return void pointer. */ - void* run(); + virtual void run(); /** * @brief close active connection. */ - void stop() const { m_notify.notify(); } - - /** - * @brief status of connection instance. - * @return true if connection is running. - */ - bool isRunning() const { return m_running; } + virtual void stop() { m_notify.notify(); Thread::stop(); } /** * @brief return own connection id. @@ -168,9 +161,6 @@ private: /** notification object for shutdown procedure */ Notify m_notify; - /** true if this instance is running */ - bool m_running; - /** id of current connection*/ int m_id; @@ -200,9 +190,8 @@ public: /** * @brief endless loop for network instance. - * @return void pointer. */ - void* run(); + virtual void run(); /** * @brief shutdown network subsystem. @@ -225,9 +214,6 @@ private: /** true if this instance is listening */ bool m_listening; - /** true if this instance is running */ - bool m_running; - /** * @brief clean inactive connections from container. */ diff --git a/src/lib/utils/logger.h b/src/lib/utils/logger.h old mode 100644 new mode 100755 index ed454fee..7e3a3c08 --- a/src/lib/utils/logger.h +++ b/src/lib/utils/logger.h @@ -143,9 +143,8 @@ public: /** * @brief endless loop for logging sink instance. - * @return void pointer. */ - void* run(); + void run(); /** * @brief get the logging areas. @@ -294,18 +293,17 @@ public: /** * @brief endless loop for logger instance. - * @return void pointer. */ - void* run(); + virtual void run(); /** * @brief shutdown logger subsystem. */ - void stop(); + virtual void stop(); private: /** private constructor - singleton pattern */ - Logger() : m_running(false) {} + Logger() {} Logger(const Logger&); Logger& operator=(const Logger&); @@ -319,9 +317,6 @@ private: /** queue for logging messages */ WQueue m_logQueue; - /** true if this instance is running */ - bool m_running; - }; #endif // LIBUTILS_LOGGER_H_ diff --git a/src/lib/utils/thread.cpp b/src/lib/utils/thread.cpp old mode 100644 new mode 100755 index 4ea84136..b2f6f4ab --- a/src/lib/utils/thread.cpp +++ b/src/lib/utils/thread.cpp @@ -23,25 +23,22 @@ #include "thread.h" -/** - * @brief static function which will be called on thread startup. - * @return void pointer. - */ -static void* runThread(void* arg) +void* Thread::runThread(void* arg) { - return ((Thread*)arg)->run(); + ((Thread*)arg)->enter(); + return NULL; } Thread::~Thread() { - if (m_running == true && m_detached == false) + if (m_started == true && m_detached == false) pthread_detach(m_threadid); - if (m_running == true) + if (m_started == true) pthread_cancel(m_threadid); } -int Thread::start(const char* name) +bool Thread::start(const char* name) { int result = pthread_create(&m_threadid, NULL, runThread, this); @@ -52,32 +49,36 @@ int Thread::start(const char* name) pthread_setname_np(m_threadid, name); #endif - m_running = true; + m_started = true; + + return true; } - return result; + return false; } -int Thread::join() +bool Thread::join() { int result = -1; - if (m_running == true) { + if (m_started == true) { + m_stopped = true; result = pthread_join(m_threadid, NULL); - if (result == 0) + if (result == 0) { m_detached = false; - + m_started = false; + } } - return result; + return result == 0; } -int Thread::detach() +bool Thread::detach() { int result = -1; - if (m_running == true && m_detached == false) { + if (m_started == true && m_detached == false) { result = pthread_detach(m_threadid); if (result == 0) @@ -85,6 +86,11 @@ int Thread::detach() } - return result; + return result == 0; } +void Thread::enter() { + m_running = true; + run(); + m_running = false; +} diff --git a/src/lib/utils/thread.h b/src/lib/utils/thread.h old mode 100644 new mode 100755 index e18e4062..67846d22 --- a/src/lib/utils/thread.h +++ b/src/lib/utils/thread.h @@ -32,7 +32,7 @@ public: /** * @brief constructor. */ - Thread() : m_threadid(0), m_running(false), m_detached(false) {} + Thread() : m_threadid(0), m_started(false), m_running(false), m_stopped(false), m_detached(false) {} /** * @brief virtual destructor. @@ -40,44 +40,73 @@ public: virtual ~Thread(); /** - * @brief create the thread and set name for process list. - * @param name the thread name which show in process list. - * @return value of thread creating. + * @brief Thread entry helper for pthread_create. + * @param arg pointer to the @a Thread. + * @return NULL. */ - int start(const char* name); + static void* runThread(void* arg); /** - * @brief join the thread. - * @return value of thread joining. + * @brief Return whether this @a Thread is still running and not yet stopped. + * @return true if this @a Thread is till running and not yet stopped. */ - int join(); + virtual bool isRunning() { return m_running == true && m_stopped == false; } /** - * @brief detach the thread. - * @return value of thread detaching. + * @brief Create the native thread and set its name. + * @param name the thread name to show in the process list. + * @return whether the thread was started. */ - int detach(); + virtual bool start(const char* name); /** - * @brief return the thread id. - * @return own thread id. + * @brief Notify the thread that it shall stop. + */ + virtual void stop() { m_stopped = true; } + + /** + * @brief Join the thread. + * @return whether the thread was joined. + */ + virtual bool join(); + + /** + * @brief Detach the thread. + * @return whether the thread was detached. + */ + virtual bool detach(); + + /** + * @brief Get the thread id. + * @return the thread id. */ pthread_t self() {return m_threadid; } /** - * @brief virtul function which must be implemented in derived class. - * @return void pointer. + * @brief Thread entry method to be overridden by derived class. */ - virtual void* run() = 0; + virtual void run() = 0; private: + + /** + * @brief Enter the Thread loop by calling run(). + */ + void enter(); + /** own thread id */ pthread_t m_threadid; - /** true if thread is running */ + /** Whether the thread was started. */ + bool m_started; + + /** Whether the thread is still running (i.e. in @a run() ). */ bool m_running; - /** true if thread is detached */ + /** Whether the thread was stopped by @a stop() or @a join(). */ + bool m_stopped; + + /** Whether the thread was detached */ bool m_detached; }; From cfe7f99510572fa1c1553553d6a53ea200516d15 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 19:01:15 +0100 Subject: [PATCH 20/83] simplifed Thread and fixed some cleanup --- src/ebusd/network.cpp | 0 src/ebusd/network.h | 0 src/lib/utils/logger.h | 0 src/lib/utils/thread.cpp | 0 src/lib/utils/thread.h | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/ebusd/network.cpp mode change 100755 => 100644 src/ebusd/network.h mode change 100755 => 100644 src/lib/utils/logger.h mode change 100755 => 100644 src/lib/utils/thread.cpp mode change 100755 => 100644 src/lib/utils/thread.h diff --git a/src/ebusd/network.cpp b/src/ebusd/network.cpp old mode 100755 new mode 100644 diff --git a/src/ebusd/network.h b/src/ebusd/network.h old mode 100755 new mode 100644 diff --git a/src/lib/utils/logger.h b/src/lib/utils/logger.h old mode 100755 new mode 100644 diff --git a/src/lib/utils/thread.cpp b/src/lib/utils/thread.cpp old mode 100755 new mode 100644 diff --git a/src/lib/utils/thread.h b/src/lib/utils/thread.h old mode 100755 new mode 100644 From 11d43843c04cc30f97031bbc8547eccc226d7530 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 19:03:21 +0100 Subject: [PATCH 21/83] renamed a method, pass some class instances as reference --- src/lib/ebus/message.cpp | 16 +++++++--------- src/lib/ebus/message.h | 6 +++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index ecdfc467..a30a0a6b 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -177,15 +177,13 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa return RESULT_ERR_INVALID_ARG; // prepare not possible } -result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, +result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, char separator, bool answer) { - if (m_isActive == true) { - 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) { + result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); + if (result != RESULT_OK) + return result; + if (m_isActive == true && answer == true) { 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) @@ -238,7 +236,7 @@ result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg) return result; } -Message* MessageMap::find(const string clazz, const string name, const bool isActive, const bool isSet) +Message* MessageMap::find(const string& clazz, const string& name, const bool isActive, const bool isSet) { string key = clazz; for (int i=0; i<2; i++) { @@ -256,7 +254,7 @@ Message* MessageMap::find(const string clazz, const string name, const bool isAc return NULL; } -Message* MessageMap::find(SymbolString master) { +Message* MessageMap::find(SymbolString& master) { if (master.size() < 5) return NULL; unsigned char maxIdLength = master[4]; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a373c668..a36674fd 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -141,7 +141,7 @@ public: */ result_t prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator=';'); - result_t handle(SymbolString& masterData, SymbolString& slaveData, + result_t decode(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, char separator=';', bool answer=false); private: @@ -203,14 +203,14 @@ public: * @return the @a Message instance, or NULL. * Note: the caller may not free the returned instance. */ - Message* find(const string clazz, const string name, const bool isActive, const bool isSet); + Message* find(const string& clazz, const string& name, const bool isActive, const bool isSet); /** * @brief Finds the @a Message instance for the specified master data. * @param master the master @a SymbolString for identifying the @a Message. * @return the @a Message instance, or NULL. * Note: the caller may not free the returned instance. */ - Message* find(SymbolString master); + Message* find(SymbolString& master); /** * @brief Removes all @a Message instances. */ From 637800125ca0662b427ca1b50a589ae4a107f343 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 19:04:16 +0100 Subject: [PATCH 22/83] changed default arg for push_back --- src/lib/ebus/symbol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index cd117362..b30d0467 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -90,7 +90,7 @@ public: * RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received, * RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected. */ - result_t push_back(const unsigned char value, const bool isEscaped, const bool updateCRC=true); + result_t push_back(const unsigned char value, const bool isEscaped=true, const bool updateCRC=true); /** * @brief Returns the number of symbols in this symbol string. * @return the number of available symbols. From bd4d36b27f32ba113b3385687c1a106d5e8a907f Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 19:01:15 +0100 Subject: [PATCH 23/83] simplifed Thread and fixed some cleanup --- src/lib/utils/logger.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/lib/utils/logger.cpp b/src/lib/utils/logger.cpp index 70b410f1..04442631 100644 --- a/src/lib/utils/logger.cpp +++ b/src/lib/utils/logger.cpp @@ -100,7 +100,7 @@ void LogSink::addMessage(const LogMessage& message) m_logQueue.add((tmp)); } -void* LogSink::run() +void LogSink::run() { while (1) { LogMessage* message = m_logQueue.remove(); @@ -111,13 +111,12 @@ void* LogSink::run() write(*message); delete message; } - return NULL; + return; } write(*message); delete message; } - return NULL; } @@ -187,7 +186,7 @@ Logger& Logger::operator-=(const LogSink* sink) void Logger::log(const int area, const int level, const string& data, ...) { - if (m_running == true) { + if (isRunning() == true) { char* tmp; va_list ap; va_start(ap, data); @@ -203,11 +202,11 @@ void Logger::log(const int area, const int level, const string& data, ...) } -void* Logger::run() +void Logger::run() { - m_running = true; + bool running = true; - while (m_running == true) { + do { LogMessage* message = m_logQueue.remove(); sinkCI_t iter = m_sinks.begin(); @@ -215,28 +214,27 @@ void* Logger::run() for (; iter != m_sinks.end(); ++iter) { if (*iter != 0) { - if (((*iter)->getAreas() & message->getArea() + if ((((*iter)->getAreas() & message->getArea()) != 0 && (*iter)->getLevel() >= message->getLevel()) && message->isRunning() == true) { (*iter)->addMessage(*message); } else if (message->isRunning() == false) { (*iter)->addMessage(*message); - m_running = false; + running = false; } - } } delete message; - } - return NULL; + } while (running == true); } void Logger::stop() { m_logQueue.add(new LogMessage(LogMessage(bas, error, "", false))); usleep(100000); + Thread::stop(); } From 29f60af55c2af851ec1c96e71d7294a3293b3491 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:10:57 +0100 Subject: [PATCH 24/83] use result_t, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/lib/ebus/Makefile.am | 3 +- src/lib/ebus/port.cpp | 82 ++++++++++++++++++++++++++++++++++------ src/lib/ebus/port.h | 77 ++++++++++++++++++++++++++++++++----- 3 files changed, 140 insertions(+), 22 deletions(-) mode change 100644 => 100755 src/lib/ebus/Makefile.am diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am old mode 100644 new mode 100755 index d8013f01..a0c1c0e2 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -1,6 +1,7 @@ AM_CXXFLAGS = -fpic \ -Wall \ - -Wextra + -Wextra \ + -I$(top_srcdir)/src/lib/utils noinst_LIBRARIES = libebus.a diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index 9dcc9e66..f5b052fc 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -22,12 +22,15 @@ #endif #include "port.h" +#include "result.h" #include #include #include +#include #include #include #include +#include "logger.h" #ifdef HAVE_PPOLL #include @@ -101,8 +104,8 @@ ssize_t Device::recvBytes(const long timeout, size_t maxCount) #endif #endif - if (ret == -1) return -1; // TODO RESULT_ERR_DEVICE - if (ret == 0) return -2; // TODO RESULT_ERR_TIMEOUT + if (ret == -1) return RESULT_ERR_DEVICE; + if (ret == 0) return RESULT_ERR_TIMEOUT; } if (maxCount > sizeof(m_buffer)) @@ -132,7 +135,7 @@ unsigned char Device::getByte() } -void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck) +result_t DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck) { m_noDeviceCheck = noDeviceCheck; @@ -144,7 +147,7 @@ void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck) m_fd = open(deviceName.c_str(), O_RDWR | O_NOCTTY); if (m_fd < 0) - return; + return RESULT_ERR_FILENOTFOUND; // save current settings of serial device tcgetattr(m_fd, &m_oldSettings); @@ -169,7 +172,7 @@ void DeviceSerial::openDevice(const string deviceName, const bool noDeviceCheck) fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK); m_open = true; - + return RESULT_OK; } void DeviceSerial::closeDevice() @@ -190,7 +193,7 @@ void DeviceSerial::closeDevice() } -void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck) +result_t DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck) { m_noDeviceCheck = noDeviceCheck; @@ -211,13 +214,13 @@ void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck he = gethostbyname(host); if (he == NULL) - return; + return RESULT_ERR_FILENOTFOUND; memcpy(&sock.sin_addr, he->h_addr_list[0], he->h_length); } else { ret = inet_aton(host, &sock.sin_addr); if (ret == 0) - return; + return RESULT_ERR_FILENOTFOUND; } sock.sin_family = AF_INET; @@ -225,14 +228,16 @@ void DeviceNetwork::openDevice(const string deviceName, const bool noDeviceCheck m_fd = socket(AF_INET, SOCK_STREAM, 0); if (m_fd < 0) - return; + return RESULT_ERR_INVALID_ARG; ret = connect(m_fd, (struct sockaddr*) &sock, sizeof(sock)); if (ret < 0) - return; + return RESULT_ERR_INVALID_ARG; free(hostport); m_open = true; + + return RESULT_OK; } void DeviceNetwork::closeDevice() @@ -247,8 +252,11 @@ void DeviceNetwork::closeDevice() } -Port::Port(const string deviceName, const bool noDeviceCheck) - : m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck) +Port::Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, Logger* loggerRaw, + const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize) + : m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck), + m_logRaw(logRaw), m_loggerRaw(loggerRaw), + m_dumpRawFile(dumpRawFile), m_dumpRawMaxSize(dumpRawMaxSize) { m_device = NULL; @@ -257,6 +265,56 @@ Port::Port(const string deviceName, const bool noDeviceCheck) setType(dt_network); else setType(dt_serial); + + m_dumpRaw = false; + + setDumpRaw(dumpRaw); // open fstream if necessary +} + +unsigned char Port::byte() +{ + unsigned char byte = m_device->getByte(); + + if (m_logRaw == true && m_loggerRaw != NULL) + m_loggerRaw->log(bus, event, "%02x", byte); + + if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) { + m_dumpRawStream.write((char*)&byte, 1); + + if (m_dumpRawStream.tellp() >= m_dumpRawMaxSize * 1024) { + string oldfile = m_dumpRawFile + ".old"; + if (rename(m_dumpRawFile.c_str(), oldfile.c_str()) == 0) { + m_dumpRawStream.close(); + m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); + } + } + } + + return byte; +} + +void Port::setDumpRaw(bool dumpRaw) +{ + if (dumpRaw == m_dumpRaw) + return; + + m_dumpRaw = dumpRaw; + + if (dumpRaw == false) + m_dumpRawStream.close(); + else + m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); +} + +void Port::setDumpRawFile(const string& dumpFile) { + if (dumpFile == m_dumpRawFile) + return; + + m_dumpRawStream.close(); + m_dumpRawFile = dumpFile; + + if (m_dumpRaw == true) + m_dumpRawStream.open(m_dumpRawFile.c_str(), ios::out | ios::binary | ios::app); } void Port::setType(const DeviceType type) diff --git a/src/lib/ebus/port.h b/src/lib/ebus/port.h index 0dd82c85..9b833894 100644 --- a/src/lib/ebus/port.h +++ b/src/lib/ebus/port.h @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include "logger.h" +#include "result.h" using namespace std; @@ -64,7 +68,7 @@ public: * @param deviceName to determine device type. * @param noDeviceCheck en-/disable device check. */ - virtual void openDevice(const string deviceName, const bool noDeviceCheck) = 0; + virtual result_t openDevice(const string deviceName, const bool noDeviceCheck) = 0; /** * @brief virtual close function for closing opened file descriptor @@ -147,7 +151,7 @@ public: * @param deviceName to determine device type. * @param noDeviceCheck en-/disable device check. */ - void openDevice(const string deviceName, const bool noDeviceCheck); + virtual result_t openDevice(const string deviceName, const bool noDeviceCheck); /** * @brief close function for closing opened file descriptor @@ -177,7 +181,7 @@ public: * @param deviceName to determine device type. * @param noDeviceCheck en-/disable device check. */ - void openDevice(const string deviceName, const bool noDeviceCheck); + virtual result_t openDevice(const string deviceName, const bool noDeviceCheck); /** * @brief close opened file descriptor @@ -200,17 +204,18 @@ public: * @param deviceName to determine device type. * @param noDeviceCheck en-/disable device check. */ - Port(const string deviceName, const bool noDeviceCheck); + Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, Logger* loggerRaw, + const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize); /** * @brief destructor. */ - ~Port() { delete m_device; } + ~Port() { delete m_device; m_dumpRawStream.close(); } /** * @brief open device */ - void open() { m_device->openDevice(m_deviceName, m_noDeviceCheck); } + result_t open() { return m_device->openDevice(m_deviceName, m_noDeviceCheck); } /** * @brief close device @@ -234,7 +239,7 @@ public: /** * @brief recv read bytes from opened file descriptor. - * @param timeout max time out for new input data. + * @param timeout max time out for new input data [usec]. * @param maxCount max size of receive buffer. * @return number of read bytes or -1 if an error has occured. */ @@ -245,7 +250,7 @@ public: * @brief fetch first byte from receive buffer. * @return first byte (raw) */ - unsigned char byte() { return m_device->getByte(); } + unsigned char byte(); /** * @brief get current size (bytes) of the receive buffer. @@ -253,9 +258,45 @@ public: */ ssize_t size() const { return m_device->sizeRecvBuffer(); } + /** + * @brief Get whether logging of raw data is enabled. + * @return whether logging of raw data is enabled. + */ + bool getLogRaw() { return m_logRaw; } + + /** + * @brief Enable or disable logging of raw data. + * @param logRawData true to enable logging of raw data, false to disable it. + */ + void setLogRaw(bool logRaw=true) { m_logRaw = logRaw; } + + /** + * @brief Get whether dumping of raw data to a file is enabled. + * @return whether dumping of raw data to a file is enabled. + */ + bool getDumpRaw() { return m_dumpRaw; } + + /** + * @brief Enable or disable dumping of raw data to a file. + * @param dumpRaw true to enable dumping of raw data to a file, false to disable it. + */ + void setDumpRaw(bool dumpRaw=true); + + /** + * @brief Set the name of the file to dump raw data to. + * @param dumpFile the name of the file to dump raw data to. + */ + void setDumpRawFile(const string& dumpFile); + + /** + * @brief Set the maximum size of a file to dump raw data to. + * @param maxSize the maximum size of a file to dump raw data to. + */ + void setDumpRawMaxSize(const long maxSize) { m_dumpRawMaxSize = maxSize; } + private: /** the device name */ - string m_deviceName; + const string m_deviceName; /** the device instance */ Device* m_device; @@ -263,6 +304,24 @@ private: /** true if device check is disabled */ bool m_noDeviceCheck; + /** whether logging of raw data is enabled. */ + bool m_logRaw; + + /** the @a Logger used for logging of raw data, or NULL. */ + Logger* m_loggerRaw; + + /** whether dumping of raw data to a file is enabled. */ + bool m_dumpRaw; + + /** the name of the file to dump raw data to. */ + string m_dumpRawFile; + + /** the maximum size of @a m_dumpFile. */ + long m_dumpRawMaxSize; + + /** the @a ofstream for dumping raw data to. */ + ofstream m_dumpRawStream; + /** * @brief internal setter for device type. * @param type of device From 036036e626b1e5dbd3c11ab9b1ab80c72ce8a4e0 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:10:57 +0100 Subject: [PATCH 25/83] use result_t, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/lib/ebus/test/test_port.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ebus/test/test_port.cpp b/src/lib/ebus/test/test_port.cpp index ebdd8ea4..853f03db 100644 --- a/src/lib/ebus/test/test_port.cpp +++ b/src/lib/ebus/test/test_port.cpp @@ -26,7 +26,7 @@ using namespace std; int main () { string dev("/dev/ttyUSB20"); - Port port(dev, true); + Port port(dev, true, false, NULL, false, "", 1); port.open(); From d90dbe8507305c0134bf639a676347a5a90f2e19 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:13:25 +0100 Subject: [PATCH 26/83] introduced BusHandler for managing all possible message transfer types --- src/ebusd/bushandler.cpp | 281 +++++++++++++++++++++++++++++++++++++++ src/ebusd/bushandler.h | 163 +++++++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 src/ebusd/bushandler.cpp create mode 100644 src/ebusd/bushandler.h diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp new file mode 100644 index 00000000..5e1d06ad --- /dev/null +++ b/src/ebusd/bushandler.cpp @@ -0,0 +1,281 @@ +/* + * 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 "bushandler.h" +#include "message.h" +#include "data.h" +#include "result.h" +#include "symbol.h" +#include "appl.h" +#include +#include +#include + +using namespace std; + +extern Logger& L; +extern Appl& A; + +/** + * @brief Return the string corresponding to the @a BusState and send position. + * @param state the @a BusState. + * @param sendPos >=0 while sending data, -1 while receiving data. + * @return the string corresponding to the @a BusState. + */ +const char* getStateCode(BusState state, int sendPos) { + switch (state) + { + case bs_skip: return "skip"; + case bs_ready: return "ready"; + case bs_command: return sendPos < 0 ? "receive command" : "send command"; + case bs_commandAck: return sendPos < 0 ? "receive command ACK" : "send command ACK"; + case bs_response: return sendPos < 0 ? "receive response" : "send response"; + case bs_responseAck: return sendPos < 0 ? "receive response ACK" : "send response ACK"; + //case bs_validTransfer: return sendPos < 0 ? "after complete receive" : "after complete send"; + default: return "unknown state"; + } +} + + +void BusHandler::run() +{ + result_t result = RESULT_OK; + do { + if (m_port->isOpen() == true) { + result = receiveSymbol(); + + if (result != RESULT_OK) + L.log(bus, error, " %s", getResultCode(result)); + + } + else { + // TODO: define max reopen + sleep(10); + result = m_port->open(); + + if (result != RESULT_OK) + L.log(bus, error, "can't open %s", A.getOptVal("device")); + + } + + } while (isRunning() == true); +} + +result_t BusHandler::receiveSymbol() +{ + long timeout; + ssize_t count; + if (m_state == bs_skip) + timeout = 0; + else if (m_state == bs_ready) + timeout = SYN_TIMEOUT; + else if (m_sendPos >= 0) + timeout = SLAVE_RECV_TIMEOUT; + else + timeout = SYN_TIMEOUT; + + count = m_port->recv(timeout, 1); + + if (count < 0) + return setState(bs_skip, RESULT_ERR_DEVICE); + + if (count == 0) { + if (m_state == bs_ready) + return RESULT_OK; // TODO keep "no signal" within auto-syn state + return setState(bs_skip, RESULT_ERR_TIMEOUT); + } + + unsigned char symbol = m_port->byte(); + if (symbol == SYN) { + m_repeat = false; + return setState(bs_ready, RESULT_OK); + } + + unsigned char headerLen, crcPos; + result_t result; + + switch (m_state) + { + case bs_skip: + return RESULT_OK; + + case bs_ready: + if (symbol == ESC) + return setState(bs_skip, RESULT_ERR_ESC); + + result = m_command.push_back(symbol); + if (result < RESULT_OK) + return setState(bs_skip, result); + + return setState(bs_command, result); + + case bs_command: + headerLen = 4; + crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; + result = m_command.push_back(symbol, true, m_command.size() < crcPos); + if (result < RESULT_OK) + return setState(bs_skip, result); + + if (result == RESULT_OK && m_command.size() == crcPos + 1) { // CRC received + m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); + if (m_command[1] == BROADCAST) { + if (m_commandCrcValid) { + transferCompleted(tt_broadcast); + return setState(bs_skip, RESULT_OK); + } + + return setState(bs_skip, RESULT_ERR_CRC); + } + /*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) { + setState(bs_commandAck, RESULT_OK); + m_sendPos = 0; + symbol = m_commandCrcValid ? ACK : NAK; + if (m_port->send(&symbol) <= 0) + return setState(bs_skip, RESULT_ERR_SEND); + }*/ + return setState(bs_commandAck, RESULT_OK); + } + return result; + + case bs_commandAck: + if (symbol == ESC) + return setState(bs_skip, RESULT_ERR_ESC); + /*if (m_sendPos >= 0) { + if (symbol == ACK && m_commandCrcValid == true) + return setState(); + + return setState() + }*/ + if (symbol == ACK) { + if (m_commandCrcValid == false) + return setState(bs_skip, RESULT_ERR_ACK); + + if (isMaster(m_command[1]) == true) { + transferCompleted(tt_masterMaster); + return setState(bs_skip, RESULT_OK); + } + + return setState(bs_response, RESULT_OK); + } + if (symbol == NAK) { + if (m_repeat == false) { + m_repeat = true; + return setState(bs_ready, RESULT_ERR_NAK); + } + return setState(bs_skip, RESULT_ERR_NAK); + } + return setState(bs_skip, RESULT_ERR_ACK); + + case bs_response: + headerLen = 0; + crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff; + result = m_response.push_back(symbol, true, m_response.size() < crcPos); + if (result < RESULT_OK) + return setState(bs_skip, result); + + if (result == RESULT_OK && m_response.size() == crcPos + 1) { // CRC received + m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC(); + /*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) { + setState(bs_responseAck, RESULT_OK); + m_sendPos = 0; + symbol = m_responseCrcValid ? ACK : NAK; + if (m_port->send(&symbol) <= 0) + return setState(bs_skip, RESULT_ERR_SEND); + }*/ + return setState(bs_responseAck, RESULT_OK); + } + return result; + + case bs_responseAck: + if (symbol == ESC) + return setState(bs_skip, RESULT_ERR_ESC); + /*if (m_sendPos >= 0) { + if (symbol == ACK && m_responseCrcValid == true) + return setState(); + + return setState() + }*/ + if (symbol == ACK) { + if (m_responseCrcValid == false) + return setState(bs_skip, RESULT_ERR_ACK); + + transferCompleted(tt_masterSlave); + return setState(bs_skip, RESULT_OK); + } + if (symbol == NAK) { + if (m_repeat == false) { + m_repeat = true; + return setState(bs_response, RESULT_ERR_NAK); + } + return setState(bs_skip, RESULT_ERR_NAK); + } + return setState(bs_skip, RESULT_ERR_ACK); + } + + return RESULT_OK; +} + +result_t BusHandler::setState(BusState state, result_t result) +{ + if (state == m_state) + return result; + + if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) + L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state, m_sendPos), getStateCode(state, m_sendPos)); + + m_state = state; + if (state == bs_ready || state == bs_skip) { + m_command.clear(); + m_commandCrcValid = false; + m_response.clear(); + m_responseCrcValid = false; + m_sendPos = -1; + } + if (state == bs_skip) + m_repeat = false; + + return result; +} + +void BusHandler::transferCompleted(TransferType type) +{ + switch (type) + { + case tt_broadcast: + L.log(bus, trace, "received broadcast %s", m_command.getDataStr().c_str()); + break; + case tt_masterMaster: + L.log(bus, trace, "received master %s", m_command.getDataStr().c_str()); + break; + case tt_masterSlave: + L.log(bus, trace, "received master %s, slave %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); + break; + default: + return; + } + Message* msg = m_messages->find(m_command); + if (msg != NULL) { + ostringstream output; + result_t result = msg->decode(m_command, m_response, output); + if (result != RESULT_OK) + L.log(bus, error, "unable to parse %s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), getResultCode(result)); + else + L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); + } +} diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h new file mode 100644 index 00000000..52a5e48f --- /dev/null +++ b/src/ebusd/bushandler.h @@ -0,0 +1,163 @@ +/* + * 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_BUSHANDLER_H_ +#define LIBEBUS_BUSHANDLER_H_ + +#include "message.h" +#include "data.h" +#include "symbol.h" +#include "result.h" +#include "port.h" +#include "thread.h" +#include +#include +#include + +using namespace std; + +/** the maximum allowed time [us] for retrieval of a single symbol from an addressed slave. */ +#define SLAVE_RECV_TIMEOUT 10000 +/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol. */ +#define SYN_TIMEOUT 50000 + +/** the possible bus states. */ +enum BusState { + bs_skip, // skip all symbols until next @a SYN + bs_ready, // ready for next master (after @a SYN symbol, send/receive QQ) + bs_command, // receive/send command (ZZ, PBSB, master data) + bs_commandAck, // receive/send command ACK/NACK + bs_response, // receive/send response (slave data) + bs_responseAck, // receive/send response ACK/NACK + //bs_validTransfer,// completed a valid message transfer +}; + +/** the possible message transfer types. */ +enum TransferType { + tt_broadcast, // broadcast transfer + tt_masterMaster, // master to master transfer + tt_masterSlave // master to slave transfer +}; + +/** the possible combinations of participants in a single message exchange. */ +enum MessageDirection { + md_thisToAll, // message from us to all (broadcast) + md_thisToMaster, // message from us to another master + md_thisToSlave, // message from us to another slave + md_otherToAll, // message from a master (other than us) to all (broadcast): @a bs_ready, @a bs_recvCmd + md_otherToMaster, // message from a master (other than us) to another master (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck + md_otherToSlave, // message from a master (other than us) to another slave (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck, @a bs_recvResp, @a bs_recvAck + md_otherToThisMaster, // message from a master (other than us) to us (as master) + md_otherToThisSlave, // message from a master (other than us) to us (as slave) + md_undefined, +}; + + +/** + * @brief Handles input from and output to the bus with respect to the ebus protocol. + */ +class BusHandler : public Thread +{ +public: + + /** + * @brief Construct a new instance. + * @param port the @a Port instance for accessing the bus. + * @param messages the @a MessageMap instance with all known @a Message instances. + * @param ownMasterAddress the own master address to react on master-master messages, or @a SYN to ignore. + * @param ownSlaveAddress the own slave address to react on master-slave messages, or @a SYN to ignore. + */ + BusHandler(Port* port, MessageMap* messages, unsigned char ownMasterAddress, + unsigned char ownSlaveAddress) + : m_port(port), m_messages(messages), m_ownMasterAddress(ownMasterAddress), + m_ownSlaveAddress(ownSlaveAddress), m_state(bs_skip), m_repeat(false), + m_sendPos(-1), m_commandCrcValid(false), m_responseCrcValid(false) {} + + /** + * @brief Destructor. + */ + virtual ~BusHandler() {} + + /** + * @brief Main thread entry. + */ + virtual void run(); + +private: + + /** + * @brief Receive another symbol from the bus. + * @return RESULT_OK on success, or an error code. + */ + result_t receiveSymbol(); + + /** + * @brief Set a new @a BusState and add a log message if necessary. + * @param state the new @a BusState. + * @param result the result code. + * @return the result code. + */ + result_t setState(BusState state, result_t result); + + /** + * @brief Called when a transfer was successfully completed. + * @param type the @a TransferType. + */ + void transferCompleted(TransferType type); + + /** the @a Port instance for accessing the bus. */ + Port* m_port; + + /** the @a MessageMap instance with all known @a Message instances. */ + MessageMap* m_messages; + + /** the own master address to react on master-master messages, or @a SYN to ignore. */ + unsigned char m_ownMasterAddress; + + /** the own slave address to react on master-slave messages, or @a SYN to ignore. */ + unsigned char m_ownSlaveAddress; + + /** the current @a BusState. */ + BusState m_state; + + /** whether the current message part is being repeated. */ + bool m_repeat; + + /* + * the offset of the last sent symbol while sending command/response, + * or 0 while sending ACK/NACK, or -1 if not sending. + */ + int m_sendPos; + + /** the received/sent command. */ + SymbolString m_command; + + /** whether the command CRC is valid. */ + bool m_commandCrcValid; + + /** the received/sent response. */ + SymbolString m_response; + + /** whether the response CRC is valid. */ + bool m_responseCrcValid; + +}; + + +#endif // LIBEBUS_BUSHANDLER_H_ From ab3508c187bce50689bc26464146fa2dcc699d3e Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:15:06 +0100 Subject: [PATCH 27/83] start switching to BusHandler and MessageMap, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/ebusd/Makefile.am | 4 +- src/ebusd/baseloop.cpp | 138 ++++++++++++++++++++++++++++++----------- src/ebusd/baseloop.h | 24 ++++--- 3 files changed, 121 insertions(+), 45 deletions(-) diff --git a/src/ebusd/Makefile.am b/src/ebusd/Makefile.am index b99b0495..2a1ab2a5 100644 --- a/src/ebusd/Makefile.am +++ b/src/ebusd/Makefile.am @@ -6,8 +6,8 @@ AM_CXXFLAGS = -fpic \ bin_PROGRAMS = ebusd -ebusd_SOURCES = busloop.cpp \ - busloop.h \ +ebusd_SOURCES = bushandler.cpp \ + bushandler.h \ network.cpp \ network.h \ baseloop.cpp \ diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 6bcf1958..fbab60c8 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -18,9 +18,9 @@ */ #include "baseloop.h" -#include "configfile.h" #include "logger.h" #include "appl.h" +#include using namespace std; @@ -30,15 +30,42 @@ extern Appl& A; BaseLoop::BaseLoop() { // create commands DB - m_commands = ConfigCommands(A.getOptVal("ebusconfdir"), ft_csv).getCommands(); - L.log(bas, trace, "ebus configuration dir: %s", A.getOptVal("ebusconfdir")); - L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB()); - L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); - L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB()); + m_templates = new DataFieldTemplates(); + m_messages = new MessageMap(); - // create busloop - m_busloop = new BusLoop(m_commands); - m_busloop->start("busloop"); + string confdir = A.getOptVal("ebusconfdir"); + L.log(bas, trace, "ebus configuration dir: %s", confdir.c_str()); + result_t result = m_templates->readFromFile(confdir+"/_types.csv"); + if (result == RESULT_OK) + L.log(bas, trace, "read templates"); + else + L.log(bas, error, "error reading templates: %s", getResultCode(result)); + result = readConfigFiles(confdir, ".csv"); + if (result == RESULT_OK) + L.log(bas, trace, "read config files"); + else + L.log(bas, error, "error reading config files: %s", getResultCode(result)); + + /*L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB()); + L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); + L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());*/ + + const bool logRaw = A.getOptVal("lograwdata"); + + const bool dumpRaw = A.getOptVal("dump"); + const char* dumpRawFile = A.getOptVal("dumpfile"); + const long dumpRawMaxSize = A.getOptVal("dumpsize"); + + // create Port + m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &L, dumpRaw, dumpRawFile, dumpRawMaxSize); + m_port->open(); + + if (m_port->isOpen() == false) + L.log(bus, error, "can't open %s", A.getOptVal("device")); + + // create BusHandler + m_busHandler = new BusHandler(m_port, m_messages, SYN, SYN); // TODO + m_busHandler->start("bushandler"); // create network m_network = new Network(A.getOptVal("localhost"), &m_netQueue); @@ -47,22 +74,63 @@ BaseLoop::BaseLoop() BaseLoop::~BaseLoop() { - // free network if (m_network != NULL) delete m_network; - // free busloop - if (m_busloop != NULL) { - m_busloop->stop(); - m_busloop->join(); - delete m_busloop; + if (m_busHandler != NULL) { + m_busHandler->stop(); + m_busHandler->join(); + delete m_busHandler; } - // free commands DB - if (m_commands != NULL) - delete m_commands; + if (m_port != NULL) + delete m_port; + + if (m_messages != NULL) + delete m_messages; + + if (m_templates != NULL) + delete m_templates; } +result_t BaseLoop::readConfigFiles(const string path, const string extension) +{ + DIR* dir = opendir(path.c_str()); + + if (dir == NULL) + return RESULT_ERR_FILENOTFOUND; + + dirent* d = readdir(dir); + + while (d != NULL) { + if (d->d_type == DT_DIR) { + string fn = d->d_name; +//std::cout << "found dir " << fn << endl; + if (fn != "." && fn != "..") { + const string p = path + "/" + d->d_name; + result_t result = readConfigFiles(p, extension); + if (result != RESULT_OK) + return result; + } + } else if (d->d_type == DT_REG) { + string fn = d->d_name; +//std::cout << "found file " << fn << endl; + if (fn.find(extension, (fn.length() - extension.length())) != string::npos + && fn != "_types" + extension) { + const string p = path + "/" + d->d_name; + result_t result = m_messages->readFromFile(p, m_templates); + if (result != RESULT_OK) + return result; + } + } + + d = readdir(dir); + } + closedir(dir); + + return RESULT_OK; +}; + void BaseLoop::start() { for (;;) { @@ -100,7 +168,7 @@ string BaseLoop::decodeMessage(const string& data) { ostringstream result; string cycdata, polldata; - int index; + Message* message; // prepare data string token; @@ -118,15 +186,15 @@ string BaseLoop::decodeMessage(const string& data) result << "command not found"; break; - case ct_get: + /*case ct_get: if (cmd.size() < 3 || cmd.size() > 4) { result << "usage: 'get class cmd (sub)'"; break; } - index = m_commands->findCommand(data); + message = m_messages->find(cmd[1], cmd[2], true, false); - if (index >= 0) { + if (message != NULL) { // polling data if (strcasecmp(m_commands->getCmdType(index).c_str(), "P") == 0) { @@ -176,9 +244,9 @@ string BaseLoop::decodeMessage(const string& data) result << "ebus command not found"; } - break; + break;*/ - case ct_set: + /*case ct_set: if (cmd.size() != 4) { result << "usage: 'set class cmd value'"; break; @@ -231,9 +299,9 @@ string BaseLoop::decodeMessage(const string& data) result << "ebus command not found"; } - break; + break;*/ - case ct_cyc: + /*case ct_cyc: if (cmd.size() < 3 || cmd.size() > 4) { result << "usage: 'cyc class cmd (sub)'"; break; @@ -259,9 +327,9 @@ string BaseLoop::decodeMessage(const string& data) result << "ebus command not found"; } - break; + break;*/ - case ct_hex: + /*case ct_hex: if (cmd.size() != 2) { result << "usage: 'hex value' (value: ZZPBSBNNDx)"; break; @@ -289,9 +357,9 @@ string BaseLoop::decodeMessage(const string& data) delete message; } - break; + break;*/ - case ct_scan: + /*case ct_scan: if (cmd.size() == 1) { m_busloop->scan(); result << "done"; @@ -315,7 +383,7 @@ string BaseLoop::decodeMessage(const string& data) result << "usage: 'scan'" << endl << " 'scan full'" << endl << " 'scan result'"; - break; + break;*/ case ct_log: if (cmd.size() != 3 ) { @@ -348,7 +416,7 @@ string BaseLoop::decodeMessage(const string& data) break; } - m_busloop->raw(); + m_port->setLogRaw(!m_port->getLogRaw()); result << "done"; break; @@ -358,11 +426,11 @@ string BaseLoop::decodeMessage(const string& data) break; } - m_busloop->dump(); + m_port->setDumpRaw(!m_port->getDumpRaw()); result << "done"; break; - case ct_reload: + /*case ct_reload: if (cmd.size() != 1) { result << "usage: 'reload'"; break; @@ -382,7 +450,7 @@ string BaseLoop::decodeMessage(const string& data) result << "done"; break; - } + }*/ case ct_help: result << "commands:" << endl diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index d45556ba..b058130a 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -20,9 +20,9 @@ #ifndef BASELOOP_H_ #define BASELOOP_H_ -#include "commands.h" +#include "message.h" #include "network.h" -#include "busloop.h" +#include "bushandler.h" using namespace std; @@ -51,7 +51,7 @@ class BaseLoop public: /** - * @brief construct the baseloop and creates commads, network and busloop subsystems. + * @brief construct the baseloop and creates messaging, network and busloop subsystems. */ BaseLoop(); @@ -60,6 +60,7 @@ public: */ ~BaseLoop(); + result_t readConfigFiles(const string path, const string extension); /** * @brief start baseloop instance. */ @@ -72,13 +73,20 @@ public: void addMessage(NetMessage* message) { m_netQueue.add(message); } private: - /** the commands instance */ - Commands* m_commands; - /** the busloop instance */ - BusLoop* m_busloop; + /** the @a DataFieldTemplates instance. */ + DataFieldTemplates* m_templates; - /** the network instance */ + /** the @a MessageMap instance. */ + MessageMap* m_messages; + + /** the @a Port instance. */ + Port* m_port; + + /** the @a BusHandler instance. */ + BusHandler* m_busHandler; + + /** the @a Network instance. */ Network* m_network; /** queue for network messages */ From 9affddf19bfc531f0b483a0602479347251d5abf Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:10:57 +0100 Subject: [PATCH 28/83] use result_t, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/ebusctl/Makefile.am | 0 src/ebusctl/ebusctl.cpp | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/ebusctl/Makefile.am diff --git a/src/ebusctl/Makefile.am b/src/ebusctl/Makefile.am old mode 100644 new mode 100755 diff --git a/src/ebusctl/ebusctl.cpp b/src/ebusctl/ebusctl.cpp index da642266..6ada8b46 100644 --- a/src/ebusctl/ebusctl.cpp +++ b/src/ebusctl/ebusctl.cpp @@ -23,7 +23,7 @@ #include "appl.h" #include "port.h" -#include "decode.h" +#include "data.h" #include "tcpsocket.h" #include #include @@ -69,7 +69,7 @@ int main(int argc, char* argv[]) if (strcasecmp(A.getArg(0).c_str(), "feed") == 0) { string dev(A.getOptVal("device")); - Port port(dev, true); + Port port(dev, true, false, NULL, false, "", 1); port.open(); if(port.isOpen() == true) { From 0f2fb3c27e86a1cae4d9d69924ccbbd8ef62b6f1 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:10:57 +0100 Subject: [PATCH 29/83] use result_t, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/lib/utils/Makefile.am | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/lib/utils/Makefile.am diff --git a/src/lib/utils/Makefile.am b/src/lib/utils/Makefile.am old mode 100644 new mode 100755 From f94c981bdc3ba887b9c2c3aea90144abbc785214 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Nov 2014 20:10:57 +0100 Subject: [PATCH 30/83] use result_t, move raw logging and dumping to Port and avoid permanent open/close on ofstream --- src/lib/ebus/test/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/lib/ebus/test/Makefile.am diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am old mode 100644 new mode 100755 index 56cdfd8c..4570f354 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -1,7 +1,8 @@ AM_CXXFLAGS = -fpic \ -Wall \ -Wextra \ - -I$(top_srcdir)/src/lib/ebus + -I$(top_srcdir)/src/lib/ebus \ + -I$(top_srcdir)/src/lib/utils noinst_PROGRAMS = test_port \ test_symbol \ @@ -9,7 +10,8 @@ noinst_PROGRAMS = test_port \ test_message test_port_SOURCES = test_port.cpp -test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a +test_port_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ + $(top_srcdir)/src/lib/ebus/libebus.a test_symbol_SOURCES = test_symbol.cpp test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a From fb3574de8c6a985efc6599797a9362e59d61ff05 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 10:22:36 +0100 Subject: [PATCH 31/83] added defaults, added printErrorPos --- src/lib/ebus/data.cpp | 28 +++++++++++++++++++++++++++- src/lib/ebus/data.h | 33 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index f619a757..2af7a240 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -95,6 +95,32 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co return ret; } +void printErrorPos(vector::iterator begin, const vector::iterator end, vector::iterator pos, char separator) +{ + cout << "Erroneous item is here:" << endl; + bool first = true; + int cnt = 0; + if (pos > begin) + pos--; + while (begin != end) { + if (first == true) + first = false; + else { + cout << separator; + if (begin <= pos) { + cnt++; + } + } + if (begin < pos) { + cnt += (*begin).length(); + } + cout << (*begin++); + } + cout << endl; + cout << setw(cnt) << " " << setw(0) << "^" << endl; +} + + result_t DataField::create(vector::iterator& it, const vector::iterator end, DataFieldTemplates* templates, @@ -1060,7 +1086,7 @@ result_t DataFieldTemplates::add(DataField* field, bool replace) return RESULT_OK; } -result_t DataFieldTemplates::addFromFile(vector& row, void* arg) +result_t DataFieldTemplates::addFromFile(vector& row, void* arg, vector< vector >* defaults) { DataField* field = NULL; vector::iterator it = row.begin(); diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 8117a9da..a62de4e3 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -83,6 +83,15 @@ typedef struct { */ unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL); +/** + * @brief Print the error position of the iterator to stdout. + * @param begin the iterator to the beginning of the items. + * @param end the iterator to the end of the items. + * @param pos the iterator with the erroneous position. + * @param separator the character to place between items. + */ +void printErrorPos(vector::iterator begin, const vector::iterator end, vector::iterator pos, char separator=';'); + class DataFieldTemplates; class SingleDataField; @@ -152,7 +161,9 @@ public: /** * @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 additional offset to add for reading the master data. * @param slaveData the unescaped slave data @a SymbolString for reading binary data. + * @param slaveOffset the additional offset to add for reading the slave data. * @param output the @a ostringstream to append the formatted value to. * @param verbose whether to prepend the name, append the unit (if present), and append * the comment in square brackets (if present). @@ -570,7 +581,8 @@ public: /** * @brief Constructs a new instance. */ - FileReader() {} + FileReader(bool supportsDefaults) + : m_supportsDefaults(supportsDefaults) {} /** * @brief Destructor. */ @@ -591,6 +603,7 @@ public: unsigned int lineNo = 0; vector row; string token; + vector< vector > defaults; while (getline(ifs, line) != 0) { lineNo++; // skip empty lines and comments @@ -601,7 +614,12 @@ public: while (getline(isstr, token, FIELD_SEPARATOR) != 0) row.push_back(token); - result_t result = addFromFile(row, arg); + if (m_supportsDefaults == true && line.substr(0, 1) == "*") { + row[0] = row[0].substr(1); + defaults.push_back(row); + continue; + } + result_t result = addFromFile(row, arg, m_supportsDefaults == true ? &defaults : NULL); if (result != RESULT_OK) { cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; ifs.close(); @@ -615,9 +633,14 @@ public: /** * @brief Adds a definition that was read from a file. * @param row the definition row read from the file. + * @param defaults all previously read default rows (initial star char removed), or NULL if not supported. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t addFromFile(vector& row, T arg) = 0; + virtual result_t addFromFile(vector& row, T arg, vector< vector >* defaults) = 0; + +private: + /** whether this instance supports rows with defaults (starting with a star). */ + bool m_supportsDefaults; }; @@ -632,7 +655,7 @@ public: /** * @brief Constructs a new instance. */ - DataFieldTemplates() {} + DataFieldTemplates() : FileReader(false) {} /** * @brief Destructor. */ @@ -650,7 +673,7 @@ public: */ result_t add(DataField* message, bool replace=false); // @copydoc - virtual result_t addFromFile(vector& row, void* arg); + virtual result_t addFromFile(vector& row, void* arg, vector< vector >* defaults); /** * @brief Gets the template @a DataField instance with the specified name. * @return the template @a DataField instance, or NULL. From 43b50875f9ad1a9d3722fb8e02c0be34e26144d4 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 10:23:50 +0100 Subject: [PATCH 32/83] added defaults, allow poll priority as number only, verbose print csv error position, splitted id into pbsb+id again, moved printErrorPos to data.h --- src/lib/ebus/message.cpp | 171 +++++++++++++++++++++-------- src/lib/ebus/message.h | 6 +- src/lib/ebus/test/test_message.cpp | 41 ++----- 3 files changed, 140 insertions(+), 78 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index a30a0a6b..7f736d45 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -49,13 +49,31 @@ Message::Message(const string clazz, const string name, const bool isSet, m_key = key; } +/** + * @brief Helper method for getting a default if the value is empty. + * @param value the value to check. + * @param defaults a @a verctor of defaults, or NULL. + * @param pos the position in defaults. + * @return the default if available and value is empty, or the value. + */ +string getDefault(string value, vector* defaults, size_t pos) +{ + if (value.length() > 0 || defaults == NULL || pos > defaults->size()) { + return value; + } + + string ret = defaults->at(pos); + return ret; +} + result_t Message::create(vector::iterator& it, const vector::iterator end, - DataFieldTemplates* templates, Message*& returnValue) + vector* defaults, DataFieldTemplates* templates, Message*& returnValue) { // [type];[class];name;[comment];[QQ];ZZ;id;fields... result_t result; bool isSet, isActive; unsigned int pollPriority = 0; + size_t defaultPos = 1; if (it == end) return RESULT_ERR_EOF; @@ -68,7 +86,7 @@ result_t Message::create(vector::iterator& it, const vector::ite } else if (str[0] == 'C' || str[0] == 'c') { isActive = false; isSet = str[1] == 'W' || str[1] == 'w'; - } else if (str[0] == 'P' || str[0] == 'p') { + } else if (str[0] == 'P' || str[0] == 'p') { // poll priority isActive = true; isSet = false; if (str[1] == 0) @@ -79,12 +97,19 @@ result_t Message::create(vector::iterator& it, const vector::ite if (result != RESULT_OK) return result; } - } else { + } else if (str[0] >= '0' && str[0] <= '9') { // poll priority + isActive = true; + isSet = false; + result_t result; + pollPriority = parseInt(str, 10, 1, 9, result); + if (result != RESULT_OK) + return result; + } else { // default "r" isActive = true; isSet = false; } - string clazz = *it++; + string clazz = getDefault(*it++, defaults, defaultPos++); if (it == end) return RESULT_ERR_EOF; @@ -93,17 +118,18 @@ result_t Message::create(vector::iterator& it, const vector::ite return RESULT_ERR_EOF; if (name.length() == 0) return RESULT_ERR_INVALID_ARG; // empty name + defaultPos++; - string comment = *it++; + string comment = getDefault(*it++, defaults, defaultPos++); if (it == end) return RESULT_ERR_EOF; - str = (*it++).c_str(); + str = getDefault(*it++, defaults, defaultPos++).c_str(); if (it == end) return RESULT_ERR_EOF; unsigned char srcAddress; - if (*str == 0 || isActive == true) - srcAddress = SYN; // no specific source defined, or ignore for active message + if (*str == 0) + srcAddress = SYN; // no specific source defined else { srcAddress = parseInt(str, 16, 0, 0xff, result); if (result != RESULT_OK) @@ -112,7 +138,7 @@ result_t Message::create(vector::iterator& it, const vector::ite return RESULT_ERR_INVALID_ARG; } - str = (*it++).c_str(); + str = getDefault(*it++, defaults, defaultPos++).c_str(); if (it == end) return RESULT_ERR_EOF; @@ -122,35 +148,74 @@ result_t Message::create(vector::iterator& it, const vector::ite if (isValidAddress(dstAddress) == false) return RESULT_ERR_INVALID_ARG; - istringstream input(*it++); // message id (PBSB + optional master data) vector id; - 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()); + for (int pos=0, useDefaults=1; pos<2; pos++) { // message id (PBSB, optional master data) + string token = *it++; + if (useDefaults == 1) { + if (pos == 0 && token.size() > 0) { + useDefaults = false; + } else { + token.append(getDefault("", defaults, defaultPos)); + } + } + istringstream input(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); + 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 (pos == 0 && id.size() != 2) { + return RESULT_ERR_INVALID_ARG; // missing/too short/too PBSB + } + defaultPos++; } - if (id.size() < 2 || id.size() > 6) + if (id.size() < 2 || id.size() > 6) { return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID + } + vector::iterator realEnd = end; + if (defaults!=NULL && defaults->size() > defaultPos + 3) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]") + vector newTypes; + while (defaults->at(defaultPos + 3).size() > 0) { + for (size_t i = 0; i < 6; i++) { + if (defaults->size() > defaultPos) + newTypes.push_back(defaults->at(defaultPos)); + else + newTypes.push_back(""); + + defaultPos++; + } + if (defaults->size() <= defaultPos + 3) + break; + } + if (newTypes.size() > 0) { + while (it != end) { + newTypes.push_back(*it++); + } + it = newTypes.begin(); + realEnd = newTypes.end(); + } + } DataField* data = NULL; - result = DataField::create(it, end, templates, data, isSet, dstAddress); - if (result != RESULT_OK) + result = DataField::create(it, realEnd, templates, data, isSet, dstAddress); + if (result != RESULT_OK) { return result; - + } returnValue = new Message(clazz, name, isSet, isActive, comment, srcAddress, dstAddress, id, data, pollPriority); return RESULT_OK; } @@ -201,14 +266,16 @@ result_t MessageMap::add(Message* message) else key.append(";C"); map::iterator nameIt = m_messagesByName.find(key); - if (nameIt != m_messagesByName.end()) - return RESULT_ERR_INVALID_ARG; // duplicate key + if (nameIt != m_messagesByName.end()) { + return RESULT_ERR_DUPLICATE; // duplicate key + } if (message->isActive() == false) { unsigned long long pkey = message->getKey(); map::iterator keyIt = m_passiveMessagesByKey.find(pkey); - if (keyIt != m_passiveMessagesByKey.end()) + if (keyIt != m_passiveMessagesByKey.end()) { return RESULT_ERR_DUPLICATE; // duplicate key + } unsigned char idLength = message->getId().size() - 2; if (idLength > m_maxIdLength) @@ -221,18 +288,36 @@ result_t MessageMap::add(Message* message) return RESULT_OK; } -result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg) +result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, vector< vector >* defaults) { Message* message = NULL; - vector::iterator it = row.begin(); - result_t result = Message::create(it, row.end(), arg, message); - if (result != RESULT_OK) - return result; - - result = add(message); - if (result != RESULT_OK) - delete message; + string types = row[0]; + if (types.length() == 0) + types.append("r"); + result_t result = RESULT_ERR_EOF; + for (size_t i=0; i* defaultRow = NULL; + if (defaults != NULL && defaults->size() > 0) { + for (vector< vector >::reverse_iterator it = defaults->rbegin(); it != defaults->rend(); it++) { + if ((*it)[0] == type || (type[0] >= '0' && type[0] <= '9' && ((*it)[0][0] == 'r' && (*it)[0][0] == 'R'))) { + defaultRow = &(*it); + break; + } + } + } + vector::iterator it = row.begin(); + result = Message::create(it, row.end(), defaultRow, arg, message); + if (result != RESULT_OK) { + printErrorPos(row.begin(), row.end(), it); + return result; + } + result = add(message); + if (result != RESULT_OK) { + delete message; + } + } return result; } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a36674fd..6863570d 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -64,12 +64,14 @@ public: * @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 defaults a @a vector with known default values, or NULL. * @param templates the @a DataFieldTemplates to be referenced by name, or NULL. * @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(vector::iterator& it, const vector::iterator end, + vector* defaults, DataFieldTemplates*, Message*& returnValue); /** * @brief Get the optional device class. @@ -183,7 +185,7 @@ public: /** * @brief Constructs a new instance. */ - MessageMap() : m_maxIdLength(0) {} + MessageMap() : FileReader(true), m_maxIdLength(0) {} /** * @brief Destructor. */ @@ -196,7 +198,7 @@ public: */ result_t add(Message* message); // @copydoc - virtual result_t addFromFile(vector& row, DataFieldTemplates* arg); + virtual result_t addFromFile(vector& row, DataFieldTemplates* arg, vector< vector >* defaults); /** * @brief Finds the @a Message instance for the specified class and name. * @param master the master @a SymbolString for identifying the @a Message. diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 389d845f..204f3afc 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -41,42 +41,17 @@ void verify(bool expectFailMatch, string type, string input, << gotStr << "<, expected >" << expectStr << "<" << endl; } -void printErrorPos(vector::iterator it, const vector::iterator end, vector::iterator pos) -{ - cout << "Erroneous item is here:" << endl; - bool first = true; - int cnt = 0; - if (pos > it) - pos--; - while (it != end) { - if (first == true) - first = false; - else { - cout << ';'; - if (it <= pos) { - cnt++; - } - } - if (it < pos) { - cnt += (*it).length(); - } - cout << (*it++); - } - cout << endl; - cout << setw(cnt) << " " << setw(0) << "^" << endl; -} - int main() { // message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields... // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, - {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, - {"r;ehp;time;;;08;b5090d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, - {"r;ehp;date;;;08;b5090d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, - {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B50929BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, + {"c;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, + {"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, + {"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, + {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, + {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, }; DataFieldTemplates* templates = new DataFieldTemplates(); result_t result = templates->readFromFile("_types.csv"); @@ -86,13 +61,13 @@ int main() cout << "read templates error: " << getResultCode(result) << endl; MessageMap* messages = new MessageMap(); - result = messages->readFromFile("ehp00.csv", templates); + result = messages->readFromFile("neu-ehp00.csv", templates); if (result == RESULT_OK) cout << "read messages OK" << endl; else cout << "read messages error: " << getResultCode(result) << endl; - Message *message = NULL; + Message* message = NULL; Message* deleteMessage = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; @@ -116,7 +91,7 @@ int main() deleteMessage = NULL; } vector::iterator it = entries.begin(); - result_t result = Message::create(it, entries.end(), templates, deleteMessage); + result_t result = Message::create(it, entries.end(), NULL, templates, deleteMessage); if (failedCreate == true) { if (result == RESULT_OK) From 4649d74fa4100f60d5b25e170cf393635a4364be Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 10:24:39 +0100 Subject: [PATCH 33/83] removed commented code --- src/ebusd/baseloop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index fbab60c8..715b8221 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -105,7 +105,7 @@ result_t BaseLoop::readConfigFiles(const string path, const string extension) while (d != NULL) { if (d->d_type == DT_DIR) { string fn = d->d_name; -//std::cout << "found dir " << fn << endl; + if (fn != "." && fn != "..") { const string p = path + "/" + d->d_name; result_t result = readConfigFiles(p, extension); @@ -114,7 +114,7 @@ result_t BaseLoop::readConfigFiles(const string path, const string extension) } } else if (d->d_type == DT_REG) { string fn = d->d_name; -//std::cout << "found file " << fn << endl; + if (fn.find(extension, (fn.length() - extension.length())) != string::npos && fn != "_types" + extension) { const string p = path + "/" + d->d_name; From 31145bb05777f15e2b6f149cc121e85ff2559ba5 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:02:16 +0100 Subject: [PATCH 34/83] added check for decode via loaded MessageMap --- src/lib/ebus/test/test_message.cpp | 141 +++++++++++++++++------------ 1 file changed, 82 insertions(+), 59 deletions(-) diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 204f3afc..63eb475e 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -47,11 +47,13 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {"c;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, + {"u;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, {"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, {"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, - {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, + {"u;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "pm"}, + {"","55.50;ok","1025b50903290000","050000780300",""}, + }; DataFieldTemplates* templates = new DataFieldTemplates(); result_t result = templates->readFromFile("_types.csv"); @@ -90,69 +92,90 @@ int main() delete deleteMessage; deleteMessage = NULL; } - vector::iterator it = entries.begin(); - result_t result = Message::create(it, entries.end(), NULL, templates, deleteMessage); - - if (failedCreate == true) { - if (result == RESULT_OK) - cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; - else - cout << "\"" << check[0] << "\": failed create OK" << endl; - continue; - } - if (result != RESULT_OK) { - cout << "\"" << check[0] << "\": create error: " - << getResultCode(result) << endl; - printErrorPos(entries.begin(), entries.end(), it); - continue; - } - if (deleteMessage == NULL) { - cout << "\"" << check[0] << "\": create error: NULL" << endl; - continue; - } - if (it != entries.end()) { - cout << "\"" << check[0] << "\": create error: trailing input" << endl; - continue; - } - cout << "\"" << check[0] << "\": create OK" << endl; - - if (dontMap == false) { - result = messages->add(deleteMessage); + if (entries.size() == 0) { + message = messages->find(mstr); + if (message == NULL) { + cout << " find error: NULL" << endl; + continue; + } + cout << " find OK" << endl; + } else { + vector::iterator it = entries.begin(); + result = Message::create(it, entries.end(), NULL, templates, deleteMessage); + if (failedCreate == true) { + if (result == RESULT_OK) + cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; + else + cout << "\"" << check[0] << "\": failed create OK" << endl; + continue; + } if (result != RESULT_OK) { - cout << "\"" << check[0] << "\": add error: " + cout << "\"" << check[0] << "\": create error: " + << getResultCode(result) << endl; + printErrorPos(entries.begin(), entries.end(), it); + continue; + } + if (deleteMessage == NULL) { + cout << "\"" << check[0] << "\": create error: NULL" << endl; + continue; + } + if (it != entries.end()) { + cout << "\"" << check[0] << "\": create error: trailing input" << endl; + continue; + } + cout << "\"" << check[0] << "\": create OK" << endl; + if (dontMap == false) { + result_t result = messages->add(deleteMessage); + if (result != RESULT_OK) { + cout << "\"" << check[0] << "\": add error: " + << getResultCode(result) << endl; + continue; + } + cout << " map OK" << endl; + message = deleteMessage; + deleteMessage = NULL; + if (messages->find(mstr) == message) + cout << " find OK" << endl; + else + cout << " find error: NULL" << endl; + } + else + message = deleteMessage; + } + istringstream input(inputStr); + SymbolString writeMstr = SymbolString(); + if (message->isPassive() == true) { + ostringstream output; + result = message->decode(mstr, sstr, output); + if (result != RESULT_OK) { + cout << " \"" << inputStr << "\": decode error: " << getResultCode(result) << endl; continue; } - cout << " map OK" << endl; - message = deleteMessage; - deleteMessage = NULL; - if (messages->find(mstr) == message) - cout << " find OK" << endl; - else - cout << " find error: NULL" << endl; - } - else - message = deleteMessage; - istringstream input(inputStr); - SymbolString writeMstr = SymbolString(); - result = message->prepare(0xff, writeMstr, input); - if (failedPrepare == true) { - if (result == RESULT_OK) - cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; - else - cout << " \"" << inputStr << "\": failed prepare OK" << endl; - continue; - } + cout << " \"" << inputStr << "\": decode OK" << endl; - if (result != RESULT_OK) { - cout << " \"" << inputStr << "\": prepare error: " - << getResultCode(result) << endl; - continue; - } - cout << " \"" << inputStr << "\": prepare OK" << endl; + bool match = inputStr == output.str(); + verify(false, "decode", check[2] + "/" + check[3], match, inputStr, output.str()); + } else { + result = message->prepareMaster(0xff, writeMstr, input); + if (failedPrepare == true) { + if (result == RESULT_OK) + cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; + else + cout << " \"" << inputStr << "\": failed prepare OK" << endl; + continue; + } - bool match = writeMstr==mstr; - verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); + if (result != RESULT_OK) { + cout << " \"" << inputStr << "\": prepare error: " + << getResultCode(result) << endl; + continue; + } + cout << " \"" << inputStr << "\": prepare OK" << endl; + + bool match = writeMstr==mstr; + verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); + } } if (deleteMessage != NULL) { From 7d46a58ba50753ac68fdc881aeb310ba077fcdb4 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:03:58 +0100 Subject: [PATCH 35/83] switched to using priority in getMasterNumber() --- src/lib/ebus/symbol.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index 0ce1fbcb..5f6a33ce 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -193,40 +193,40 @@ unsigned char getMasterNumber(unsigned char addr) { unsigned char addrHi = (addr & 0xF0) >> 4; unsigned char addrLo = (addr & 0x0F); - unsigned char index; - switch (addrHi) + unsigned char priority; + switch (addrLo) { case 0x0: - index = 0; + priority = 0; break; case 0x1: - index = 1; + priority = 1; break; case 0x3: - index = 2; + priority = 2; break; case 0x7: - index = 3; + priority = 3; break; case 0xF: - index = 4; + priority = 4; break; default: return 0; } - switch (addrLo) + switch (addrHi) { case 0x0: - return 5*index + 1; + return 5*0 + priority + 1; case 0x1: - return 5*index + 2; + return 5*1 + priority + 2; case 0x3: - return 5*index + 3; + return 5*2 + priority + 3; case 0x7: - return 5*index + 4; + return 5*3 + priority + 4; case 0xF: - return 5*index + 5; + return 5*4 + priority + 5; default: return 0; } From 46fb6763bcebae3141704a57afbb39494077e318 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:05:35 +0100 Subject: [PATCH 36/83] do not override name when referencing templates, added DataField::dump() --- src/lib/ebus/data.cpp | 66 +++++++++++++++++++++++++++++++++++++++---- src/lib/ebus/data.h | 17 +++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 2af7a240..75b8c36a 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -136,8 +136,6 @@ result_t DataField::create(vector::iterator& it, unsigned int divisor = 0; const bool isTemplate = dstAddress == SYN; string token; - if (it == end) - break; // name;part;type[:len][;[divisor|values][;[unit][;[comment]]]] const string name = *it++; @@ -152,7 +150,7 @@ result_t DataField::create(vector::iterator& it, firstName = name; firstComment = comment; } - if (dstAddress == BROADCAST || isMaster(dstAddress) + if (dstAddress == BROADCAST || isMaster(dstAddress) == true || (isTemplate == false && isSetMessage == true && partStr[0] == 0) || strcasecmp(partStr, "M") == 0) { // master data partType = pt_masterData; @@ -238,7 +236,7 @@ result_t DataField::create(vector::iterator& it, break; } found = true; - result = templ->derive(name, comment, unit, partType, divisor, values, fields); + result = templ->derive("", "", "", partType, divisor, values, fields); if (result != RESULT_OK) break; } @@ -347,6 +345,16 @@ result_t DataField::create(vector::iterator& it, } +void SingleDataField::dump(ostream& output) +{ + output << m_name << FIELD_SEPARATOR; + if (m_partType == pt_masterData) + output << "m"; + else if (m_partType == pt_slaveData) + output << "s"; + output << FIELD_SEPARATOR << m_dataType.name; +} + result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, ostringstream& output, @@ -365,7 +373,6 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff default: return RESULT_ERR_INVALID_ARG; // invalid part type } - if (isIgnored() == true) { if (offset + m_length > input.size()) { return RESULT_ERR_INVALID_ARG; @@ -431,6 +438,15 @@ result_t StringDataField::derive(string name, string comment, return RESULT_OK; } +void StringDataField::dump(ostream& output) +{ + SingleDataField::dump(output); + if ((m_dataType.flags & ADJ) != 0) + output << ":" << static_cast(m_length); + output << FIELD_SEPARATOR << FIELD_SEPARATOR; // no value list, no divisor + output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR; +} + result_t StringDataField::readSymbols(SymbolString& input, unsigned char baseOffset, ostringstream& output) { @@ -633,6 +649,18 @@ bool NumericDataField::hasFullByteOffset(bool after) || (after == true && m_bitOffset + (m_bitCount % 8) >= 8); } +void NumericDataField::dump(ostream& output) +{ + SingleDataField::dump(output); + if ((m_dataType.flags & ADJ) != 0) { + if ((m_dataType.maxBits % 8) != 0) + output << ":" << static_cast(m_bitCount); + else + output << ":" << static_cast(m_length); + } + output << FIELD_SEPARATOR; +} + result_t NumericDataField::readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value) { @@ -749,6 +777,13 @@ result_t NumberDataField::derive(string name, string comment, return RESULT_OK; } +void NumberDataField::dump(ostream& output) +{ + NumericDataField::dump(output); + output << static_cast(m_divisor) << FIELD_SEPARATOR; + output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR; +} + result_t NumberDataField::readSymbols(SymbolString& input, unsigned char baseOffset, ostringstream& output) { @@ -881,6 +916,21 @@ result_t ValueListDataField::derive(string name, string comment, return RESULT_OK; } +void ValueListDataField::dump(ostream& output) +{ + NumericDataField::dump(output); + bool first = true; + for (map::iterator it = m_values.begin(); it != m_values.end(); it++) { + if (first == true) + first = false; + else + output << VALUE_SEPARATOR; + output << static_cast(it->first) << "=" << it->second; + } + output << FIELD_SEPARATOR; + output << m_unit << FIELD_SEPARATOR << m_comment << FIELD_SEPARATOR; +} + result_t ValueListDataField::readSymbols(SymbolString& input, unsigned char baseOffset, ostringstream& output) { @@ -968,6 +1018,12 @@ result_t DataFieldSet::derive(string name, string comment, return RESULT_OK; } +void DataFieldSet::dump(ostream& output) +{ + for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) + (*it)->dump(output); +} + result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, ostringstream& output, bool verbose, char separator) diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index a62de4e3..9e8c4b75 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -158,6 +158,11 @@ public: * @return the field comment. */ string getComment() const { return m_comment; } + /** + * @brief Dump the field settings to the output. + * @param output the @a ostream to dump to. + */ + virtual void dump(ostream& output) = 0; /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -248,6 +253,8 @@ public: * only consumes a part of a byte and a subsequent field may re-use the same offset. */ virtual bool hasFullByteOffset(bool after) { return true; } + // @copydoc + virtual void dump(ostream& output); /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -339,6 +346,8 @@ public: string unit, const PartType partType, unsigned int divisor, map values, vector& fields); + // @copydoc + virtual void dump(ostream& output); protected: @@ -379,6 +388,8 @@ public: virtual ~NumericDataField() {} // @copydoc virtual bool hasFullByteOffset(bool after); + // @copydoc + virtual void dump(ostream& output); protected: @@ -441,6 +452,8 @@ public: string unit, const PartType partType, unsigned int divisor, map values, vector& fields); + // @copydoc + virtual void dump(ostream& output); protected: @@ -490,6 +503,8 @@ public: string unit, const PartType partType, unsigned int divisor, map values, vector& fields); + // @copydoc + virtual void dump(ostream& output); protected: @@ -552,6 +567,8 @@ public: */ size_t size() const { return m_fields.size(); } // @copydoc + virtual void dump(ostream& output); + // @copydoc virtual result_t read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, ostringstream& output, From 377c9c61c0887ac2f9a07dc9c2e73f7b65be139e Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:12:59 +0100 Subject: [PATCH 37/83] changed from m_isActive to m_isPassive, made defaults more flexible (every char besides r/w/p/0-9 can be used for defining messages to listen to - aka cyc), fix for defaults field list and duplicate message definitions, multiple message types now need to be separated by comma, optimized finding messages --- src/lib/ebus/message.cpp | 201 +++++++++++++++++++++------------------ src/lib/ebus/message.h | 76 ++++++++------- 2 files changed, 150 insertions(+), 127 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 7f736d45..5723af6d 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -28,21 +28,21 @@ using namespace std; Message::Message(const string clazz, const string name, const bool isSet, - const bool isActive, const string comment, + const bool isPassive, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, const vector id, DataField* data, const unsigned int pollPriority) : m_class(clazz), m_name(name), m_isSet(isSet), - m_isActive(isActive), m_comment(comment), + m_isPassive(isPassive), m_comment(comment), m_srcAddress(srcAddress), m_dstAddress(dstAddress), m_id(id), m_data(data), m_pollPriority(pollPriority) { int exp = 7; unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5); - if (isActive == true) - key |= 0x1fLL << (8 * exp--); + if (isPassive == true) + key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); // 0..25 else - key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); + key |= 0x1fLL << (8 * exp--); // special value for active key |= (unsigned long long)dstAddress << (8 * exp--); for (vector::const_iterator it=id.begin(); it* defaults, size_t pos) { +/*cout<<"getDefault("<(defaults->size()); +cout<<","<(pos)<<"=";*/ if (value.length() > 0 || defaults == NULL || pos > defaults->size()) { +//cout<at(pos); - return ret; + value = defaults->at(pos); +//cout<::iterator& it, const vector::iterator end, - vector* defaults, DataFieldTemplates* templates, Message*& returnValue) + vector< vector >* defaultsRows, + DataFieldTemplates* templates, Message*& returnValue) { // [type];[class];name;[comment];[QQ];ZZ;id;fields... result_t result; - bool isSet, isActive; + bool isSet = false, isPassive = true; + char defaultsChar; unsigned int pollPriority = 0; size_t defaultPos = 1; if (it == end) @@ -80,15 +90,15 @@ result_t Message::create(vector::iterator& it, const vector::ite const char* str = (*it++).c_str(); if (it == end) return RESULT_ERR_EOF; - if (strcasecmp(str, "W") == 0) { - isActive = true; + if (str[0] == 0 || strcasecmp(str, "R") == 0) { // default: active get + isPassive = false; + defaultsChar = 'r'; + } else if (strcasecmp(str, "W") == 0) { // active set + isPassive = false; isSet = true; - } else if (str[0] == 'C' || str[0] == 'c') { - isActive = false; - isSet = str[1] == 'W' || str[1] == 'w'; - } else if (str[0] == 'P' || str[0] == 'p') { // poll priority - isActive = true; - isSet = false; + defaultsChar = 'w'; + } else if (str[0] == 'P' || str[0] == 'p') { // poll (=active get) + isPassive = false; if (str[1] == 0) pollPriority = 1; else { @@ -97,16 +107,28 @@ result_t Message::create(vector::iterator& it, const vector::ite if (result != RESULT_OK) return result; } - } else if (str[0] >= '0' && str[0] <= '9') { // poll priority - isActive = true; - isSet = false; + defaultsChar = 'r'; + } else if (str[0] >= '0' && str[0] <= '9') { // poll priority (=active get) + isPassive = false; result_t result; pollPriority = parseInt(str, 10, 1, 9, result); if (result != RESULT_OK) return result; - } else { // default "r" - isActive = true; - isSet = false; + defaultsChar = 'r'; + } else { // any other: passive set/get + isSet = str[1] == 'W' || str[1] == 'w'; + defaultsChar = str[0]; + } + + vector* defaults = NULL; + if (defaultsRows != NULL && defaultsRows->size() > 0) { + for (vector< vector >::reverse_iterator it = defaultsRows->rbegin(); it != defaultsRows->rend(); it++) { + string check = (*it)[0]; + if (check[0] == defaultsChar) { + defaults = &(*it); + break; + } + } } string clazz = getDefault(*it++, defaults, defaultPos++); @@ -153,9 +175,9 @@ result_t Message::create(vector::iterator& it, const vector::ite string token = *it++; if (useDefaults == 1) { if (pos == 0 && token.size() > 0) { - useDefaults = false; + useDefaults = 0; } else { - token.append(getDefault("", defaults, defaultPos)); + token = getDefault("", defaults, defaultPos).append(token); } } istringstream input(token); @@ -189,9 +211,9 @@ result_t Message::create(vector::iterator& it, const vector::ite } vector::iterator realEnd = end; - if (defaults!=NULL && defaults->size() > defaultPos + 3) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]") - vector newTypes; - while (defaults->at(defaultPos + 3).size() > 0) { + vector newTypes; + if (defaults!=NULL && defaults->size() > defaultPos + 2) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]") + while (defaults->size() > defaultPos + 2 && defaults->at(defaultPos + 2).size() > 0) { for (size_t i = 0; i < 6; i++) { if (defaults->size() > defaultPos) newTypes.push_back(defaults->at(defaultPos)); @@ -200,8 +222,6 @@ result_t Message::create(vector::iterator& it, const vector::ite defaultPos++; } - if (defaults->size() <= defaultPos + 3) - break; } if (newTypes.size() > 0) { while (it != end) { @@ -216,74 +236,77 @@ result_t Message::create(vector::iterator& it, const vector::ite if (result != RESULT_OK) { return result; } - returnValue = new Message(clazz, name, isSet, isActive, comment, srcAddress, dstAddress, id, data, pollPriority); + returnValue = new Message(clazz, name, isSet, isPassive, comment, srcAddress, dstAddress, id, data, pollPriority); return RESULT_OK; } -result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator) +result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator) { - if (m_isActive == 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); - 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, m_id.size() - 2, slaveData, 0, separator); - if (result != RESULT_OK) - return result; - masterData.push_back(masterData.getCRC(), false, false); - return RESULT_OK; - } - return RESULT_ERR_INVALID_ARG; // prepare not possible + if (m_isPassive == true) + return RESULT_ERR_INVALID_ARG; // prepare not possible + + 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); + 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, m_id.size() - 2, slaveData, 0, separator); + if (result != RESULT_OK) + return result; + masterData.push_back(masterData.getCRC(), false, false); + /*if (slaveData.size() > 0) { + return RESULT_ERR_INVALID_ARG; // TODO support answering MS queries (set slave length, calc crc) + }*/ + return RESULT_OK; } result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, - ostringstream& output, char separator, bool answer) + ostringstream& output, char separator) { result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); if (result != RESULT_OK) return result; - if (m_isActive == true && answer == true) { + /*if (m_isPassive == false && answer == true) { 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; - } + }*/ return RESULT_OK; } result_t MessageMap::add(Message* message) { - string key = message->getClass().append(";").append(message->getName()); - if (message->isActive() == true) + if (message->isPassive() == false) { + string key = message->getClass().append(";").append(message->getName()); key.append(message->isSet() ? ";W" : ";R"); - else - key.append(";C"); - map::iterator nameIt = m_messagesByName.find(key); - if (nameIt != m_messagesByName.end()) { - return RESULT_ERR_DUPLICATE; // duplicate key - } - - if (message->isActive() == false) { - unsigned long long pkey = message->getKey(); - map::iterator keyIt = m_passiveMessagesByKey.find(pkey); - if (keyIt != m_passiveMessagesByKey.end()) { + map::iterator nameIt = m_messagesByName.find(key); + if (nameIt != m_messagesByName.end()) { return RESULT_ERR_DUPLICATE; // duplicate key } - unsigned char idLength = message->getId().size() - 2; - if (idLength > m_maxIdLength) - m_maxIdLength = idLength; - m_passiveMessagesByKey[pkey] = message; + m_messagesByName[key] = message; + return RESULT_OK; } - m_messagesByName[key] = message; + unsigned long long key = message->getKey(); + map::iterator keyIt = m_passiveMessagesByKey.find(key); + if (keyIt != m_passiveMessagesByKey.end()) { + return RESULT_ERR_DUPLICATE; // duplicate key + } + + unsigned char idLength = message->getId().size() - 2; + if (idLength < m_minIdLength) + m_minIdLength = idLength; + if (idLength > m_maxIdLength) + m_maxIdLength = idLength; + m_passiveMessagesByKey[key] = message; return RESULT_OK; } @@ -296,19 +319,12 @@ result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, v types.append("r"); result_t result = RESULT_ERR_EOF; - for (size_t i=0; i* defaultRow = NULL; - if (defaults != NULL && defaults->size() > 0) { - for (vector< vector >::reverse_iterator it = defaults->rbegin(); it != defaults->rend(); it++) { - if ((*it)[0] == type || (type[0] >= '0' && type[0] <= '9' && ((*it)[0][0] == 'r' && (*it)[0][0] == 'R'))) { - defaultRow = &(*it); - break; - } - } - } + istringstream stream(types); + string type; + while (getline(stream, type, ',') != 0) { + row[0] = type; vector::iterator it = row.begin(); - result = Message::create(it, row.end(), defaultRow, arg, message); + result = Message::create(it, row.end(), defaults, arg, message); if (result != RESULT_OK) { printErrorPos(row.begin(), row.end(), it); return result; @@ -321,15 +337,11 @@ result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, v return result; } -Message* MessageMap::find(const string& clazz, const string& name, const bool isActive, const bool isSet) +Message* MessageMap::find(const string& clazz, const string& name, const bool isSet) { string key = clazz; for (int i=0; i<2; i++) { - key.append(";").append(name); - if (isActive == true) - key.append(isSet ? ";W" : ";R"); - else - key.append(";C"); + key.append(";").append(name).append(isSet ? ";W" : ";R"); map::iterator it = m_messagesByName.find(key); if (it != m_messagesByName.end()) return it->second; @@ -339,17 +351,20 @@ Message* MessageMap::find(const string& clazz, const string& name, const bool is return NULL; } -Message* MessageMap::find(SymbolString& master) { +Message* MessageMap::find(SymbolString& master) +{ if (master.size() < 5) return NULL; - unsigned char maxIdLength = master[4]; + unsigned char maxIdLength = master[4]; + if (maxIdLength < m_minIdLength) + return NULL; if (maxIdLength > m_maxIdLength) maxIdLength = m_maxIdLength; if (master.size() < 5+maxIdLength) return NULL; unsigned long long sourceMask = 0x1fLL << (8 * 7); - for (int idLength=maxIdLength; idLength>=0; idLength--) { + for (int idLength=maxIdLength; idLength>=m_maxIdLength; idLength--) { int exp = 7; unsigned long long key = (unsigned long long)idLength << (8 * exp + 5); key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--); diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 6863570d..2e53fb79 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -37,22 +37,21 @@ class Message public: /** - * @brief Constructs a new instance. + * @brief Construct a new instance. * @param class the optional device class. * @param name the message name (unique within the same class and type). * @param isSet whether this is a set message. - * @param isActive 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 isPassive true if message can only be initiated by a participant other than us, + * false if message can be initiated by any participant. * @param comment the comment. - * @param srcAddress the source address (optional if passive), or @a SYN for any. + * @param srcAddress the source address, or @a SYN for any (only relevant if passive). * @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 string clazz, const string name, const bool isSet, - const bool isActive, const string comment, + const bool isPassive, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, const vector id, DataField* data, const unsigned int pollPriority); @@ -64,15 +63,15 @@ public: * @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 defaults a @a vector with known default values, or NULL. + * @param defaultsRows a @a vector with rows containing defaults, or NULL. * @param templates the @a DataFieldTemplates to be referenced by name, or NULL. * @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(vector::iterator& it, const vector::iterator end, - vector* defaults, - DataFieldTemplates*, Message*& returnValue); + vector< vector >* defaultsRows, + DataFieldTemplates* templates, Message*& returnValue); /** * @brief Get the optional device class. * @return the optional device class. @@ -89,13 +88,11 @@ public: */ bool isSet() const { return m_isSet; } /** - * @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. + * @brief Get whether message can be initiated only by a participant other than us. + * @return true if message can only be initiated by a participant other than us, + * false if message can be initiated by any participant. */ - bool isActive() const { return m_isActive; } + bool isPassive() const { return m_isPassive; } /** * @brief Get the comment. * @return the comment. @@ -117,7 +114,7 @@ public: */ vector getId() const { return m_id; } /** - * @brief Returns the key for storing in @a MessageSet. + * @brief Return the key for storing in @a MessageSet. * @return the key for storing in @a MessageSet. */ unsigned long long getKey() { return m_key; } @@ -134,17 +131,24 @@ public: //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 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. + * @brief Prepare master @a SymbolString for sending to the bus. + * @param masterData the master data @a SymbolString for writing symbols to. + * @param input the @a istringstream to parse the formatted value(s) from. * @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, + result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator=';'); + /** + * @brief Decode a received message. + * @param masterData the unescaped received master @a SymbolString. + * @param slaveData the unescaped received slave @a SymbolString. + * @param output the @a ostringstream to append the formatted value to. + * @param separator the separator character between multiple fields. + * @return @a RESULT_OK on success, or an error code. + */ result_t decode(SymbolString& masterData, SymbolString& slaveData, - ostringstream& output, char separator=';', bool answer=false); + ostringstream& output, char separator=';'); private: @@ -154,13 +158,12 @@ private: const string m_name; /** whether this is a set message. */ const bool m_isSet; - /** 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_isActive; + /** true if message can only be initiated by a participant other than us, + * false if message can be initiated by any participant. */ + const bool m_isPassive; /** the comment. */ const string m_comment; - /** the source address (optional if passive), or @a SYN for any. */ + /** the source address, or @a SYN for any (only relevant if passive). */ const unsigned char m_srcAddress; /** the destination address. */ const unsigned char m_dstAddress; @@ -183,15 +186,15 @@ class MessageMap : public FileReader public: /** - * @brief Constructs a new instance. + * @brief Construct a new instance. */ - MessageMap() : FileReader(true), m_maxIdLength(0) {} + MessageMap() : FileReader(true), m_minIdLength(4), m_maxIdLength(0) {} /** * @brief Destructor. */ virtual ~MessageMap() { clear(); } /** - * @brief Adds a @a Message instance to this set. + * @brief Add a @a Message instance to this set. * @param message the @a Message instance to add. * @return @a RESULT_OK on success, or an error code. * Note: the caller may not free the added instance on success. @@ -200,14 +203,16 @@ public: // @copydoc virtual result_t addFromFile(vector& row, DataFieldTemplates* arg, vector< vector >* defaults); /** - * @brief Finds the @a Message instance for the specified class and name. - * @param master the master @a SymbolString for identifying the @a Message. + * @brief Find the @a Message instance for the specified class and name. + * @param class the optional device class. + * @param name the message name. + * @param isSet whether this is a set message. * @return the @a Message instance, or NULL. * Note: the caller may not free the returned instance. */ - Message* find(const string& clazz, const string& name, const bool isActive, const bool isSet); + Message* find(const string& clazz, const string& name, const bool isSet); /** - * @brief Finds the @a Message instance for the specified master data. + * @brief Find the @a Message instance for the specified master data. * @param master the master @a SymbolString for identifying the @a Message. * @return the @a Message instance, or NULL. * Note: the caller may not free the returned instance. @@ -221,6 +226,9 @@ public: private: + /** the minimum ID length used by any of the known @a Message instances. */ + unsigned char m_minIdLength; + /** the maximum ID length used by any of the known @a Message instances. */ unsigned char m_maxIdLength; From 3da2c42c0e5ac9ecfcc4018d911b9edb6fa458ac Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:18:35 +0100 Subject: [PATCH 38/83] added getPollPriority() --- src/lib/ebus/message.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 2e53fb79..25373f5d 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -118,6 +118,11 @@ public: * @return the key for storing in @a MessageSet. */ unsigned long long getKey() { return m_key; } + /** + * @brief Get the polling priority, or 0 for no polling at all. + * @return the polling priority, or 0 for no polling at all. + */ + unsigned char getPollPriority() const { return m_pollPriority; } /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. From 3b99ca0b4db85493b3387d4f5d2a2a0827391376 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 20:25:12 +0100 Subject: [PATCH 39/83] corrected #define --- src/ebusd/bushandler.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 52a5e48f..89ebdb1c 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -17,8 +17,8 @@ * along with ebusd. If not, see http://www.gnu.org/licenses/. */ -#ifndef LIBEBUS_BUSHANDLER_H_ -#define LIBEBUS_BUSHANDLER_H_ +#ifndef BUSHANDLER_H_ +#define BUSHANDLER_H_ #include "message.h" #include "data.h" @@ -160,4 +160,4 @@ private: }; -#endif // LIBEBUS_BUSHANDLER_H_ +#endif // BUSHANDLER_H_ From 671aa54468f66310f9d45943226652260285212d Mon Sep 17 00:00:00 2001 From: john30 Date: Mon, 1 Dec 2014 22:14:01 +0100 Subject: [PATCH 40/83] pass log function instead of Logger to avoid dependencies, started decodeMessage for get --- src/ebusd/baseloop.cpp | 30 ++++++++++++++++++------------ src/ebusd/baseloop.h | 16 ++++++++++++++-- src/ebusd/bushandler.cpp | 1 + src/lib/ebus/port.cpp | 9 ++++----- src/lib/ebus/port.h | 12 ++++++++---- src/lib/ebus/test/Makefile.am | 3 +-- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 715b8221..afd2b94e 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -57,7 +57,7 @@ BaseLoop::BaseLoop() const long dumpRawMaxSize = A.getOptVal("dumpsize"); // create Port - m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &L, dumpRaw, dumpRawFile, dumpRawMaxSize); + m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &BaseLoop::logRaw, dumpRaw, dumpRawFile, dumpRawMaxSize); m_port->open(); if (m_port->isOpen() == false) @@ -164,6 +164,10 @@ void BaseLoop::start() } } +void BaseLoop::logRaw(const unsigned char byte) { + L.log(bus, event, "%02x", byte); +} + string BaseLoop::decodeMessage(const string& data) { ostringstream result; @@ -186,18 +190,20 @@ string BaseLoop::decodeMessage(const string& data) result << "command not found"; break; - /*case ct_get: - if (cmd.size() < 3 || cmd.size() > 4) { - result << "usage: 'get class cmd (sub)'"; + case ct_get: + if (cmd.size() < 2 || cmd.size() > 4) { + result << "usage: 'get [class] cmd' or 'get class cmd sub'"; break; } - message = m_messages->find(cmd[1], cmd[2], true, false); + if (cmd.size() == 2) + message = m_messages->find("", cmd[1], false); + else + message = m_messages->find(cmd[1], cmd[2], false); if (message != NULL) { - // polling data - if (strcasecmp(m_commands->getCmdType(index).c_str(), "P") == 0) { + /*if (message->getPollPriority() > 0) // get polldata polldata = m_commands->getPollData(index); if (polldata != "") { @@ -213,12 +219,12 @@ string BaseLoop::decodeMessage(const string& data) } break; - } + }*/ - string busCommand(A.getOptVal("address")); + /*string busCommand(A.getOptVal("address")); busCommand += m_commands->getBusCommand(index); transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); - + m_busHandler-> BusMessage* message = new BusMessage(busCommand, false, false); L.log(bas, trace, " msg: %s", busCommand.c_str()); // send message @@ -238,13 +244,13 @@ string BaseLoop::decodeMessage(const string& data) result << message->getResultCodeCStr(); } - delete message; + delete message;*/ } else { result << "ebus command not found"; } - break;*/ + break; /*case ct_set: if (cmd.size() != 4) { diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index b058130a..c6aab310 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -51,16 +51,22 @@ class BaseLoop public: /** - * @brief construct the baseloop and creates messaging, network and busloop subsystems. + * @brief Construct the base loop and create messaging, network and bus handling subsystems. */ BaseLoop(); /** - * @brief destructor. + * @brief Destructor. */ ~BaseLoop(); + /** + * @brief Read the configuration files from the specified path. + * @param path the path from which to read the files. + * @param extension the filename extension of the files to read. + */ result_t readConfigFiles(const string path, const string extension); + /** * @brief start baseloop instance. */ @@ -72,6 +78,12 @@ public: */ void addMessage(NetMessage* message) { m_netQueue.add(message); } + /** + * @brief Create a log message for a retrieved raw data byte. + * @param param byte the retrieved raw data byte. + */ + static void logRaw(const unsigned char byte); + private: /** the @a DataFieldTemplates instance. */ diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 5e1d06ad..5c527cb5 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -22,6 +22,7 @@ #include "data.h" #include "result.h" #include "symbol.h" +#include "logger.h" #include "appl.h" #include #include diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index f5b052fc..08defe83 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -30,7 +30,6 @@ #include #include #include -#include "logger.h" #ifdef HAVE_PPOLL #include @@ -252,10 +251,10 @@ void DeviceNetwork::closeDevice() } -Port::Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, Logger* loggerRaw, +Port::Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, void (*logRawFunc)(const unsigned char byte), const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize) : m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck), - m_logRaw(logRaw), m_loggerRaw(loggerRaw), + m_logRaw(logRaw), m_logRawFunc(logRawFunc), m_dumpRawFile(dumpRawFile), m_dumpRawMaxSize(dumpRawMaxSize) { m_device = NULL; @@ -275,8 +274,8 @@ unsigned char Port::byte() { unsigned char byte = m_device->getByte(); - if (m_logRaw == true && m_loggerRaw != NULL) - m_loggerRaw->log(bus, event, "%02x", byte); + if (m_logRaw == true && m_logRawFunc != NULL) + (*m_logRawFunc)(byte); if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) { m_dumpRawStream.write((char*)&byte, 1); diff --git a/src/lib/ebus/port.h b/src/lib/ebus/port.h index 9b833894..124dd147 100644 --- a/src/lib/ebus/port.h +++ b/src/lib/ebus/port.h @@ -26,7 +26,6 @@ #include #include #include -#include "logger.h" #include "result.h" using namespace std; @@ -203,8 +202,13 @@ public: * @brief constructs a new instance and determine device type. * @param deviceName to determine device type. * @param noDeviceCheck en-/disable device check. + * @param logRaw whether logging of raw data is enabled. + * @param logRawFunc a function to call for logging raw data, or NULL. + * @param dumpRaw whether dumping of raw data to a file is enabled. + * @param dumpRawFile the name of the file to dump raw data to. + * @param dumpRawMaxSize the maximum size of @a m_dumpFile. */ - Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, Logger* loggerRaw, + Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, void (*logRawFunc)(const unsigned char byte), const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize); /** @@ -307,8 +311,8 @@ private: /** whether logging of raw data is enabled. */ bool m_logRaw; - /** the @a Logger used for logging of raw data, or NULL. */ - Logger* m_loggerRaw; + /** a function to call for logging raw data, or NULL. */ + void (*m_logRawFunc)(const unsigned char byte); /** whether dumping of raw data to a file is enabled. */ bool m_dumpRaw; diff --git a/src/lib/ebus/test/Makefile.am b/src/lib/ebus/test/Makefile.am index 4570f354..ac8369f7 100755 --- a/src/lib/ebus/test/Makefile.am +++ b/src/lib/ebus/test/Makefile.am @@ -10,8 +10,7 @@ noinst_PROGRAMS = test_port \ test_message test_port_SOURCES = test_port.cpp -test_port_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ - $(top_srcdir)/src/lib/ebus/libebus.a +test_port_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a test_symbol_SOURCES = test_symbol.cpp test_symbol_LDADD = $(top_srcdir)/src/lib/ebus/libebus.a From c9015eb4f497fd08de0e940cfa97b380e9f4b4a7 Mon Sep 17 00:00:00 2001 From: john30 Date: Mon, 1 Dec 2014 22:15:30 +0100 Subject: [PATCH 41/83] fixed storage for messages by name only --- src/lib/ebus/message.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 5723af6d..26ce9764 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -284,13 +284,18 @@ result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, result_t MessageMap::add(Message* message) { if (message->isPassive() == false) { - string key = message->getClass().append(";").append(message->getName()); - key.append(message->isSet() ? ";W" : ";R"); + bool isSet = message->isSet(); + string clazz = message->getClass(); + string name = message->getName(); + string key = string(isSet ? "W" : "R") + clazz + ";" + name; map::iterator nameIt = m_messagesByName.find(key); if (nameIt != m_messagesByName.end()) { return RESULT_ERR_DUPLICATE; // duplicate key } + m_messagesByName[key] = message; + + key = string(isSet ? "-W" : "-R") + name; // also store without class m_messagesByName[key] = message; return RESULT_OK; } @@ -339,13 +344,15 @@ result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, v Message* MessageMap::find(const string& clazz, const string& name, const bool isSet) { - string key = clazz; + string key; for (int i=0; i<2; i++) { - key.append(";").append(name).append(isSet ? ";W" : ";R"); + if (i==0) + key = string(isSet ? "W" : "R") + clazz + ";" + name; + else + key = string(isSet ? "-W" : "-R") + name; // second try: without class map::iterator it = m_messagesByName.find(key); if (it != m_messagesByName.end()) return it->second; - key.clear(); // try again without class name } return NULL; @@ -392,7 +399,8 @@ Message* MessageMap::find(SymbolString& master) void MessageMap::clear() { for (map::iterator it=m_messagesByName.begin(); it!=m_messagesByName.end(); it++) { - delete it->second; + if (it->first[0] != '-') // avoid double free + delete it->second; it->second = NULL; } m_messagesByName.clear(); From eff24a8b063132bf7e10fd7392ca38396858ea43 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 20:57:22 +0100 Subject: [PATCH 42/83] added hex type --- src/lib/utils/appl.cpp | 3 +++ src/lib/utils/appl.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/utils/appl.cpp b/src/lib/utils/appl.cpp index f56d8c1a..c87d2a38 100644 --- a/src/lib/utils/appl.cpp +++ b/src/lib/utils/appl.cpp @@ -165,6 +165,9 @@ void Appl::setOptVal(const char* option, const string value, DataType datatype) case dt_bool: m_optvals[option] = true; break; + case dt_hex: + m_optvals[option] = strtol(value.c_str(), NULL, 16); + break; case dt_int: m_optvals[option] = strtol(value.c_str(), NULL, 10); break; diff --git a/src/lib/utils/appl.h b/src/lib/utils/appl.h index 8e988deb..7b88f2e8 100644 --- a/src/lib/utils/appl.h +++ b/src/lib/utils/appl.h @@ -33,7 +33,8 @@ using namespace std; enum DataType { dt_none, /*!< default for __text_only__ */ dt_bool, /*!< boolean */ - dt_int, /*!< integer */ + dt_hex, /*!< hex integer */ + dt_int, /*!< dec integer */ dt_long, /*!< long */ dt_float, /*!< float */ dt_string /*!< string */ From 53a5b0b809872598a7f1874dcf8d19d82185fb87 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 20:58:02 +0100 Subject: [PATCH 43/83] changed address option to hex, added answer option --- src/ebusd/ebusd.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ebusd/ebusd.cpp b/src/ebusd/ebusd.cpp index fbc85345..aad7f47f 100644 --- a/src/ebusd/ebusd.cpp +++ b/src/ebusd/ebusd.cpp @@ -43,9 +43,12 @@ void define_args() A.addText("Options:\n"); - A.addOption("address", "a", OptVal("FF"), dt_string, ot_mandatory, + A.addOption("address", "a", OptVal(0xff), dt_hex, ot_mandatory, "\tebus device address (FF)"); + A.addOption("answer", "", OptVal(false), dt_bool, ot_none, + "\tanswers to requests from other devices"); + A.addOption("device", "d", OptVal("/dev/ttyUSB0"), dt_string, ot_mandatory, "\tebus device (serial or network) (/dev/ttyUSB0)"); From 0cb6095fb5f9feec9aed0eda68bd5fec6e4c7073 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 23:01:31 +0100 Subject: [PATCH 44/83] added optional bool wait to remove() and next(), added remove(item) --- src/lib/utils/wqueue.h | 58 ++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) mode change 100644 => 100755 src/lib/utils/wqueue.h diff --git a/src/lib/utils/wqueue.h b/src/lib/utils/wqueue.h old mode 100644 new mode 100755 index 6964c476..35d72b81 --- a/src/lib/utils/wqueue.h +++ b/src/lib/utils/wqueue.h @@ -67,17 +67,25 @@ public: /** * @brief remove the first item from queue. - * @return the item. + * @param wait true to wait for an item to be added to the queue, false to return NULL if no item is available. + * @return the item, or NULL if no item is available and wait was false. */ - T remove() + T remove(bool wait=true) { pthread_mutex_lock(&m_mutex); - while (m_queue.size() == 0) - pthread_cond_wait(&m_cond, &m_mutex); - - T item = m_queue.front(); - m_queue.pop_front(); + T item; + if (wait) { + while (m_queue.size() == 0) + pthread_cond_wait(&m_cond, &m_mutex); + item = m_queue.front(); + m_queue.pop_front(); + } + else if (m_queue.size() > 0) { + item = m_queue.front(); + m_queue.pop_front(); + } else + item = NULL; pthread_mutex_unlock(&m_mutex); @@ -85,17 +93,39 @@ public: } /** - * @brief return the first item from queue without remove. - * @return the item. + * @brief Remove the specified item from queue. + * @param item the item to remove. + * @return whether the item was removed. */ - T next() + bool remove(T item) + { + pthread_mutex_lock(&m_mutex); + int oldSize = m_queue.size(); + if (oldSize > 0) + m_queue.remove(item); + int newSize = m_queue.size(); + pthread_mutex_unlock(&m_mutex); + return newSize != oldSize; + } + + /** + * @brief return the first item from queue without remove. + * @return the item, or NULL if no item is available and wait was false. + */ + T next(bool wait=true) { pthread_mutex_lock(&m_mutex); - while (m_queue.size() == 0) - pthread_cond_wait(&m_cond, &m_mutex); - - T item = m_queue.front(); + T item; + if (wait) { + while (m_queue.size() == 0) + pthread_cond_wait(&m_cond, &m_mutex); + item = m_queue.front(); + } + else if (m_queue.size() > 0) + item = m_queue.front(); + else + item = NULL; pthread_mutex_unlock(&m_mutex); From 508eedbe51865679f206e259722a64e13358da41 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 23:01:31 +0100 Subject: [PATCH 45/83] added optional bool wait to remove() and next(), added remove(item) --- src/lib/utils/wqueue.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/utils/wqueue.h diff --git a/src/lib/utils/wqueue.h b/src/lib/utils/wqueue.h old mode 100755 new mode 100644 From 09b2d969beab1e4832670569642ef4cc51bbbe60 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 23:02:30 +0100 Subject: [PATCH 46/83] added SymbolString(SymbolString), optimized --- src/lib/ebus/symbol.cpp | 15 +++++++++++++-- src/lib/ebus/symbol.h | 9 +++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index 5f6a33ce..6e35772c 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -48,7 +48,7 @@ static const unsigned char CRC_LOOKUP_TABLE[] = }; -SymbolString::SymbolString(const string str) +SymbolString::SymbolString(const string& str) : m_unescapeState(0), m_crc(0) { // parse + escape @@ -60,7 +60,18 @@ SymbolString::SymbolString(const string str) push_back(m_crc, false, false); } -SymbolString::SymbolString(const string str, bool isEscaped) +SymbolString::SymbolString(const SymbolString& str) + : m_unescapeState(0), m_crc(0) +{ + // escape + for (size_t i = 0; i < str.size(); i++) { + push_back(str[i], false, true); + } + // add CRC + escape + push_back(m_crc, false, false); +} + +SymbolString::SymbolString(const string& str, bool isEscaped) : m_unescapeState(1), m_crc(0) { // parse + optionally unescape diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index b30d0467..adf5501b 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -50,13 +50,18 @@ 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 string str); + SymbolString(const string& str); + /** + * @brief Creates a new escaped instance from an unescaped @a SymbolString and adds the calculated CRC. + * @param str the unescaped SymbolString. + */ + SymbolString(const SymbolString& 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 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. From 8b9d935cbf83fb4757943c8cb6ecc16f6471323c Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 23:03:20 +0100 Subject: [PATCH 47/83] started implementing get&hex --- src/ebusd/baseloop.cpp | 129 +++++++++++++++++++++-------------------- src/ebusd/baseloop.h | 3 + 2 files changed, 69 insertions(+), 63 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index afd2b94e..620f8c21 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -21,6 +21,7 @@ #include "logger.h" #include "appl.h" #include +#include using namespace std; @@ -50,6 +51,9 @@ BaseLoop::BaseLoop() L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());*/ + m_ownAddress = A.getOptVal("address") & 0xff; + bool answer = A.getOptVal("answer"); + const bool logRaw = A.getOptVal("lograwdata"); const bool dumpRaw = A.getOptVal("dump"); @@ -64,7 +68,7 @@ BaseLoop::BaseLoop() L.log(bus, error, "can't open %s", A.getOptVal("device")); // create BusHandler - m_busHandler = new BusHandler(m_port, m_messages, SYN, SYN); // TODO + m_busHandler = new BusHandler(m_port, m_messages, answer ? m_ownAddress : SYN, answer ? (m_ownAddress+5)&0xff : SYN); m_busHandler->start("bushandler"); // create network @@ -172,7 +176,6 @@ string BaseLoop::decodeMessage(const string& data) { ostringstream result; string cycdata, polldata; - Message* message; // prepare data string token; @@ -196,60 +199,57 @@ string BaseLoop::decodeMessage(const string& data) break; } - if (cmd.size() == 2) - message = m_messages->find("", cmd[1], false); - else - message = m_messages->find(cmd[1], cmd[2], false); + { + Message* message; + if (cmd.size() == 2) + message = m_messages->find("", cmd[1], false); + else + message = m_messages->find(cmd[1], cmd[2], false); - if (message != NULL) { + if (message != NULL) { - /*if (message->getPollPriority() > 0) - // get polldata - polldata = m_commands->getPollData(index); - if (polldata != "") { + /*if (message->getPollPriority() > 0) + // get polldata + polldata = m_commands->getPollData(index); + if (polldata != "") { + // decode data + Command* command = new Command(index, (*m_commands)[index], polldata); + + // return result + result << command->calcResult(cmd); + + delete command; + } else { + result << "no data stored"; + } + + break; + }*/ + + SymbolString master; + istringstream input; + message->prepareMaster(m_ownAddress, master, input); + L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); + + // send message + SymbolString slave; + result_t ret = m_busHandler->sendAndWait(master, slave); + + if (ret == RESULT_OK) // decode data - Command* command = new Command(index, (*m_commands)[index], polldata); + ret = message->decode(master, slave, result); - // return result - result << command->calcResult(cmd); - - delete command; - } else { - result << "no data stored"; + if (ret != RESULT_OK) { + L.log(bas, error, " %s", getResultCode(ret)); + result << getResultCode(ret); } + else + result << result.str(); // TODO reduce to requested variable only - break; - }*/ - - /*string busCommand(A.getOptVal("address")); - busCommand += m_commands->getBusCommand(index); - transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); - m_busHandler-> - BusMessage* message = new BusMessage(busCommand, false, false); - L.log(bas, trace, " msg: %s", busCommand.c_str()); - // send message - m_busloop->addMessage(message); - message->waitSignal(); - - if (!message->isErrorResult()) { - // decode data - Command* command = new Command(index, (*m_commands)[index], message->getMessageStr()); // TODO use getCommand()+getResult() - - // return result - result << command->calcResult(cmd); - - delete command; } else { - L.log(bas, error, " %s", message->getResultCodeCStr()); - result << message->getResultCodeCStr(); + result << "ebus command not found"; } - - delete message;*/ - - } else { - result << "ebus command not found"; } - break; /*case ct_set: @@ -335,35 +335,38 @@ string BaseLoop::decodeMessage(const string& data) break;*/ - /*case ct_hex: + case ct_hex: if (cmd.size() != 2) { result << "usage: 'hex value' (value: ZZPBSBNNDx)"; break; } { - string busCommand(A.getOptVal("address")); cmd[1].erase(remove_if(cmd[1].begin(), cmd[1].end(), ::isspace), cmd[1].end()); - busCommand += cmd[1]; - transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); + string src; + ostringstream msg; + msg << hex << setw(2) << setfill('0') << static_cast(m_ownAddress); + msg << cmd[1]; + SymbolString master(cmd[1]); + L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); - BusMessage* message = new BusMessage(busCommand, false, false); - L.log(bas, trace, " msg: %s", busCommand.c_str()); // send message - m_busloop->addMessage(message); - message->waitSignal(); + SymbolString slave; + result_t ret = m_busHandler->sendAndWait(master, slave); - if (message->isErrorResult()) { - L.log(bas, error, " %s", message->getResultCodeCStr()); - result << message->getResultCodeCStr(); - } else { - result << message->getMessageStr(); // TODO use getCommand()+getResult() + if (ret == RESULT_OK) + // decode data + result << slave.getDataStr(); // TODO find suitable message?, message->decode(master, slave, result); + + if (ret != RESULT_OK) { + L.log(bas, error, " %s", getResultCode(ret)); + result << getResultCode(ret); } - - delete message; + else + result << result.str(); // TODO reduce to requested variable only } - break;*/ + break; /*case ct_scan: if (cmd.size() == 1) { diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index c6aab310..0c1662e5 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -92,6 +92,9 @@ private: /** the @a MessageMap instance. */ MessageMap* m_messages; + /** the own master address for sending on the bus. */ + unsigned char m_ownAddress; + /** the @a Port instance. */ Port* m_port; From 73d4d423d6a3c1f02f4455e67d3fbaed10704c93 Mon Sep 17 00:00:00 2001 From: john30 Date: Wed, 3 Dec 2014 23:03:20 +0100 Subject: [PATCH 48/83] started implementing get&hex --- src/ebusd/bushandler.cpp | 108 ++++++++++++++++++++++++++++++++++++--- src/ebusd/bushandler.h | 59 ++++++++++++++++++++- 2 files changed, 158 insertions(+), 9 deletions(-) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 5c527cb5..8951a03d 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace std; @@ -54,6 +55,62 @@ const char* getStateCode(BusState state, int sendPos) { } +BusRequest::BusRequest(SymbolString& master, SymbolString& slave) + : m_master(master), m_slave(slave), m_finished(false) +{ + pthread_mutex_init(&m_mutex, NULL); + pthread_cond_init(&m_cond, NULL); +} + +BusRequest::~BusRequest() +{ + pthread_mutex_destroy(&m_mutex); + pthread_cond_destroy(&m_cond); +} + +bool BusRequest::wait(int timeout) +{ + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + t.tv_sec += timeout; + int result = 0; + + pthread_mutex_lock(&m_mutex); + + while (m_finished == false && result == 0) + result = pthread_cond_timedwait(&m_cond, &m_mutex, &t); + + if (result == 0 && m_finished == false) + result = 1; + + pthread_mutex_unlock(&m_mutex); + + return result == 0; +} + +void BusRequest::notify(bool finished) +{ + pthread_mutex_lock(&m_mutex); + + m_finished = finished; + + pthread_mutex_unlock(&m_mutex); +} + + +result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) +{ + BusRequest* request = new BusRequest(master, slave); + + m_requests.add(request); + bool result = request->wait(5); + if (result == false) + m_requests.remove(request); + delete request; + + return result == true ? RESULT_OK : RESULT_ERR_TIMEOUT; +} + void BusHandler::run() { result_t result = RESULT_OK; @@ -82,14 +139,37 @@ result_t BusHandler::receiveSymbol() { long timeout; ssize_t count; + unsigned char sentSymbol = SYN; + BusRequest* startRequest = NULL; if (m_state == bs_skip) timeout = 0; - else if (m_state == bs_ready) - timeout = SYN_TIMEOUT; - else if (m_sendPos >= 0) + else if (m_sendPos >= 0) { timeout = SLAVE_RECV_TIMEOUT; - else + if (m_sendPos+1 < m_request->m_master.size()) { + m_sendPos++; + sentSymbol = m_request->m_master[m_sendPos]; + if (m_port->send(&sentSymbol) != 1) { + sentSymbol = SYN; // try again later // TODO error: send failed, abort send + m_request->notify(false); + m_request = NULL; + m_sendPos = -1; + } + } + } + else { timeout = SYN_TIMEOUT; + if (m_state == bs_ready && m_request == NULL) { + startRequest = m_requests.next(false); + if (startRequest != NULL) { + // initiate arbitration + sentSymbol = startRequest->m_master[0]; + if (m_port->send(&sentSymbol) != 1) { + sentSymbol = SYN; // try again later // TODO error: send failed + startRequest = NULL; + } + } + } + } count = m_port->recv(timeout, 1); @@ -119,12 +199,24 @@ result_t BusHandler::receiveSymbol() case bs_ready: if (symbol == ESC) return setState(bs_skip, RESULT_ERR_ESC); - + if (m_sendPos < 0 && sentSymbol != SYN) { + // check arbitration + if (symbol == sentSymbol) { // arbitration successful + if (m_requests.remove(startRequest) == false) { + sentSymbol = SYN; // try again later // TODO error: send failed, abort send + } else { + m_request = startRequest; + m_sendPos = 0; + } + } else { // arbitration lost + sentSymbol = SYN; // try again later // TODO error: lost arbitration + } + } result = m_command.push_back(symbol); if (result < RESULT_OK) return setState(bs_skip, result); - return setState(bs_command, result); + return setState(bs_command, RESULT_OK); case bs_command: headerLen = 4; @@ -152,7 +244,7 @@ result_t BusHandler::receiveSymbol() }*/ return setState(bs_commandAck, RESULT_OK); } - return result; + return RESULT_OK; case bs_commandAck: if (symbol == ESC) @@ -201,7 +293,7 @@ result_t BusHandler::receiveSymbol() }*/ return setState(bs_responseAck, RESULT_OK); } - return result; + return RESULT_OK; case bs_responseAck: if (symbol == ESC) diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 89ebdb1c..8323a020 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -25,10 +25,12 @@ #include "symbol.h" #include "result.h" #include "port.h" +#include "wqueue.h" #include "thread.h" #include #include #include +#include using namespace std; @@ -68,6 +70,50 @@ enum MessageDirection { md_undefined, }; +class BusHandler; + +class BusRequest +{ + friend class BusHandler; +public: + + /** + * @brief Constructor. + */ + BusRequest(SymbolString& master, SymbolString& slave); + + /** + * @brief Destructor. + */ + virtual ~BusRequest(); + + /** + * @brief Wait for notification. + * @return the result code. + */ + bool wait(int timeout); + + /** + * @brief Notify all waiting threads. + */ + void notify(bool finished); + +private: + + SymbolString& m_master; + + SymbolString& m_slave; + + bool m_finished; + + /** a mutex for wait/notify. */ + pthread_mutex_t m_mutex; + + /** a mutex condition for wait/notify. */ + pthread_cond_t m_cond; + +}; + /** * @brief Handles input from and output to the bus with respect to the ebus protocol. @@ -87,13 +133,20 @@ public: unsigned char ownSlaveAddress) : m_port(port), m_messages(messages), m_ownMasterAddress(ownMasterAddress), m_ownSlaveAddress(ownSlaveAddress), m_state(bs_skip), m_repeat(false), - m_sendPos(-1), m_commandCrcValid(false), m_responseCrcValid(false) {} + m_sendPos(-1), m_commandCrcValid(false), m_responseCrcValid(false), m_request(NULL) {} /** * @brief Destructor. */ virtual ~BusHandler() {} + /** + * @brief Send a message on the bus and wait for the answer. + * @param master the @a SymbolString with the master data to send. + * @param slave the @a SymbolString that will be filled with retrieved slave data. + */ + result_t sendAndWait(SymbolString& master, SymbolString& slave); + /** * @brief Main thread entry. */ @@ -157,6 +210,10 @@ private: /** whether the response CRC is valid. */ bool m_responseCrcValid; + WQueue m_requests; + + BusRequest* m_request; + }; From 9cea334407c1a12a47beb2a35cbc418ee929beec Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 12:35:41 +0100 Subject: [PATCH 49/83] better ==, added commented code for debug, added todo --- src/lib/ebus/symbol.cpp | 2 +- src/lib/ebus/symbol.h | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index 6e35772c..253236d4 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -48,7 +48,7 @@ static const unsigned char CRC_LOOKUP_TABLE[] = }; -SymbolString::SymbolString(const string& str) +SymbolString::SymbolString(const string& str) //TODO use a factory method instead : m_unescapeState(0), m_crc(0) { // parse + escape diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index adf5501b..b90a51d8 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -85,7 +85,20 @@ public: * @param other the other instance. * @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols). */ - bool operator==(SymbolString other) { return m_unescapeState==other.m_unescapeState && m_data==other.m_data; } + bool operator==(SymbolString& other) { + return m_unescapeState==other.m_unescapeState && m_data==other.m_data; + /*bool ret = m_unescapeState==other.m_unescapeState && m_data==other.m_data; + for (int i=0; i(m_data[i])<<" "; + } + cout<<"["<(m_unescapeState)<<"]"; + cout<<(ret?" == ":" != "); + for (int i=0; i(other.m_data[i])<<" "; + } + cout<<"["<(other.m_unescapeState)<<"]"< Date: Sat, 6 Dec 2014 12:46:15 +0100 Subject: [PATCH 50/83] reworked result codes, added new base type VTI (vaillant specific time), added support for replacement value for time types --- src/ebusd/baseloop.cpp | 2 +- src/lib/ebus/data.cpp | 154 +++++++++++++++++++------------- src/lib/ebus/data.h | 2 +- src/lib/ebus/result.cpp | 39 ++++---- src/lib/ebus/result.h | 45 +++++----- src/lib/ebus/test/test_data.cpp | 4 +- 6 files changed, 142 insertions(+), 104 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 620f8c21..3344d28a 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -102,7 +102,7 @@ result_t BaseLoop::readConfigFiles(const string path, const string extension) DIR* dir = opendir(path.c_str()); if (dir == NULL) - return RESULT_ERR_FILENOTFOUND; + return RESULT_ERR_NOTFOUND; dirent* d = readdir(dir); diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 75b8c36a..52810c95 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -39,6 +39,7 @@ static const dataType_t dataTypes[] = { {"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) {"HTI", 24, bt_tim, 0, 0, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b) + {"VTI", 24, bt_tim, REV, 0x63, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type] {"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" (0x00 - 0x06) [ebus type] @@ -80,12 +81,12 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co unsigned int ret = strtoul(str, &strEnd, base); if (strEnd == NULL || *strEnd != 0) { - result = RESULT_ERR_INVALID_ARG; // invalid value + result = RESULT_ERR_INVALID_NUM; // invalid value return 0; } if (ret < minValue || ret > maxValue) { - result = RESULT_ERR_INVALID_ARG; // invalid value + result = RESULT_ERR_OUT_OF_RANGE; // invalid value return 0; } if (length != NULL) @@ -130,7 +131,10 @@ result_t DataField::create(vector::iterator& it, vector fields; string firstName, firstComment; result_t result = RESULT_OK; - while (it != end && result == RESULT_OK) { + if (it == end) + return RESULT_ERR_EOF; + + do { string unit, comment; PartType partType; unsigned int divisor = 0; @@ -163,14 +167,14 @@ result_t DataField::create(vector::iterator& it, partType = pt_any; } else { - result = RESULT_ERR_INVALID_ARG; + result = RESULT_ERR_INVALID_PART; break; } string typeStr = *it++; if (typeStr.empty() == true) { if (name.empty() == false || partStr[0] != 0) - result = RESULT_ERR_INVALID_ARG; + result = RESULT_ERR_MISSING_TYPE; break; } @@ -178,11 +182,8 @@ result_t DataField::create(vector::iterator& it, if (it != end) { string divisorStr = *it++; if (divisorStr.empty() == false) { - if (divisorStr.find('=') == string::npos) { + if (divisorStr.find('=') == string::npos) divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result); - if (result != RESULT_OK) - break; - } else { istringstream stream(divisorStr); while (getline(stream, token, VALUE_SEPARATOR) != 0) { @@ -190,15 +191,15 @@ result_t DataField::create(vector::iterator& it, char* strEnd = NULL; unsigned int id = strtoul(str, &strEnd, 10); if (strEnd == NULL || strEnd == str || *strEnd != '=') { - result = RESULT_ERR_INVALID_ARG; + result = RESULT_ERR_INVALID_LIST; break; } values[id] = string(strEnd + 1); } - if (result != RESULT_OK) - break; } + if (result != RESULT_OK) + break; } } @@ -227,18 +228,17 @@ result_t DataField::create(vector::iterator& it, istringstream stream(typeStr); bool found = false; string lengthStr; - while (getline(stream, token, VALUE_SEPARATOR) != 0) { + while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) { DataField* templ = templates->get(token); if (templ == NULL) { if (found == false) break; // fallback to direct definition - result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition - break; + result = RESULT_ERR_NOTFOUND; // cannot mix reference and direct definition + } + else { + found = true; + result = templ->derive("", "", "", partType, divisor, values, fields); } - found = true; - result = templ->derive("", "", "", partType, divisor, values, fields); - if (result != RESULT_OK) - break; } if (result != RESULT_OK) break; @@ -267,7 +267,7 @@ result_t DataField::create(vector::iterator& it, bitCount = 1; // default count: 1 bit } else if (length > bitCount) { - result = RESULT_ERR_INVALID_ARG; // invalid length + result = RESULT_ERR_OUT_OF_RANGE; // invalid length break; } else { @@ -282,7 +282,7 @@ result_t DataField::create(vector::iterator& it, useLength = length; } else { - result = RESULT_ERR_INVALID_ARG; // invalid length + result = RESULT_ERR_OUT_OF_RANGE; // invalid length break; } } @@ -314,7 +314,7 @@ result_t DataField::create(vector::iterator& it, } if (values.begin()->first < dataType.minValueOrLength || values.rbegin()->first > dataType.maxValueOrLength) { - result = RESULT_ERR_INVALID_ARG; + result = RESULT_ERR_OUT_OF_RANGE; break; } @@ -326,14 +326,16 @@ result_t DataField::create(vector::iterator& it, if (add != NULL) fields.push_back(add); else if (result == RESULT_OK) - result = RESULT_ERR_INVALID_ARG; // type not found - } + result = RESULT_ERR_NOTFOUND; // type not found + + } while (it != end && result == RESULT_OK); + if (fields.empty() == true || result != RESULT_OK) { - while (fields.empty() == false) { + while (fields.empty() == false) { // cleanup already created fields delete fields.back(); fields.pop_back(); } - return result == RESULT_OK ? RESULT_ERR_INVALID_ARG :result; + return result == RESULT_OK ? RESULT_ERR_INVALID_ARG : result; } if (fields.size() == 1) @@ -371,11 +373,11 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff offset = 1 + slaveOffset; // skip NN break; default: - return RESULT_ERR_INVALID_ARG; // invalid part type + return RESULT_ERR_INVALID_PART; } if (isIgnored() == true) { if (offset + m_length > input.size()) { - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_INVALID_POS; } return RESULT_OK; } @@ -411,7 +413,7 @@ result_t SingleDataField::write(istringstream& input, offset = 1 + slaveOffset; // skip NN break; default: - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_INVALID_PART; } return writeSymbols(input, offset, output); } @@ -423,7 +425,7 @@ result_t StringDataField::derive(string name, string comment, vector& fields) { if (m_partType != pt_any && partType == pt_any) - return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance + return RESULT_ERR_INVALID_PART; // 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 if (name.empty() == true) @@ -455,7 +457,7 @@ result_t StringDataField::readSymbols(SymbolString& input, unsigned char ch, last = 0; if (baseOffset + m_length > input.size()) { - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_INVALID_POS; } if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) @@ -469,7 +471,7 @@ result_t StringDataField::readSymbols(SymbolString& input, ch = input[baseOffset + offset]; if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) { if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) - return RESULT_ERR_INVALID_ARG; // invalid BCD + return RESULT_ERR_OUT_OF_RANGE; // invalid BCD ch = (ch >> 4) * 10 + (ch & 0x0f); } switch (m_dataType.type) @@ -484,11 +486,21 @@ result_t StringDataField::readSymbols(SymbolString& input, if (i + 1 == m_length) output << (2000 + ch); else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12)) - return RESULT_ERR_INVALID_ARG; // invalid date + return RESULT_ERR_OUT_OF_RANGE; // invalid date else output << setw(2) << setfill('0') << static_cast(ch) << "."; break; case bt_tim: + if (m_dataType.replacement != 0 && ch == m_dataType.replacement) { + if (m_length == 1) { // truncated time + output << NULL_VALUE << ":" << NULL_VALUE; + break; + } + if (i > 0) + output << ":"; + output << NULL_VALUE; + break; + } if (m_length == 1) { // truncated time if (i == 0) { ch /= 6; // hours @@ -498,8 +510,8 @@ result_t StringDataField::readSymbols(SymbolString& input, else ch = (ch % 6) * 10; // minutes } - if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || ( last == 24 && ch > 0) ))) - return RESULT_ERR_INVALID_ARG; // invalid time + if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || (last == 24 && ch > 0) ))) + return RESULT_ERR_OUT_OF_RANGE; // invalid time if (i > 0) output << ":"; output << setw(2) << setfill('0') << static_cast(ch); @@ -549,10 +561,10 @@ result_t StringDataField::writeSymbols(istringstream& input, token.clear(); token.push_back(input.get()); if (input.eof() == true) - return RESULT_ERR_INVALID_ARG; // too short hex value + return RESULT_ERR_INVALID_NUM; // too short hex value token.push_back(input.get()); if (input.eof() == true) - return RESULT_ERR_INVALID_ARG; // too short hex value + return RESULT_ERR_INVALID_NUM; // too short hex value value = parseInt(token.c_str(), 16, 0, 0xff, result); if (result != RESULT_OK) @@ -563,7 +575,7 @@ result_t StringDataField::writeSymbols(istringstream& input, if (m_length == 4 && i == 2) continue; // skip weekday in between if (input.eof() == true || getline(input, token, '.') == 0) - return RESULT_ERR_INVALID_ARG; // incomplete + return RESULT_ERR_EOF; // incomplete value = parseInt(token.c_str(), 10, 0, 2099, result); if (result != RESULT_OK) return result; // invalid date part @@ -578,7 +590,7 @@ result_t StringDataField::writeSymbols(istringstream& input, 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 + return RESULT_ERR_INVALID_NUM; // 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 @@ -588,18 +600,32 @@ result_t StringDataField::writeSymbols(istringstream& input, if (value >= 2000) value -= 2000; else if (value > 99) - return RESULT_ERR_INVALID_ARG; // invalid year + return RESULT_ERR_OUT_OF_RANGE; // invalid year } else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) - return RESULT_ERR_INVALID_ARG; // invalid date part + return RESULT_ERR_OUT_OF_RANGE; // invalid date part break; case bt_tim: if (input.eof() == true || getline(input, token, LENGTH_SEPARATOR) == 0) - return RESULT_ERR_INVALID_ARG; // incomplete + return RESULT_ERR_EOF; // incomplete + if (m_dataType.replacement != 0 && strcmp(token.c_str(), NULL_VALUE) == 0) { + value = m_dataType.replacement; + if (m_length == 1) { // truncated time + if (i == 0) { + last = value; + offset -= incr; // repeat for minutes + count++; + continue; + } + if (last != m_dataType.replacement) + return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes + } + break; + } 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) )) - return RESULT_ERR_INVALID_ARG; // invalid time part + return RESULT_ERR_OUT_OF_RANGE; // invalid time part if (m_length == 1) { // truncated time if (i == 0) { last = value; @@ -608,10 +634,10 @@ result_t StringDataField::writeSymbols(istringstream& input, continue; } if ((value % 10) != 0) - return RESULT_ERR_INVALID_ARG; // invalid truncated time minutes + return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes value = last * 6 + (value / 10); if (value > 24 * 6) - return RESULT_ERR_INVALID_ARG; // invalid time + return RESULT_ERR_OUT_OF_RANGE; // invalid time } break; default: @@ -628,16 +654,16 @@ result_t StringDataField::writeSymbols(istringstream& input, last = value; if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) { if (value > 99) - return RESULT_ERR_INVALID_ARG; // invalid BCD + return RESULT_ERR_OUT_OF_RANGE; // invalid BCD value = ((value / 10) << 4) | (value % 10); } if (value > 0xff) - return RESULT_ERR_INVALID_ARG; // value out of range + return RESULT_ERR_OUT_OF_RANGE; // value out of range output[baseOffset + offset] = (unsigned char)value; } if (i < m_length) - return RESULT_ERR_INVALID_ARG; // input too short + return RESULT_ERR_EOF; // input too short return RESULT_OK; } @@ -669,7 +695,7 @@ result_t NumericDataField::readRawValue(SymbolString& input, unsigned char ch; if (baseOffset + m_length > input.size()) - return RESULT_ERR_INVALID_ARG; // not enough data available + return RESULT_ERR_INVALID_POS; // not enough data available if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) start = m_length - 1; @@ -685,7 +711,7 @@ result_t NumericDataField::readRawValue(SymbolString& input, return RESULT_OK; } if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) - return RESULT_ERR_INVALID_ARG; // invalid BCD + return RESULT_ERR_OUT_OF_RANGE; // invalid BCD ch = (ch >> 4) * 10 + (ch & 0x0f); value += ch * exp; @@ -720,7 +746,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, if ((m_dataType.flags & BCD) == 0) { if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0) - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_OUT_OF_RANGE; value <<= m_bitOffset; } @@ -754,7 +780,7 @@ result_t NumberDataField::derive(string name, string comment, vector& fields) { if (m_partType != pt_any && partType == pt_any) - return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance + return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance if (name.empty() == true) name = m_name; if (comment.empty() == true) @@ -834,7 +860,7 @@ result_t NumberDataField::writeSymbols(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 + return RESULT_ERR_EOF; // input too short else { char* strEnd = NULL; if (m_divisor <= 1) { @@ -848,17 +874,17 @@ result_t NumberDataField::writeSymbols(istringstream& input, else value = strtoul(str, &strEnd, 10); if (strEnd == NULL || *strEnd != 0) - return RESULT_ERR_INVALID_ARG; // invalid value + return RESULT_ERR_INVALID_NUM; // invalid value } else { char* strEnd = NULL; double dvalue = strtod(str, &strEnd); if (strEnd == NULL || *strEnd != 0) - return RESULT_ERR_INVALID_ARG; // invalid value + return RESULT_ERR_INVALID_NUM; // invalid value dvalue = round(dvalue * m_divisor); 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 + return RESULT_ERR_OUT_OF_RANGE; // value out of range if (dvalue < 0 && m_bitCount != 32) value = (unsigned int) (dvalue + (1 << m_bitCount)); else @@ -866,7 +892,7 @@ result_t NumberDataField::writeSymbols(istringstream& input, } else { if (dvalue < 0.0 || dvalue >= (1LL << (8 * m_length))) - return RESULT_ERR_INVALID_ARG; // value out of range + return RESULT_ERR_OUT_OF_RANGE; // value out of range value = (unsigned int) dvalue; } } @@ -874,13 +900,13 @@ result_t NumberDataField::writeSymbols(istringstream& input, if ((m_dataType.flags & SIG) != 0) { // 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 + return RESULT_ERR_OUT_OF_RANGE; // value out of range } else if (value > m_dataType.maxValueOrLength) - return RESULT_ERR_INVALID_ARG; // value out of range + return RESULT_ERR_OUT_OF_RANGE; // value out of range } else if (value < m_dataType.minValueOrLength || value > m_dataType.maxValueOrLength) - return RESULT_ERR_INVALID_ARG; // value out of range + return RESULT_ERR_OUT_OF_RANGE; // value out of range } return writeRawValue(value, baseOffset, output); @@ -893,7 +919,7 @@ result_t ValueListDataField::derive(string name, string comment, vector& fields) { if (m_partType != pt_any && partType == pt_any) - return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance + return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance if (name.empty() == true) name = m_name; if (comment.empty() == true) @@ -951,7 +977,7 @@ result_t ValueListDataField::readSymbols(SymbolString& input, return RESULT_OK; } - return RESULT_ERR_INVALID_ARG; // value assignment not found + return RESULT_ERR_NOTFOUND; // value assignment not found } result_t ValueListDataField::writeSymbols(istringstream& input, @@ -969,7 +995,7 @@ result_t ValueListDataField::writeSymbols(istringstream& input, if (strcasecmp(str, NULL_VALUE) == 0) return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value - return RESULT_ERR_INVALID_ARG; // value assignment not found + return RESULT_ERR_NOTFOUND; // value assignment not found } DataFieldSet::~DataFieldSet() @@ -1095,7 +1121,7 @@ result_t DataFieldSet::write(istringstream& input, if (ignored == true) token.clear(); else if (getline(input, token, separator) == 0) - return RESULT_ERR_INVALID_ARG; // incomplete + return RESULT_ERR_EOF; // incomplete istringstream single(token); result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 9e8c4b75..196eeb11 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -614,7 +614,7 @@ public: ifstream ifs; ifs.open(filename.c_str(), ifstream::in); if (ifs.is_open() == false) - return RESULT_ERR_FILENOTFOUND; + return RESULT_ERR_NOTFOUND; string line; unsigned int lineNo = 0; diff --git a/src/lib/ebus/result.cpp b/src/lib/ebus/result.cpp index 4146db05..66cea24a 100644 --- a/src/lib/ebus/result.cpp +++ b/src/lib/ebus/result.cpp @@ -24,24 +24,31 @@ using namespace std; const char* getResultCode(result_t resultCode) { switch (resultCode) { - case RESULT_ERR_SEND: return "ERR_SEND: send error"; - case RESULT_ERR_EXTRA_DATA: return "ERR_EXTRA_DATA: received bytes > sent bytes"; - case RESULT_ERR_NAK: return "ERR_NAK: NAK received"; - case RESULT_ERR_CRC: return "ERR_CRC: CRC error"; - case RESULT_ERR_ACK: return "ERR_ACK: ACK error"; - case RESULT_ERR_TIMEOUT: return "ERR_TIMEOUT: read timeout"; - case RESULT_ERR_SYN: return "ERR_SYN: SYN received"; - case RESULT_ERR_BUS_LOST: return "ERR_BUS_LOST: lost bus arbitration"; - case RESULT_ERR_ESC: return "ERR_ESC: invalid escape sequence received"; - case RESULT_ERR_INVALID_ARG: return "ERR_INVALID_ARG: invalid argument specified"; - case RESULT_ERR_DEVICE: return "ERR_DEVICE: generic device error"; - case RESULT_ERR_EOF: return "ERR_EOF: end of input reached"; - case RESULT_ERR_FILENOTFOUND: return "ERR_FILENOTFOUND: file not found or not readable"; - case RESULT_ERR_DUPLICATE: return "ERR_DUPLICATE: duplicate entry"; + case RESULT_IN_ESC: return "success: escape sequence received"; + case RESULT_SYN: return "success: SYN received"; + case RESULT_ERR_GENERIC_IO: return "ERR: generic I/O error"; + case RESULT_ERR_DEVICE: return "ERR: generic device error"; + case RESULT_ERR_SEND: return "ERR: send error"; + case RESULT_ERR_ESC: return "ERR: invalid escape sequence"; + case RESULT_ERR_TIMEOUT: return "ERR: read timeout"; + case RESULT_ERR_NOTFOUND: return "ERR: file/element not found or not readable"; + case RESULT_ERR_EOF: return "ERR: end of input reached"; + case RESULT_ERR_INVALID_ARG: return "ERR: invalid argument"; + case RESULT_ERR_INVALID_NUM: return "ERR: invalid numeric argument"; + case RESULT_ERR_INVALID_POS: return "ERR: invalid position"; + case RESULT_ERR_OUT_OF_RANGE: return "ERR: argument value out of valid range"; + case RESULT_ERR_INVALID_PART: return "ERR: invalid part type value"; + case RESULT_ERR_MISSING_TYPE: return "ERR: missing data type"; + case RESULT_ERR_INVALID_LIST: return "ERR: invalid value list"; + case RESULT_ERR_DUPLICATE: return "ERR: duplicate entry"; + case RESULT_ERR_BUS_LOST: return "ERR: arbitration lost"; + case RESULT_ERR_CRC: return "ERR: CRC error"; + case RESULT_ERR_ACK: return "ERR: ACK error"; + case RESULT_ERR_NAK: return "ERR: NAK received"; default: if (resultCode >= 0) - return "success"; - return "ERR: unknown error code"; + return "success: unknown result code"; + return "ERR: unknown result code"; } } diff --git a/src/lib/ebus/result.h b/src/lib/ebus/result.h index 1870a5da..f419e31b 100644 --- a/src/lib/ebus/result.h +++ b/src/lib/ebus/result.h @@ -20,29 +20,32 @@ #ifndef LIBEBUS_RESULT_H_ #define LIBEBUS_RESULT_H_ -static const int RESULT_OK = 0; +static const int RESULT_OK = 0; // success -static const int RESULT_BUS_ACQUIRED = 1; // bus successfully acquired -static const int RESULT_DATA = 2; // some data received -static const int RESULT_SYN = 3; // regular SYN after message received -static const int RESULT_BUS_LOCKED = 4; // bus is locked for access -static const int RESULT_BUS_PRIOR_RETRY = 5; // retry to access bus -static const int RESULT_IN_ESC = 6; // start of escape sequence received +static const int RESULT_IN_ESC = 1; // start of escape sequence received +static const int RESULT_SYN = 2; // regular SYN after message received -static const int RESULT_ERR_SEND = -1; // send error -static const int RESULT_ERR_EXTRA_DATA = -2; // received bytes > sent bytes -static const int RESULT_ERR_NAK = -3; // NAK received -static const int RESULT_ERR_CRC = -4; // CRC error -static const int RESULT_ERR_ACK = -5; // ACK error -static const int RESULT_ERR_TIMEOUT = -6; // read timeout -static const int RESULT_ERR_SYN = -7; // SYN received -static const int RESULT_ERR_BUS_LOST = -8; // arbitration lost -static const int RESULT_ERR_ESC = -9; // invalid escape sequence received -static const int RESULT_ERR_INVALID_ARG = -10; // invalid argument -static const int RESULT_ERR_DEVICE = -11; // generic device error (usually fatal) -static const int RESULT_ERR_EOF = -12; // end of input reached -static const int RESULT_ERR_FILENOTFOUND = -13;// file not found or not readable -static const int RESULT_ERR_DUPLICATE = -14; // duplicate entry +static const int RESULT_ERR_GENERIC_IO = -1; // generic I/O error (usually fatal) +static const int RESULT_ERR_DEVICE = -2; // generic device error (usually fatal) +static const int RESULT_ERR_SEND = -3; // send error +static const int RESULT_ERR_ESC = -4; // invalid escape sequence +static const int RESULT_ERR_TIMEOUT = -5; // read timeout + +static const int RESULT_ERR_NOTFOUND = -6; // file/element not found or not readable +static const int RESULT_ERR_EOF = -7; // end of input reached +static const int RESULT_ERR_INVALID_ARG = -8; // invalid argument +static const int RESULT_ERR_INVALID_NUM = -9; // invalid numeric argument +static const int RESULT_ERR_INVALID_POS = -10; // invalid position +static const int RESULT_ERR_OUT_OF_RANGE = -11; // argument value out of valid range +static const int RESULT_ERR_INVALID_PART = -12; // invalid part type value +static const int RESULT_ERR_MISSING_TYPE = -13; // missing data type +static const int RESULT_ERR_INVALID_LIST = -14; // invalid value list +static const int RESULT_ERR_DUPLICATE = -15; // duplicate entry + +static const int RESULT_ERR_BUS_LOST = -16; // arbitration lost +static const int RESULT_ERR_CRC = -17; // CRC error +static const int RESULT_ERR_ACK = -18; // ACK error +static const int RESULT_ERR_NAK = -19; // NAK received /** type for result code. */ typedef int result_t; diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index efb0f081..7f668f15 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -69,6 +69,8 @@ int main() {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, {"x;;bti", "", "10fe070003605923", "00", "rw"}, {"x;;hti", "21:04:58", "10fe07000315043a", "00", ""}, + {"x;;vti", "21:04:58", "10fe0700033a0415", "00", ""}, + {"x;;vti", "-:-:-", "10fe070003636363", "00", ""}, {"x;;htm", "21:04", "10fe0700021504", "00", ""}, {"x;;htm", "00:00", "10fe0700020000", "00", ""}, {"x;;htm", "23:59", "10fe070002173b", "00", ""}, @@ -78,7 +80,7 @@ int main() {"x;;ttm", "22:40", "10fe07000188", "00", ""}, {"x;;ttm", "00:00", "10fe07000100", "00", ""}, {"x;;ttm", "23:50", "10fe0700018f", "00", ""}, - {"x;;ttm", "24:00", "10fe07000190", "00", ""}, + {"x;;ttm", "-:-", "10fe07000190", "00", ""}, {"x;;ttm", "", "10fe07000191", "00", "rw"}, {"x;;bdy", "Mon", "10fe07000300", "00", ""}, {"x;;bdy", "Sun", "10fe07000306", "00", ""}, From 0e1e724f628968127b290838dfb0798531b71d2d Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 12:46:15 +0100 Subject: [PATCH 51/83] reworked result codes, added new base type VTI (vaillant specific time), added support for replacement value for time types --- src/lib/ebus/port.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index 08defe83..42027cf0 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -146,7 +146,7 @@ result_t DeviceSerial::openDevice(const string deviceName, const bool noDeviceCh m_fd = open(deviceName.c_str(), O_RDWR | O_NOCTTY); if (m_fd < 0) - return RESULT_ERR_FILENOTFOUND; + return RESULT_ERR_NOTFOUND; // save current settings of serial device tcgetattr(m_fd, &m_oldSettings); @@ -213,13 +213,13 @@ result_t DeviceNetwork::openDevice(const string deviceName, const bool noDeviceC he = gethostbyname(host); if (he == NULL) - return RESULT_ERR_FILENOTFOUND; + return RESULT_ERR_NOTFOUND; memcpy(&sock.sin_addr, he->h_addr_list[0], he->h_length); } else { ret = inet_aton(host, &sock.sin_addr); if (ret == 0) - return RESULT_ERR_FILENOTFOUND; + return RESULT_ERR_NOTFOUND; } sock.sin_family = AF_INET; @@ -227,11 +227,11 @@ result_t DeviceNetwork::openDevice(const string deviceName, const bool noDeviceC m_fd = socket(AF_INET, SOCK_STREAM, 0); if (m_fd < 0) - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_GENERIC_IO; ret = connect(m_fd, (struct sockaddr*) &sock, sizeof(sock)); if (ret < 0) - return RESULT_ERR_INVALID_ARG; + return RESULT_ERR_GENERIC_IO; free(hostport); m_open = true; From 38f0ddbe78dfae54899a0fdd282b477b3cde0ae3 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 12:47:48 +0100 Subject: [PATCH 52/83] simplified message type detection --- src/lib/ebus/message.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 26ce9764..34020834 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -80,7 +80,7 @@ result_t Message::create(vector::iterator& it, const vector::ite { // [type];[class];name;[comment];[QQ];ZZ;id;fields... result_t result; - bool isSet = false, isPassive = true; + bool isSet = false, isPassive = false; char defaultsChar; unsigned int pollPriority = 0; size_t defaultPos = 1; @@ -90,15 +90,12 @@ result_t Message::create(vector::iterator& it, const vector::ite const char* str = (*it++).c_str(); if (it == end) return RESULT_ERR_EOF; - if (str[0] == 0 || strcasecmp(str, "R") == 0) { // default: active get - isPassive = false; + if (str[0] == 0 || strncasecmp(str, "R", 1) == 0) { // default: active get defaultsChar = 'r'; - } else if (strcasecmp(str, "W") == 0) { // active set - isPassive = false; + } else if (strncasecmp(str, "W", 1) == 0) { // active set isSet = true; defaultsChar = 'w'; - } else if (str[0] == 'P' || str[0] == 'p') { // poll (=active get) - isPassive = false; + } else if (strncasecmp(str, "P", 1) == 0) { // poll (=active get) if (str[1] == 0) pollPriority = 1; else { @@ -109,14 +106,14 @@ result_t Message::create(vector::iterator& it, const vector::ite } defaultsChar = 'r'; } else if (str[0] >= '0' && str[0] <= '9') { // poll priority (=active get) - isPassive = false; result_t result; pollPriority = parseInt(str, 10, 1, 9, result); if (result != RESULT_OK) return result; defaultsChar = 'r'; } else { // any other: passive set/get - isSet = str[1] == 'W' || str[1] == 'w'; + isPassive = true; + isSet = strncasecmp(str+1, "R", 1) == 0; defaultsChar = str[0]; } From 73b74f16026298d9b29ae70e46577ddb0fefc6c6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 13:02:16 +0100 Subject: [PATCH 53/83] implemented get --- src/ebusd/Makefile.am | 2 +- src/ebusd/bushandler.cpp | 357 ++++++++++++++++++++++++--------------- src/ebusd/bushandler.h | 68 +++++--- 3 files changed, 266 insertions(+), 161 deletions(-) diff --git a/src/ebusd/Makefile.am b/src/ebusd/Makefile.am index 2a1ab2a5..5d060fb6 100644 --- a/src/ebusd/Makefile.am +++ b/src/ebusd/Makefile.am @@ -16,7 +16,7 @@ ebusd_SOURCES = bushandler.cpp \ ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ $(top_srcdir)/src/lib/ebus/libebus.a \ - -lpthread + -lpthread -lrt distclean-local: -rm -f Makefile.in diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 8951a03d..3152a700 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -35,28 +35,31 @@ extern Logger& L; extern Appl& A; /** - * @brief Return the string corresponding to the @a BusState and send position. + * @brief Return the string corresponding to the @a BusState. * @param state the @a BusState. - * @param sendPos >=0 while sending data, -1 while receiving data. * @return the string corresponding to the @a BusState. */ -const char* getStateCode(BusState state, int sendPos) { +const char* getStateCode(BusState state) { switch (state) { - case bs_skip: return "skip"; - case bs_ready: return "ready"; - case bs_command: return sendPos < 0 ? "receive command" : "send command"; - case bs_commandAck: return sendPos < 0 ? "receive command ACK" : "send command ACK"; - case bs_response: return sendPos < 0 ? "receive response" : "send response"; - case bs_responseAck: return sendPos < 0 ? "receive response ACK" : "send response ACK"; - //case bs_validTransfer: return sendPos < 0 ? "after complete receive" : "after complete send"; - default: return "unknown state"; + case bs_skip: return "skip"; + case bs_ready: return "ready"; + case bs_sendCmd: return "send command"; + case bs_recvCmdAck: return "receive command ACK"; + case bs_recvRes: return "receive response"; + case bs_sendResAck: return "send response ACK"; + case bs_recvCmd: return "receive command"; + case bs_recvResAck: return "receive response ACK"; +// case bs_sendRes: return "send response"; +// case bs_sendCmdAck: return "send command ACK"; + case bs_sendSyn: return "send SYN"; + default: return "unknown"; } } BusRequest::BusRequest(SymbolString& master, SymbolString& slave) - : m_master(master), m_slave(slave), m_finished(false) + : m_master(master), m_slave(slave), m_finished(false), m_result(RESULT_SYN) { pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cond, NULL); @@ -88,11 +91,12 @@ bool BusRequest::wait(int timeout) return result == 0; } -void BusRequest::notify(bool finished) +void BusRequest::notify(result_t result) { pthread_mutex_lock(&m_mutex); - m_finished = finished; + m_result = result; + m_finished = true; pthread_mutex_unlock(&m_mutex); } @@ -103,29 +107,24 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) BusRequest* request = new BusRequest(master, slave); m_requests.add(request); - bool result = request->wait(5); - if (result == false) + bool success = request->wait(5); + if (success == false) m_requests.remove(request); + result_t result = request->m_result; delete request; - return result == true ? RESULT_OK : RESULT_ERR_TIMEOUT; + return success == true ? result : RESULT_ERR_TIMEOUT; } void BusHandler::run() { - result_t result = RESULT_OK; do { - if (m_port->isOpen() == true) { - result = receiveSymbol(); - - if (result != RESULT_OK) - L.log(bus, error, " %s", getResultCode(result)); - - } + if (m_port->isOpen() == true) + handleSymbol(); else { // TODO: define max reopen sleep(10); - result = m_port->open(); + result_t result = m_port->open(); if (result != RESULT_OK) L.log(bus, error, "can't open %s", A.getOptVal("device")); @@ -135,46 +134,72 @@ void BusHandler::run() } while (isRunning() == true); } -result_t BusHandler::receiveSymbol() +#define RECV_TIMEOUT 4500 + +result_t BusHandler::handleSymbol() { - long timeout; - ssize_t count; - unsigned char sentSymbol = SYN; - BusRequest* startRequest = NULL; - if (m_state == bs_skip) - timeout = 0; - else if (m_sendPos >= 0) { - timeout = SLAVE_RECV_TIMEOUT; - if (m_sendPos+1 < m_request->m_master.size()) { - m_sendPos++; - sentSymbol = m_request->m_master[m_sendPos]; - if (m_port->send(&sentSymbol) != 1) { - sentSymbol = SYN; // try again later // TODO error: send failed, abort send - m_request->notify(false); - m_request = NULL; - m_sendPos = -1; - } + long timeout = SYN_TIMEOUT; + unsigned char sendSymbol = ESC; + bool sending = false; + + // check if another symbol has to be sent and determine timeout for receive + switch (m_state) + { + case bs_skip: + timeout = 0; // endless + break; + + case bs_ready: + m_request = m_requests.next(false); + if (m_request != NULL) { // initiate arbitration + sendSymbol = m_request->m_master[0]; + sending = true; } + break; + + case bs_recvCmd: + case bs_recvCmdAck: + case bs_recvRes: + case bs_recvResAck: + timeout = SLAVE_RECV_TIMEOUT; + break; + + case bs_sendCmd: + if (m_request != NULL) { + sendSymbol = m_request->m_master[m_nextSendPos]; + sending = true; + } + break; + + case bs_sendResAck: + if (m_request != NULL) { + sendSymbol = m_responseCrcValid ? ACK : NAK; + sending = true; + } + break; + + case bs_sendSyn: + sendSymbol = SYN; + sending = true; + break; } - else { - timeout = SYN_TIMEOUT; - if (m_state == bs_ready && m_request == NULL) { - startRequest = m_requests.next(false); - if (startRequest != NULL) { - // initiate arbitration - sentSymbol = startRequest->m_master[0]; - if (m_port->send(&sentSymbol) != 1) { - sentSymbol = SYN; // try again later // TODO error: send failed - startRequest = NULL; - } - } + + // send symbol if necessary + if (sending == true) { + if (m_port->send(&sendSymbol, 1) == 1) + timeout = RECV_TIMEOUT; + else { + sending = false; + timeout = 0; + setState(bs_skip, RESULT_ERR_SEND); } } - count = m_port->recv(timeout, 1); + // receive next symbol (optionally check reception of sent symbol) + ssize_t count = m_port->recv(timeout, 1); if (count < 0) - return setState(bs_skip, RESULT_ERR_DEVICE); + return setState(bs_skip, count); if (count == 0) { if (m_state == bs_ready) @@ -182,11 +207,9 @@ result_t BusHandler::receiveSymbol() return setState(bs_skip, RESULT_ERR_TIMEOUT); } - unsigned char symbol = m_port->byte(); - if (symbol == SYN) { - m_repeat = false; - return setState(bs_ready, RESULT_OK); - } + unsigned char recvSymbol = m_port->byte(); + if (recvSymbol == SYN) + return setState(bs_ready, RESULT_SYN); unsigned char headerLen, crcPos; result_t result; @@ -197,128 +220,185 @@ result_t BusHandler::receiveSymbol() return RESULT_OK; case bs_ready: - if (symbol == ESC) - return setState(bs_skip, RESULT_ERR_ESC); - if (m_sendPos < 0 && sentSymbol != SYN) { + if (m_request != NULL && sending == true) { // check arbitration - if (symbol == sentSymbol) { // arbitration successful - if (m_requests.remove(startRequest) == false) { - sentSymbol = SYN; // try again later // TODO error: send failed, abort send - } else { - m_request = startRequest; - m_sendPos = 0; + if (recvSymbol == sendSymbol) { // arbitration successful + if (m_requests.remove(m_request) == false) { + // request already timed out + m_request = NULL; + return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); } - } else { // arbitration lost - sentSymbol = SYN; // try again later // TODO error: lost arbitration + m_nextSendPos = 1; + m_repeat = false; + return setState(bs_sendCmd, RESULT_OK); } + // arbitration lost + setState(m_state, RESULT_ERR_BUS_LOST); // try again later } - result = m_command.push_back(symbol); + result = m_command.push_back(recvSymbol, false); // expect no escaping for master address if (result < RESULT_OK) return setState(bs_skip, result); - return setState(bs_command, RESULT_OK); + m_repeat = false; + return setState(bs_recvCmd, RESULT_OK); - case bs_command: + case bs_recvCmd: headerLen = 4; crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; - result = m_command.push_back(symbol, true, m_command.size() < crcPos); + result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos); if (result < RESULT_OK) return setState(bs_skip, result); - if (result == RESULT_OK && m_command.size() == crcPos + 1) { // CRC received + if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received + unsigned char dstAddress = m_command[1]; + //if (isValidAddress(dstAddress) == false || isMaster(m_command[0]) == false) + // return setState(bs_skip, RESULT_ERR_INVALID_ADDR); + m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); - if (m_command[1] == BROADCAST) { - if (m_commandCrcValid) { + if (m_commandCrcValid) { + if (dstAddress == BROADCAST) { transferCompleted(tt_broadcast); return setState(bs_skip, RESULT_OK); } + //if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress) + // return setState(bs_sendCmdAck, RESULT_OK); - return setState(bs_skip, RESULT_ERR_CRC); + return setState(bs_recvCmdAck, RESULT_OK); } - /*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) { - setState(bs_commandAck, RESULT_OK); - m_sendPos = 0; - symbol = m_commandCrcValid ? ACK : NAK; - if (m_port->send(&symbol) <= 0) - return setState(bs_skip, RESULT_ERR_SEND); - }*/ - return setState(bs_commandAck, RESULT_OK); + if (dstAddress == BROADCAST) + return setState(bs_skip, RESULT_OK); + + //if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress) + // return setState(bs_sendCmdAck, RESULT_ERR_CRC); + if (m_repeat == true) + return setState(bs_skip, RESULT_ERR_CRC); + return setState(bs_recvCmdAck, RESULT_ERR_CRC); } return RESULT_OK; - case bs_commandAck: - if (symbol == ESC) - return setState(bs_skip, RESULT_ERR_ESC); - /*if (m_sendPos >= 0) { - if (symbol == ACK && m_commandCrcValid == true) - return setState(); - - return setState() - }*/ - if (symbol == ACK) { + case bs_recvCmdAck: + if (recvSymbol == ACK) { if (m_commandCrcValid == false) return setState(bs_skip, RESULT_ERR_ACK); - if (isMaster(m_command[1]) == true) { + if (m_request != NULL) { + if (isMaster(m_request->m_master[1]) == true) { + transferCompleted(tt_masterMaster); + return setState(bs_sendSyn, RESULT_OK); + } + } else if (isMaster(m_command[1]) == true) { transferCompleted(tt_masterMaster); return setState(bs_skip, RESULT_OK); } - return setState(bs_response, RESULT_OK); + m_repeat = false; + return setState(bs_recvRes, RESULT_OK); } - if (symbol == NAK) { + if (recvSymbol == NAK) { if (m_repeat == false) { m_repeat = true; - return setState(bs_ready, RESULT_ERR_NAK); + m_nextSendPos = 0; + m_command.clear(); + if (m_request != NULL) + return setState(bs_sendCmd, RESULT_ERR_NAK); + + return setState(bs_recvCmd, RESULT_ERR_NAK); } + if (m_request != NULL) + return setState(bs_sendSyn, RESULT_ERR_NAK); + return setState(bs_skip, RESULT_ERR_NAK); } + if (m_request != NULL) + return setState(bs_sendSyn, RESULT_ERR_ACK); + return setState(bs_skip, RESULT_ERR_ACK); - case bs_response: + case bs_recvRes: headerLen = 0; crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff; - result = m_response.push_back(symbol, true, m_response.size() < crcPos); - if (result < RESULT_OK) - return setState(bs_skip, result); + result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos); + if (result < RESULT_OK) { + if (m_request != NULL) + return setState(bs_sendSyn, result); - if (result == RESULT_OK && m_response.size() == crcPos + 1) { // CRC received + return setState(bs_skip, result); + } + if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC(); - /*if (m_command[1] == m_ownSlaveAddress || m_command[1] == m_ownMasterAddress) { - setState(bs_responseAck, RESULT_OK); - m_sendPos = 0; - symbol = m_responseCrcValid ? ACK : NAK; - if (m_port->send(&symbol) <= 0) - return setState(bs_skip, RESULT_ERR_SEND); - }*/ - return setState(bs_responseAck, RESULT_OK); + if (m_responseCrcValid) { + if (m_request != NULL) + return setState(bs_sendResAck, RESULT_OK); + + return setState(bs_recvResAck, RESULT_OK); + } + if (m_repeat == true) { + if (m_request != NULL) + return setState(bs_sendSyn, RESULT_ERR_CRC); + + return setState(bs_skip, RESULT_ERR_CRC); + } + if (m_request != NULL) + return setState(bs_sendResAck, RESULT_ERR_CRC); + + return setState(bs_recvResAck, RESULT_ERR_CRC); } return RESULT_OK; - case bs_responseAck: - if (symbol == ESC) - return setState(bs_skip, RESULT_ERR_ESC); - /*if (m_sendPos >= 0) { - if (symbol == ACK && m_responseCrcValid == true) - return setState(); - - return setState() - }*/ - if (symbol == ACK) { + case bs_recvResAck: + if (recvSymbol == ACK) { if (m_responseCrcValid == false) return setState(bs_skip, RESULT_ERR_ACK); transferCompleted(tt_masterSlave); return setState(bs_skip, RESULT_OK); } - if (symbol == NAK) { + if (recvSymbol == NAK) { if (m_repeat == false) { m_repeat = true; - return setState(bs_response, RESULT_ERR_NAK); + m_response.clear(); + return setState(bs_recvRes, RESULT_ERR_NAK); } return setState(bs_skip, RESULT_ERR_NAK); } return setState(bs_skip, RESULT_ERR_ACK); + + case bs_sendCmd: + if (m_request != NULL && sending == true) { + if (recvSymbol == sendSymbol) { + // successfully sent + m_nextSendPos++; + if (m_nextSendPos >= m_request->m_master.size()) { + // master data completely sent + if (m_request->m_master[1] == BROADCAST) + return setState(bs_sendSyn, RESULT_OK); + + m_commandCrcValid = true; + return setState(bs_recvCmdAck, RESULT_OK); + } + return RESULT_OK; + } + } + return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG); + + case bs_sendResAck: + if (m_request != NULL && sending == true) { + if (recvSymbol == sendSymbol) { + // successfully sent + return setState(bs_sendSyn, RESULT_OK); + } + } + return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG); + + case bs_sendSyn: + if (sending == true) { + if (recvSymbol == sendSymbol) { + // successfully sent + return setState(bs_skip, RESULT_OK); + } + } + return setState(bs_skip, RESULT_ERR_INVALID_ARG); + } return RESULT_OK; @@ -330,18 +410,27 @@ result_t BusHandler::setState(BusState state, result_t result) return result; if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) - L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state, m_sendPos), getStateCode(state, m_sendPos)); + L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state)); m_state = state; + if (m_request != NULL) { + if (state == bs_sendSyn) { + m_request->m_slave = m_response; // TODO nicer + m_request->notify(result); + m_request = NULL; + } else if (result != RESULT_OK) { + m_request->notify(result); + m_request = NULL; + } + } + if (state == bs_ready || state == bs_skip) { m_command.clear(); m_commandCrcValid = false; m_response.clear(); m_responseCrcValid = false; - m_sendPos = -1; + m_nextSendPos = 0; } - if (state == bs_skip) - m_repeat = false; return result; } @@ -367,7 +456,7 @@ void BusHandler::transferCompleted(TransferType type) ostringstream output; result_t result = msg->decode(m_command, m_response, output); if (result != RESULT_OK) - L.log(bus, error, "unable to parse %s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), getResultCode(result)); + L.log(bus, error, "unable to parse %s %s from %s / %s: %s", msg->getClass().c_str(), msg->getName().c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result)); else L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 8323a020..5fefb461 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -36,18 +36,22 @@ using namespace std; /** the maximum allowed time [us] for retrieval of a single symbol from an addressed slave. */ #define SLAVE_RECV_TIMEOUT 10000 -/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol. */ +/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol (should be generated in <45ms). */ #define SYN_TIMEOUT 50000 /** the possible bus states. */ enum BusState { - bs_skip, // skip all symbols until next @a SYN - bs_ready, // ready for next master (after @a SYN symbol, send/receive QQ) - bs_command, // receive/send command (ZZ, PBSB, master data) - bs_commandAck, // receive/send command ACK/NACK - bs_response, // receive/send response (slave data) - bs_responseAck, // receive/send response ACK/NACK - //bs_validTransfer,// completed a valid message transfer + bs_skip, // skip all symbols until next @a SYN + bs_ready, // ready for next master (after @a SYN symbol, send/receive QQ) + bs_recvCmd, // receive command (ZZ, PBSB, master data) [passive set] + bs_recvCmdAck, // receive command ACK/NACK [passive set + active set+get] + bs_recvRes, // receive response (slave data) [passive set + active get] + bs_recvResAck, // receive response ACK/NACK [passive set] + bs_sendCmd, // send command (ZZ, PBSB, master data) [active set+get] + bs_sendResAck, // send response ACK/NACK [active get] +// bs_sendRes, // send response (slave data) [passive get] // TODO implement +// bs_sendCmdAck, // send command ACK/NACK [passive get] // TODO implement + bs_sendSyn, // send SYN for completed transfer [active set+get] }; /** the possible message transfer types. */ @@ -62,9 +66,9 @@ enum MessageDirection { md_thisToAll, // message from us to all (broadcast) md_thisToMaster, // message from us to another master md_thisToSlave, // message from us to another slave - md_otherToAll, // message from a master (other than us) to all (broadcast): @a bs_ready, @a bs_recvCmd - md_otherToMaster, // message from a master (other than us) to another master (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck - md_otherToSlave, // message from a master (other than us) to another slave (other than us): @a bs_ready, @a bs_recvCmd, @a bs_recvAck, @a bs_recvResp, @a bs_recvAck + md_otherToAll, // message from a master (other than us) to all (broadcast) + md_otherToMaster, // message from a master (other than us) to another master (other than us) + md_otherToSlave, // message from a master (other than us) to another slave (other than us) md_otherToThisMaster, // message from a master (other than us) to us (as master) md_otherToThisSlave, // message from a master (other than us) to us (as slave) md_undefined, @@ -72,6 +76,9 @@ enum MessageDirection { class BusHandler; +/** + * @brief Handles input from and output to the bus with respect to the ebus protocol. + */ class BusRequest { friend class BusHandler; @@ -79,6 +86,8 @@ public: /** * @brief Constructor. + * @param master the master data @a SymbolString to send. + * @param slave the slave data @a SymbolString received. */ BusRequest(SymbolString& master, SymbolString& slave); @@ -96,16 +105,22 @@ public: /** * @brief Notify all waiting threads. */ - void notify(bool finished); + void notify(result_t result); private: + /** the master data @a SymbolString to send. */ SymbolString& m_master; + /** the slave data @a SymbolString received. */ SymbolString& m_slave; + /** true once the request is finished. */ bool m_finished; + /** the result of handling the request. */ + result_t m_result; + /** a mutex for wait/notify. */ pthread_mutex_t m_mutex; @@ -132,8 +147,9 @@ public: BusHandler(Port* port, MessageMap* messages, unsigned char ownMasterAddress, unsigned char ownSlaveAddress) : m_port(port), m_messages(messages), m_ownMasterAddress(ownMasterAddress), - m_ownSlaveAddress(ownSlaveAddress), m_state(bs_skip), m_repeat(false), - m_sendPos(-1), m_commandCrcValid(false), m_responseCrcValid(false), m_request(NULL) {} + m_ownSlaveAddress(ownSlaveAddress), m_request(NULL), m_nextSendPos(0), + m_state(bs_skip), m_repeat(false), + m_commandCrcValid(false), m_responseCrcValid(false) {} /** * @brief Destructor. @@ -155,10 +171,10 @@ public: private: /** - * @brief Receive another symbol from the bus. + * @brief Handle the next symbol on the bus. * @return RESULT_OK on success, or an error code. */ - result_t receiveSymbol(); + result_t handleSymbol(); /** * @brief Set a new @a BusState and add a log message if necessary. @@ -186,18 +202,22 @@ private: /** the own slave address to react on master-slave messages, or @a SYN to ignore. */ unsigned char m_ownSlaveAddress; + /** the queue of @a BusRequests that shall be handled. */ + WQueue m_requests; + + /** the currently handled BusRequest, or NULL. */ + BusRequest* m_request; + + /** the offset of the next symbol that needs to be sent from the command or response, + * (only relevant if m_request is set and state is bs_command or bs_response). */ + unsigned char m_nextSendPos; + /** the current @a BusState. */ BusState m_state; /** whether the current message part is being repeated. */ bool m_repeat; - /* - * the offset of the last sent symbol while sending command/response, - * or 0 while sending ACK/NACK, or -1 if not sending. - */ - int m_sendPos; - /** the received/sent command. */ SymbolString m_command; @@ -210,10 +230,6 @@ private: /** whether the response CRC is valid. */ bool m_responseCrcValid; - WQueue m_requests; - - BusRequest* m_request; - }; From 2bd88f45dbe910bf93213c9acc9edb35aa0a3af1 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 13:46:52 +0100 Subject: [PATCH 54/83] fix for walking through added messages --- src/lib/ebus/message.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 34020834..a2b8d271 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -45,7 +45,7 @@ Message::Message(const string clazz, const string name, const bool isSet, key |= 0x1fLL << (8 * exp--); // special value for active key |= (unsigned long long)dstAddress << (8 * exp--); for (vector::const_iterator it=id.begin(); it=m_maxIdLength; idLength--) { + for (int idLength=maxIdLength; idLength>=m_minIdLength; idLength--) { int exp = 7; unsigned long long key = (unsigned long long)idLength << (8 * exp + 5); key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--); From 482e849a1ecbd7fce3193a901a1ec910d40113a6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 15:22:41 +0100 Subject: [PATCH 55/83] use result code --- src/lib/ebus/port.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index 42027cf0..e338a220 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -72,7 +72,7 @@ ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes) ssize_t Device::recvBytes(const long timeout, size_t maxCount) { if (isValid() == false) - return -1; // TODO RESULT_ERR_DEVICE + return RESULT_ERR_DEVICE; if (timeout > 0) { int ret; From fe66df7afac935f7c2e200e8b452ce9da670dcae Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 15:23:23 +0100 Subject: [PATCH 56/83] added missing code, formatting --- src/lib/ebus/result.cpp | 51 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/lib/ebus/result.cpp b/src/lib/ebus/result.cpp index 66cea24a..43f850e2 100644 --- a/src/lib/ebus/result.cpp +++ b/src/lib/ebus/result.cpp @@ -24,31 +24,32 @@ using namespace std; const char* getResultCode(result_t resultCode) { switch (resultCode) { - case RESULT_IN_ESC: return "success: escape sequence received"; - case RESULT_SYN: return "success: SYN received"; - case RESULT_ERR_GENERIC_IO: return "ERR: generic I/O error"; - case RESULT_ERR_DEVICE: return "ERR: generic device error"; - case RESULT_ERR_SEND: return "ERR: send error"; - case RESULT_ERR_ESC: return "ERR: invalid escape sequence"; - case RESULT_ERR_TIMEOUT: return "ERR: read timeout"; - case RESULT_ERR_NOTFOUND: return "ERR: file/element not found or not readable"; - case RESULT_ERR_EOF: return "ERR: end of input reached"; - case RESULT_ERR_INVALID_ARG: return "ERR: invalid argument"; - case RESULT_ERR_INVALID_NUM: return "ERR: invalid numeric argument"; - case RESULT_ERR_INVALID_POS: return "ERR: invalid position"; - case RESULT_ERR_OUT_OF_RANGE: return "ERR: argument value out of valid range"; - case RESULT_ERR_INVALID_PART: return "ERR: invalid part type value"; - case RESULT_ERR_MISSING_TYPE: return "ERR: missing data type"; - case RESULT_ERR_INVALID_LIST: return "ERR: invalid value list"; - case RESULT_ERR_DUPLICATE: return "ERR: duplicate entry"; - case RESULT_ERR_BUS_LOST: return "ERR: arbitration lost"; - case RESULT_ERR_CRC: return "ERR: CRC error"; - case RESULT_ERR_ACK: return "ERR: ACK error"; - case RESULT_ERR_NAK: return "ERR: NAK received"; - default: - if (resultCode >= 0) - return "success: unknown result code"; - return "ERR: unknown result code"; + case RESULT_OK: return "success"; + case RESULT_IN_ESC: return "success: escape sequence received"; + case RESULT_SYN: return "success: SYN received"; + case RESULT_ERR_GENERIC_IO: return "ERR: generic I/O error"; + case RESULT_ERR_DEVICE: return "ERR: generic device error"; + case RESULT_ERR_SEND: return "ERR: send error"; + case RESULT_ERR_ESC: return "ERR: invalid escape sequence"; + case RESULT_ERR_TIMEOUT: return "ERR: read timeout"; + case RESULT_ERR_NOTFOUND: return "ERR: file/element not found or not readable"; + case RESULT_ERR_EOF: return "ERR: end of input reached"; + case RESULT_ERR_INVALID_ARG: return "ERR: invalid argument"; + case RESULT_ERR_INVALID_NUM: return "ERR: invalid numeric argument"; + case RESULT_ERR_INVALID_POS: return "ERR: invalid position"; + case RESULT_ERR_OUT_OF_RANGE: return "ERR: argument value out of valid range"; + case RESULT_ERR_INVALID_PART: return "ERR: invalid part type value"; + case RESULT_ERR_MISSING_TYPE: return "ERR: missing data type"; + case RESULT_ERR_INVALID_LIST: return "ERR: invalid value list"; + case RESULT_ERR_DUPLICATE: return "ERR: duplicate entry"; + case RESULT_ERR_BUS_LOST: return "ERR: arbitration lost"; + case RESULT_ERR_CRC: return "ERR: CRC error"; + case RESULT_ERR_ACK: return "ERR: ACK error"; + case RESULT_ERR_NAK: return "ERR: NAK received"; + default: + if (resultCode >= 0) + return "success: unknown result code"; + return "ERR: unknown result code"; } } From d71a9623e7f2895ffeb3b7e4a76195235a172f97 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 15:26:33 +0100 Subject: [PATCH 57/83] unified output --- src/lib/ebus/test/test_message.cpp | 13 ++++++++----- src/lib/ebus/test/test_symbol.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) mode change 100644 => 100755 src/lib/ebus/test/test_symbol.cpp diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 63eb475e..6a5d17fe 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -53,7 +53,7 @@ int main() {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, {"u;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "pm"}, {"","55.50;ok","1025b50903290000","050000780300",""}, - + {"","no;25","10feb505042700190023","",""}, }; DataFieldTemplates* templates = new DataFieldTemplates(); result_t result = templates->readFromFile("_types.csv"); @@ -95,10 +95,10 @@ int main() if (entries.size() == 0) { message = messages->find(mstr); if (message == NULL) { - cout << " find error: NULL" << endl; + cout << "\"" << check[2] << "\": find error: NULL" << endl; continue; } - cout << " find OK" << endl; + cout << "\"" << check[2] << "\": find OK" << endl; } else { vector::iterator it = entries.begin(); result = Message::create(it, entries.end(), NULL, templates, deleteMessage); @@ -134,10 +134,13 @@ int main() cout << " map OK" << endl; message = deleteMessage; deleteMessage = NULL; - if (messages->find(mstr) == message) + Message* foundMessage = messages->find(mstr); + if (foundMessage == message) cout << " find OK" << endl; - else + else if (foundMessage == NULL) cout << " find error: NULL" << endl; + else + cout << " find error: different" << endl; } else message = deleteMessage; diff --git a/src/lib/ebus/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp old mode 100644 new mode 100755 index b91c3f6e..a3858469 --- a/src/lib/ebus/test/test_symbol.cpp +++ b/src/lib/ebus/test/test_symbol.cpp @@ -30,17 +30,17 @@ int main () std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177"; if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) - std::cout << "ctor escaped successful." << std::endl; + std::cout << "ctor escaped OK" << std::endl; else - std::cout << "ctor escaped invalid: got " << gotStr << ", expected " + std::cout << "ctor escaped error: got " << gotStr << ", expected " << expectStr << std::endl; unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77; if (gotCrc == expectCrc) - std::cout << "CRC successful." << std::endl; + std::cout << "CRC OK" << std::endl; else - std::cout << "CRC invalid: got 0x" << std::nouppercase << std::setw(2) + std::cout << "CRC error: got 0x" << std::nouppercase << std::setw(2) << std::hex << std::setfill('0') << static_cast(gotCrc) << ", expected 0x" << std::nouppercase << std::setw(2) << std::hex @@ -50,9 +50,9 @@ int main () gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77"; if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) - std::cout << "unescape successful." << std::endl; + std::cout << "unescape OK" << std::endl; else - std::cout << "unescape invalid: got " << gotStr << ", expected " + std::cout << "unescape error: got " << gotStr << ", expected " << expectStr << std::endl; sstr = SymbolString("10feb5050427a90015a90177", true); @@ -60,9 +60,9 @@ int main () gotStr = sstr.getDataStr(); if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0) - std::cout << "ctor unescaped successful." << std::endl; + std::cout << "ctor unescaped OK" << std::endl; else - std::cout << "ctor unescaped invalid: got " << gotStr << ", expected " + std::cout << "ctor unescaped error: got " << gotStr << ", expected " << expectStr << std::endl; return 0; From 1c633928698b2a5c7cae46d3f6ddb27c5fe4114c Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 15:26:33 +0100 Subject: [PATCH 58/83] unified output --- src/lib/ebus/test/test_symbol.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/ebus/test/test_symbol.cpp diff --git a/src/lib/ebus/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp old mode 100755 new mode 100644 From b831df5ecae9a3f4fdd760ad3a22487cd4455800 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 15:33:46 +0100 Subject: [PATCH 59/83] corrected prepareMaster() --- src/lib/ebus/message.cpp | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index a2b8d271..0b1def37 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -243,23 +243,33 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma return RESULT_ERR_INVALID_ARG; // prepare not possible 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); - 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, m_id.size() - 2, slaveData, 0, separator); + result_t result = masterData.push_back(srcAddress, false); if (result != RESULT_OK) return result; - masterData.push_back(masterData.getCRC(), false, false); - /*if (slaveData.size() > 0) { - return RESULT_ERR_INVALID_ARG; // TODO support answering MS queries (set slave length, calc crc) - }*/ - return RESULT_OK; + result = masterData.push_back(m_dstAddress, false); + if (result != RESULT_OK) + return result; + result = masterData.push_back(m_id[0], false); + if (result != RESULT_OK) + return result; + result = masterData.push_back(m_id[1], false); + if (result != RESULT_OK) + return result; + unsigned char addData = m_data->getLength(pt_masterData); + result = masterData.push_back(m_id.size() - 2 + addData, false); + if (result != RESULT_OK) + return result; + for (size_t i=2; iwrite(input, masterData, m_id.size() - 2, slaveData, 0, separator); + if (result != RESULT_OK) + return result; + result = masterData.push_back(masterData.getCRC(), false, false); // + return result; } result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, From 382da6215ccb5b9c9dc1d7ea14c128e501f20065 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 16:44:52 +0100 Subject: [PATCH 60/83] reduced DataField::read() and ::write() to a single SymbolString, adjusted message accordingly --- src/lib/ebus/data.cpp | 106 +++++++++++++---------------- src/lib/ebus/data.h | 76 ++++++++------------- src/lib/ebus/message.cpp | 14 ++-- src/lib/ebus/message.h | 6 +- src/lib/ebus/test/test_data.cpp | 11 ++- src/lib/ebus/test/test_message.cpp | 4 +- 6 files changed, 99 insertions(+), 118 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 52810c95..8f619b72 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -357,35 +357,39 @@ void SingleDataField::dump(ostream& output) output << FIELD_SEPARATOR << m_dataType.name; } -result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - ostringstream& output, +result_t SingleDataField::read(const PartType partType, + SymbolString& data, unsigned char offset, + ostringstream& output, bool leadingSeparator, bool verbose, char separator) { - SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData; - unsigned char offset; + if (partType != m_partType) + return RESULT_OK; + switch (m_partType) { case pt_masterData: - offset = 5 + masterOffset; // skip QQ ZZ PB SB NN + offset += 5; // skip QQ ZZ PB SB NN break; case pt_slaveData: - offset = 1 + slaveOffset; // skip NN + offset += 1; // skip NN break; default: return RESULT_ERR_INVALID_PART; } if (isIgnored() == true) { - if (offset + m_length > input.size()) { + if (offset + m_length > data.size()) { return RESULT_ERR_INVALID_POS; } return RESULT_OK; } + if (leadingSeparator == true) + output << separator; + if (verbose == true) output << m_name << "="; - result_t result = readSymbols(input, offset, output); + result_t result = readSymbols(data, offset, output); if (result != RESULT_OK) return result; @@ -398,24 +402,24 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff } result_t SingleDataField::write(istringstream& input, - SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - char separator) + const PartType partType, SymbolString& data, + unsigned char offset, char separator) { - SymbolString& output = m_partType != pt_slaveData ? masterData : slaveData; - unsigned char offset; + if (partType != m_partType) + return RESULT_OK; + switch (m_partType) { case pt_masterData: - offset = 5 + masterOffset; // skip QQ ZZ PB SB NN + offset += 5; // skip QQ ZZ PB SB NN break; case pt_slaveData: - offset = 1 + slaveOffset; // skip NN + offset += 1; // skip NN break; default: return RESULT_ERR_INVALID_PART; } - return writeSymbols(input, offset, output); + return writeSymbols(input, offset, data); } @@ -1050,41 +1054,32 @@ void DataFieldSet::dump(ostream& output) (*it)->dump(output); } -result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - ostringstream& output, bool verbose, char separator) +result_t DataFieldSet::read(const PartType partType, + SymbolString& data, unsigned char offset, + ostringstream& output, bool leadingSeparator, + bool verbose, char separator) { if (verbose) output << m_name << "={ "; - bool first = true; - unsigned char offsets[3]; - memset(offsets, 0, sizeof(offsets)); - offsets[pt_masterData] = masterOffset; - offsets[pt_slaveData] = slaveOffset; - bool previousFullByteOffset[] = { true, true, true }; + bool previousFullByteOffset = true; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; - bool ignored = field->isIgnored(); - PartType partType = field->getPartType(); + if (partType != pt_any && field->getPartType() != partType) + continue; - if (ignored == false) { - if (first) - first = false; - else - output << separator; - } - if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) - offsets[partType]--; + if (previousFullByteOffset == false && field->hasFullByteOffset(false) == false) + offset--; - result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator); +//cout<<"read "<getName().c_str()<<" in part "<(field->getPartType())<<" offset "<(offsets[field->getPartType()])<read(partType, data, offset, output, leadingSeparator, verbose, separator); if (result != RESULT_OK) return result; - offsets[partType] += field->getLength(partType); - - previousFullByteOffset[partType] = field->hasFullByteOffset(true); + offset += field->getLength(partType); + previousFullByteOffset = field->hasFullByteOffset(true); + leadingSeparator |= field->isIgnored() == false; } if (verbose == true) { @@ -1097,43 +1092,38 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset } result_t DataFieldSet::write(istringstream& input, - SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - char separator) + const PartType partType, SymbolString& data, + unsigned char offset, char separator) { string token; - unsigned char offsets[3]; - memset(offsets, 0, sizeof(offsets)); - offsets[pt_masterData] = masterOffset; - offsets[pt_slaveData] = slaveOffset; - bool previousFullByteOffset[] = { true, true, true }; + bool previousFullByteOffset = true; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; - bool ignored = field->isIgnored(); - PartType partType = field->getPartType(); + if (partType != pt_any && field->getPartType() != partType) + continue; - if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) - offsets[partType]--; + if (previousFullByteOffset == false && field->hasFullByteOffset(false) == false) + offset--; result_t result; if (m_fields.size() > 1) { - if (ignored == true) + if (field->isIgnored() == true) token.clear(); else if (getline(input, token, separator) == 0) - return RESULT_ERR_EOF; // incomplete + token.clear(); istringstream single(token); - result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); + result = (*it)->write(single, partType, data, offset, separator); } else - result = (*it)->write(input, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); + result = (*it)->write(input, partType, data, offset, separator); if (result != RESULT_OK) return result; - offsets[partType] += field->getLength(partType); - previousFullByteOffset[partType] = field->hasFullByteOffset(true); + offset += field->getLength(partType); + previousFullByteOffset = field->hasFullByteOffset(true); } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 196eeb11..49e3f59f 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -164,33 +164,33 @@ public: */ virtual void dump(ostream& output) = 0; /** - * @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 additional offset to add for reading the master data. - * @param slaveData the unescaped slave data @a SymbolString for reading binary data. - * @param slaveOffset the additional offset to add for reading the slave data. + * @brief Reads the value from the @a SymbolString. + * @param partType the @a PartType of the data. + * @param data the unescaped data @a SymbolString for reading binary data. + * @param offset the additional offset to add for reading binary data. * @param output the @a ostringstream to append the formatted value to. + * @param leadingSeparator whether to prepend a separator before the formatted value. * @param verbose whether to prepend the name, append the unit (if present), and append * the comment in square brackets (if present). * @param separator the separator character between multiple fields. - * @return @a RESULT_OK on success, or an error code. + * @return @a RESULT_OK on success (or if the partType does not match), or an error code. */ - virtual result_t read(SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - ostringstream& output, + virtual result_t read(const PartType partType, + SymbolString& data, unsigned char offset, + ostringstream& output, bool leadingSeparator=false, bool verbose=false, char separator=';') = 0; /** * @brief Writes the value to the master or slave @a SymbolString. * @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 partType the @a PartType of the data. + * @param data the unescaped data @a SymbolString for writing binary data. + * @param offset the additional offset to add 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(istringstream& input, - SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - char separator=';') = 0; + const PartType partType, SymbolString& data, + unsigned char offset, char separator=';') = 0; protected: @@ -255,34 +255,15 @@ public: virtual bool hasFullByteOffset(bool after) { return true; } // @copydoc virtual void dump(ostream& output); - /** - * @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, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - ostringstream& output, - bool verbose, char separator); - /** - * @brief Writes the value to the master or slave @a SymbolString. - * @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. - */ + // @copydoc + virtual result_t read(const PartType partType, + SymbolString& data, unsigned char offset, + ostringstream& output, bool leadingSeparator=false, + bool verbose=false, char separator=';'); + // @copydoc virtual result_t write(istringstream& input, - SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - char separator); + const PartType partType, SymbolString& data, + unsigned char offset, char separator=';');//TODO replace protected: @@ -569,15 +550,14 @@ public: // @copydoc virtual void dump(ostream& output); // @copydoc - virtual result_t read(SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - ostringstream& output, - bool verbose, char separator); + virtual result_t read(const PartType partType, + SymbolString& data, unsigned char offset, + ostringstream& output, bool leadingSeparator=false, + bool verbose=false, char separator=';'); // @copydoc virtual result_t write(istringstream& input, - SymbolString& masterData, unsigned char masterOffset, - SymbolString& slaveData, unsigned char slaveOffset, - char separator); + const PartType partType, SymbolString& data, + unsigned char offset, char separator=';'); private: diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 0b1def37..d233c5a7 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -264,18 +264,22 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma if (result != RESULT_OK) return result; } - SymbolString slaveData; - result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator); + result = m_data->write(input, pt_masterData, masterData, m_id.size() - 2, separator); if (result != RESULT_OK) return result; - result = masterData.push_back(masterData.getCRC(), false, false); // + result = masterData.push_back(masterData.getCRC(), false, false); // TODO only if calculated return result; } -result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, +result_t Message::decode(const PartType partType, SymbolString& data, ostringstream& output, char separator) { - result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); + unsigned char offset; + if (partType == pt_masterData) + offset = m_id.size() - 2; + else + offset = 0; + result_t result = m_data->read(partType, data, offset, output, false, false, separator); if (result != RESULT_OK) return result; /*if (m_isPassive == false && answer == true) { diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 25373f5d..4c975bdb 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -146,13 +146,13 @@ public: istringstream& input, char separator=';'); /** * @brief Decode a received message. - * @param masterData the unescaped received master @a SymbolString. - * @param slaveData the unescaped received slave @a SymbolString. + * @param partType the @a PartType of the data. + * @param data the unescaped data @a SymbolString for reading binary data. * @param output the @a ostringstream to append the formatted value to. * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - result_t decode(SymbolString& masterData, SymbolString& slaveData, + result_t decode(const PartType partType, SymbolString& data, ostringstream& output, char separator=';'); private: diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 7f668f15..4096b032 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -97,7 +97,7 @@ int main() {"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", ""}, + {"x;s;uch;;;;y;m;uch", "3;2","1025ffff0103", "0102", ""}, {"x;;uch", "38", "10feffff0126", "00", ""}, {"x;;uch", "0", "10feffff0100", "00", ""}, {"x;;uch", "254", "10feffff01fe", "00", ""}, @@ -249,7 +249,10 @@ int main() 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); + result = fields->read(pt_masterData, mstr, 0, output, false, verbose); + if (result == RESULT_OK) { + result = fields->read(pt_slaveData, sstr, 0, output, output.str().empty() == false, verbose); + } if (failedRead == true) if (result == RESULT_OK) cout << " failed read " << fields->getName() << " >" @@ -268,7 +271,9 @@ int main() if (verbose == false) { istringstream input(expectStr); - result = fields->write(input, writeMstr, 0, writeSstr, 0); + result = fields->write(input, pt_masterData, writeMstr, 0); + if (result == RESULT_OK) + result = fields->write(input, pt_slaveData, writeSstr, 0); if (failedWrite == true) { if (result == RESULT_OK) cout << " failed write " << fields->getName() << " >" diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 6a5d17fe..5509a8f5 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -149,7 +149,9 @@ int main() SymbolString writeMstr = SymbolString(); if (message->isPassive() == true) { ostringstream output; - result = message->decode(mstr, sstr, output); + result = message->decode(pt_masterData, mstr, output); + if (result == RESULT_OK) + result = message->decode(pt_slaveData, sstr, output); if (result != RESULT_OK) { cout << " \"" << inputStr << "\": decode error: " << getResultCode(result) << endl; From f5a9f2b1d121d7aa93b89571f6aa7afb7894a7c8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 16:45:20 +0100 Subject: [PATCH 61/83] code style --- src/lib/utils/wqueue.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/utils/wqueue.h b/src/lib/utils/wqueue.h index 35d72b81..5362571e 100644 --- a/src/lib/utils/wqueue.h +++ b/src/lib/utils/wqueue.h @@ -75,7 +75,7 @@ public: pthread_mutex_lock(&m_mutex); T item; - if (wait) { + if (wait == true) { while (m_queue.size() == 0) pthread_cond_wait(&m_cond, &m_mutex); item = m_queue.front(); @@ -117,7 +117,7 @@ public: pthread_mutex_lock(&m_mutex); T item; - if (wait) { + if (wait == true) { while (m_queue.size() == 0) pthread_cond_wait(&m_cond, &m_mutex); item = m_queue.front(); From b0749c8662e5159e9a71c0bdbac36d8c67c8051e Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 16:54:14 +0100 Subject: [PATCH 62/83] fixes for get+hex --- src/ebusd/baseloop.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 3344d28a..a6f56a89 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -228,23 +228,26 @@ string BaseLoop::decodeMessage(const string& data) SymbolString master; istringstream input; - message->prepareMaster(m_ownAddress, master, input); + result_t ret = message->prepareMaster(m_ownAddress, master, input); + if (ret != RESULT_OK) { + L.log(bas, error, " prepare message: %s", getResultCode(ret)); + result << getResultCode(ret); + break; + } L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); // send message SymbolString slave; - result_t ret = m_busHandler->sendAndWait(master, slave); + ret = m_busHandler->sendAndWait(master, slave); if (ret == RESULT_OK) // decode data - ret = message->decode(master, slave, result); + ret = message->decode(pt_slaveData, slave, result);// TODO reduce to requested variable only if (ret != RESULT_OK) { L.log(bas, error, " %s", getResultCode(ret)); result << getResultCode(ret); } - else - result << result.str(); // TODO reduce to requested variable only } else { result << "ebus command not found"; @@ -347,7 +350,7 @@ string BaseLoop::decodeMessage(const string& data) ostringstream msg; msg << hex << setw(2) << setfill('0') << static_cast(m_ownAddress); msg << cmd[1]; - SymbolString master(cmd[1]); + SymbolString master(msg.str()); L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); // send message @@ -362,8 +365,7 @@ string BaseLoop::decodeMessage(const string& data) L.log(bas, error, " %s", getResultCode(ret)); result << getResultCode(ret); } - else - result << result.str(); // TODO reduce to requested variable only + } break; From c4812bd16cb2528e57bec076cb72ec6e2ffa6465 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 16:54:32 +0100 Subject: [PATCH 63/83] reduced DataField::read() and ::write() to a single SymbolString, adjusted BusHandler accordingly, fix for BusRequest::notify, added define for and corrected send timeout, added syn after failed send, fixed cleanup, reduced logging --- src/ebusd/bushandler.cpp | 58 +++++++++++++++++++++++----------------- src/ebusd/bushandler.h | 8 ++++-- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 3152a700..0373e3ba 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -97,6 +97,7 @@ void BusRequest::notify(result_t result) m_result = result; m_finished = true; + pthread_cond_signal(&m_cond); pthread_mutex_unlock(&m_mutex); } @@ -134,8 +135,6 @@ void BusHandler::run() } while (isRunning() == true); } -#define RECV_TIMEOUT 4500 - result_t BusHandler::handleSymbol() { long timeout = SYN_TIMEOUT; @@ -187,7 +186,7 @@ result_t BusHandler::handleSymbol() // send symbol if necessary if (sending == true) { if (m_port->send(&sendSymbol, 1) == 1) - timeout = RECV_TIMEOUT; + timeout = SEND_TIMEOUT; else { sending = false; timeout = 0; @@ -198,12 +197,18 @@ result_t BusHandler::handleSymbol() // receive next symbol (optionally check reception of sent symbol) ssize_t count = m_port->recv(timeout, 1); - if (count < 0) + if (count <= 0 && m_state == bs_ready && sending == false) + return RESULT_OK; // TODO keep "no signal" within auto-syn state + + if (count < 0) { // count < 0 is a RESULT_ERR_ code + if (m_request != NULL) + return setState(bs_sendSyn, count); return setState(bs_skip, count); + } if (count == 0) { - if (m_state == bs_ready) - return RESULT_OK; // TODO keep "no signal" within auto-syn state + if (m_request != NULL) + return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); return setState(bs_skip, RESULT_ERR_TIMEOUT); } @@ -221,18 +226,19 @@ result_t BusHandler::handleSymbol() case bs_ready: if (m_request != NULL && sending == true) { + if (m_requests.remove(m_request) == false) { + // request already timed out + m_request = NULL; + return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); + } // check arbitration if (recvSymbol == sendSymbol) { // arbitration successful - if (m_requests.remove(m_request) == false) { - // request already timed out - m_request = NULL; - return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); - } m_nextSendPos = 1; m_repeat = false; return setState(bs_sendCmd, RESULT_OK); } // arbitration lost + m_request = NULL; setState(m_state, RESULT_ERR_BUS_LOST); // try again later } result = m_command.push_back(recvSymbol, false); // expect no escaping for master address @@ -411,18 +417,21 @@ result_t BusHandler::setState(BusState state, result_t result) if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state)); - - m_state = state; + else if (m_request != NULL || state == bs_sendCmd || state==bs_sendResAck || state==bs_sendSyn) + L.log(bus, trace, " switching from %s to %s", getStateCode(m_state), getStateCode(state)); if (m_request != NULL) { if (state == bs_sendSyn) { +// L.log(bus, trace, "notify request (syn): %s", getResultCode(result)); m_request->m_slave = m_response; // TODO nicer m_request->notify(result); m_request = NULL; } else if (result != RESULT_OK) { +// L.log(bus, trace, "notify request: %s", getResultCode(result)); m_request->notify(result); m_request = NULL; } } + m_state = state; if (state == bs_ready || state == bs_skip) { m_command.clear(); @@ -437,6 +446,18 @@ result_t BusHandler::setState(BusState state, result_t result) void BusHandler::transferCompleted(TransferType type) { + Message* msg = m_messages->find(m_command); + if (msg != NULL) { + ostringstream output; + result_t result = msg->decode(pt_masterData, m_command, output); + if (result == RESULT_OK) + result = msg->decode(pt_slaveData, m_response, output); + if (result != RESULT_OK) + L.log(bus, error, "unable to parse %s %s from %s / %s: %s", msg->getClass().c_str(), msg->getName().c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result)); + else + L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); + return; + } switch (type) { case tt_broadcast: @@ -448,16 +469,5 @@ void BusHandler::transferCompleted(TransferType type) case tt_masterSlave: L.log(bus, trace, "received master %s, slave %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); break; - default: - return; - } - Message* msg = m_messages->find(m_command); - if (msg != NULL) { - ostringstream output; - result_t result = msg->decode(m_command, m_response, output); - if (result != RESULT_OK) - L.log(bus, error, "unable to parse %s %s from %s / %s: %s", msg->getClass().c_str(), msg->getName().c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result)); - else - L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); } } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 5fefb461..299abb67 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -34,10 +34,14 @@ using namespace std; -/** the maximum allowed time [us] for retrieval of a single symbol from an addressed slave. */ +/** the maximum allowed time [us] for retrieving a symbol from an addressed slave. */ #define SLAVE_RECV_TIMEOUT 10000 -/** the maximum allowed time [us] for retrieval of an AUTO-SYN symbol (should be generated in <45ms). */ +/** the maximum allowed time [us] for retrieving the AUTO-SYN symbol (should be generated in <45ms). */ #define SYN_TIMEOUT 50000 +/** the maximum duration [us] of a single symbol. */ +#define SYMBOL_DURATION 5100 +/** the maximum allowed time [us] for retrieving back a sent symbol. */ +#define SEND_TIMEOUT 6000 /** the possible bus states. */ enum BusState { From 62fc5046e22ecf8d99de4d5e00354e6b47465344 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 21:24:24 +0100 Subject: [PATCH 64/83] added optional direct buffer to write to (instead of queuing the data), extended raw logging to include sent symbols --- src/lib/ebus/port.cpp | 26 +++++++++++++++++++------- src/lib/ebus/port.h | 29 +++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index e338a220..c9adc96c 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -69,7 +69,7 @@ ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes) return write(m_fd, buffer, nbytes); } -ssize_t Device::recvBytes(const long timeout, size_t maxCount) +ssize_t Device::recvBytes(const long timeout, size_t maxCount, unsigned char* buffer) { if (isValid() == false) return RESULT_ERR_DEVICE; @@ -102,16 +102,26 @@ ssize_t Device::recvBytes(const long timeout, size_t maxCount) ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL); #endif #endif - if (ret == -1) return RESULT_ERR_DEVICE; if (ret == 0) return RESULT_ERR_TIMEOUT; } + if (buffer != NULL) { + // read bytes from device directly into provided buffer + ssize_t nbytes = read(m_fd, buffer, maxCount); + if (nbytes == 0) + return RESULT_ERR_EOF; + + return nbytes; + } + if (maxCount > sizeof(m_buffer)) maxCount = sizeof(m_buffer); - // read bytes from device + // read bytes from device into temporary buffer ssize_t nbytes = read(m_fd, m_buffer, maxCount); + if (nbytes == 0) + return RESULT_ERR_EOF; for (int i = 0; i < nbytes; i++) m_recvBuffer.push(m_buffer[i]); @@ -154,10 +164,11 @@ result_t DeviceSerial::openDevice(const string deviceName, const bool noDeviceCh memset(&newSettings, '\0', sizeof(newSettings)); newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD); - newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - newSettings.c_iflag |= IGNPAR; + newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode + newSettings.c_iflag |= IGNPAR; // ignore parity errors newSettings.c_oflag &= ~OPOST; + // non-canonical mode: read() blocks until at least one byte is available newSettings.c_cc[VMIN] = 1; newSettings.c_cc[VTIME] = 0; @@ -251,7 +262,8 @@ void DeviceNetwork::closeDevice() } -Port::Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, void (*logRawFunc)(const unsigned char byte), +Port::Port(const string deviceName, const bool noDeviceCheck, + const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received), const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize) : m_deviceName(deviceName), m_noDeviceCheck(noDeviceCheck), m_logRaw(logRaw), m_logRawFunc(logRawFunc), @@ -275,7 +287,7 @@ unsigned char Port::byte() unsigned char byte = m_device->getByte(); if (m_logRaw == true && m_logRawFunc != NULL) - (*m_logRawFunc)(byte); + (*m_logRawFunc)(byte, true); if (m_dumpRaw == true && m_dumpRawStream.is_open() == true) { m_dumpRawStream.write((char*)&byte, 1); diff --git a/src/lib/ebus/port.h b/src/lib/ebus/port.h index 124dd147..a81fdb28 100644 --- a/src/lib/ebus/port.h +++ b/src/lib/ebus/port.h @@ -92,9 +92,10 @@ public: * @brief recvBytes read bytes from opened file descriptor. * @param timeout time for new input data [usec]. * @param maxCount max size of receive buffer. + * @param buffer optional direct buffer to write to (instead of queuing the data). * @return number of read bytes or -1 if an error has occured. */ - ssize_t recvBytes(const long timeout, size_t maxCount); + ssize_t recvBytes(const long timeout, size_t maxCount, unsigned char* buffer=NULL); /** * @brief fetch first byte from receive buffer. @@ -208,7 +209,8 @@ public: * @param dumpRawFile the name of the file to dump raw data to. * @param dumpRawMaxSize the maximum size of @a m_dumpFile. */ - Port(const string deviceName, const bool noDeviceCheck, const bool logRaw, void (*logRawFunc)(const unsigned char byte), + Port(const string deviceName, const bool noDeviceCheck, + const bool logRaw, void (*logRawFunc)(const unsigned char byte, bool received), const bool dumpRaw, const char* dumpRawFile, const long dumpRawMaxSize); /** @@ -239,16 +241,27 @@ public: * @return number of written bytes or -1 if an error has occured. */ ssize_t send(const unsigned char* buffer, size_t nbytes = MAX_WRITE_SIZE) - { return m_device->sendBytes(buffer, nbytes); } + { + ssize_t ret = m_device->sendBytes(buffer, nbytes); + if (ret>0 && m_logRaw == true && m_logRawFunc != NULL) + (*m_logRawFunc)(buffer[0], false); + return ret; + } /** * @brief recv read bytes from opened file descriptor. - * @param timeout max time out for new input data [usec]. + * @param timeout max time out for new input data [usec], or 0 for infinite. * @param maxCount max size of receive buffer. - * @return number of read bytes or -1 if an error has occured. + * @param buffer optional direct buffer to write to (instead of queuing the data). + * @return number of read bytes (never 0) or a negative result_t code. */ - ssize_t recv(const long timeout, size_t maxCount = MAX_READ_SIZE) - { return m_device->recvBytes(timeout, maxCount); } + ssize_t recv(const long timeout, size_t maxCount = MAX_READ_SIZE, unsigned char* buffer=NULL) + { + ssize_t ret = m_device->recvBytes(timeout, maxCount, buffer); + if (buffer && ret>0 && m_logRaw == true && m_logRawFunc != NULL) + (*m_logRawFunc)(buffer[0], true); + return ret; + } /** * @brief fetch first byte from receive buffer. @@ -312,7 +325,7 @@ private: bool m_logRaw; /** a function to call for logging raw data, or NULL. */ - void (*m_logRawFunc)(const unsigned char byte); + void (*m_logRawFunc)(const unsigned char byte, bool received); /** whether dumping of raw data to a file is enabled. */ bool m_dumpRaw; From c5c9c436dcc2abc37a8f24dfd563f29134acc073 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 21:48:33 +0100 Subject: [PATCH 65/83] extended raw logging to also include sent symbols, added optionas for and implemented: send+lock retries, lock counter, bus acquisition+slave receive timeout, switched to directly receiving bytes instead of queuing them, only send SYN when send is complete, adjusted default timeouts to include 2*1,2% tolerance --- src/ebusd/baseloop.cpp | 26 +++++-- src/ebusd/baseloop.h | 7 +- src/ebusd/bushandler.cpp | 149 +++++++++++++++++++++------------------ src/ebusd/bushandler.h | 68 ++++++++++++------ src/ebusd/ebusd.cpp | 4 +- 5 files changed, 155 insertions(+), 99 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index a6f56a89..3f408c79 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -52,7 +52,7 @@ BaseLoop::BaseLoop() L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());*/ m_ownAddress = A.getOptVal("address") & 0xff; - bool answer = A.getOptVal("answer"); + const bool answer = A.getOptVal("answer"); const bool logRaw = A.getOptVal("lograwdata"); @@ -60,6 +60,12 @@ BaseLoop::BaseLoop() const char* dumpRawFile = A.getOptVal("dumpfile"); const long dumpRawMaxSize = A.getOptVal("dumpsize"); + const unsigned int busLostRetries = A.getOptVal("lockretries"); + const unsigned int failedSendRetries = A.getOptVal("sendretries"); + const unsigned int busAcquireWaitTime = A.getOptVal("acquiretimeout"); + const unsigned int slaveRecvTimeout = A.getOptVal("recvtimeout"); + const unsigned int lockCount = A.getOptVal("lockcounter"); + // create Port m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &BaseLoop::logRaw, dumpRaw, dumpRawFile, dumpRawMaxSize); m_port->open(); @@ -68,7 +74,11 @@ BaseLoop::BaseLoop() L.log(bus, error, "can't open %s", A.getOptVal("device")); // create BusHandler - m_busHandler = new BusHandler(m_port, m_messages, answer ? m_ownAddress : SYN, answer ? (m_ownAddress+5)&0xff : SYN); + m_busHandler = new BusHandler(m_port, m_messages, + answer ? m_ownAddress : SYN, answer ? (m_ownAddress+5)&0xff : SYN, + busLostRetries, failedSendRetries, + busAcquireWaitTime, slaveRecvTimeout, + lockCount); m_busHandler->start("bushandler"); // create network @@ -167,9 +177,17 @@ void BaseLoop::start() return; } } +static unsigned char _lastRecvSymbol = SYN; -void BaseLoop::logRaw(const unsigned char byte) { - L.log(bus, event, "%02x", byte); +void BaseLoop::logRaw(const unsigned char byte, bool received) { + if (received == true) { + if (byte != SYN || byte !=_lastRecvSymbol) + L.log(bus, event, "<%02x", byte); + _lastRecvSymbol = byte; + } else { + L.log(bus, event, ">%02x", byte); + _lastRecvSymbol = ESC; + } } string BaseLoop::decodeMessage(const string& data) diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index 0c1662e5..73f6407b 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -79,10 +79,11 @@ public: void addMessage(NetMessage* message) { m_netQueue.add(message); } /** - * @brief Create a log message for a retrieved raw data byte. - * @param param byte the retrieved raw data byte. + * @brief Create a log message for a received/sent raw data byte. + * @param param byte the raw data byte. + * @param received true if the byte was received, false if it was sent. */ - static void logRaw(const unsigned char byte); + static void logRaw(const unsigned char byte, bool received); private: diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 0373e3ba..f66e562f 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -73,6 +73,8 @@ BusRequest::~BusRequest() bool BusRequest::wait(int timeout) { + m_finished = false; + m_result = RESULT_SYN; struct timespec t; clock_gettime(CLOCK_REALTIME, &t); t.tv_sec += timeout; @@ -105,16 +107,33 @@ void BusRequest::notify(result_t result) result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) { + result_t result = RESULT_SYN; BusRequest* request = new BusRequest(master, slave); - m_requests.add(request); - bool success = request->wait(5); - if (success == false) - m_requests.remove(request); - result_t result = request->m_result; + for (int sendRetries=m_failedSendRetries+1, lostRetries=m_busLostRetries+1; sendRetries>=0; sendRetries--) { + m_requests.add(request); + bool success = request->wait(5); + if (success == false) + m_requests.remove(request); + result = success == true ? request->m_result : RESULT_ERR_TIMEOUT; + + if (result == RESULT_OK) + break; + + if (result == RESULT_ERR_BUS_LOST) { + if (--lostRetries > 0) { + sendRetries++; // try to get lock again, do not decrement send retries + L.log(bus, error, " %s, retry bus loss", getResultCode(result)); + continue; + } + lostRetries = m_busLostRetries+1; // send retry: reset lock retries + } + L.log(bus, error, " %s, %s", getResultCode(result), sendRetries>0 ? "retry send" : "give up"); + } + delete request; - return success == true ? result : RESULT_ERR_TIMEOUT; + return result; } void BusHandler::run() @@ -149,10 +168,14 @@ result_t BusHandler::handleSymbol() break; case bs_ready: - m_request = m_requests.next(false); - if (m_request != NULL) { // initiate arbitration - sendSymbol = m_request->m_master[0]; - sending = true; + if (m_request != NULL) + setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up + if (m_remainLockCount == 0) { + m_request = m_requests.next(false); + if (m_request != NULL) { // initiate arbitration + sendSymbol = m_request->m_master[0]; + sending = true; + } } break; @@ -160,7 +183,7 @@ result_t BusHandler::handleSymbol() case bs_recvCmdAck: case bs_recvRes: case bs_recvResAck: - timeout = SLAVE_RECV_TIMEOUT; + timeout = m_slaveRecvTimeout; break; case bs_sendCmd: @@ -186,7 +209,10 @@ result_t BusHandler::handleSymbol() // send symbol if necessary if (sending == true) { if (m_port->send(&sendSymbol, 1) == 1) - timeout = SEND_TIMEOUT; + if (m_state == bs_ready) + timeout = m_busAcquireTimeout; + else + timeout = SEND_TIMEOUT; else { sending = false; timeout = 0; @@ -195,26 +221,18 @@ result_t BusHandler::handleSymbol() } // receive next symbol (optionally check reception of sent symbol) - ssize_t count = m_port->recv(timeout, 1); + unsigned char recvSymbol; + ssize_t count = m_port->recv(timeout, 1, &recvSymbol); - if (count <= 0 && m_state == bs_ready && sending == false) - return RESULT_OK; // TODO keep "no signal" within auto-syn state + if (count < 0) // count < 0 is a RESULT_ERR_ code + return setState(bs_skip, count); // TODO keep "no signal" within auto-syn state - if (count < 0) { // count < 0 is a RESULT_ERR_ code - if (m_request != NULL) - return setState(bs_sendSyn, count); - return setState(bs_skip, count); - } - - if (count == 0) { - if (m_request != NULL) - return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); - return setState(bs_skip, RESULT_ERR_TIMEOUT); - } - - unsigned char recvSymbol = m_port->byte(); - if (recvSymbol == SYN) + //unsigned char recvSymbol = m_port->byte(); // TODO remove me + if (recvSymbol == SYN) { + if (sending == false && m_remainLockCount > 0) + m_remainLockCount--; return setState(bs_ready, RESULT_SYN); + } unsigned char headerLen, crcPos; result_t result; @@ -228,8 +246,7 @@ result_t BusHandler::handleSymbol() if (m_request != NULL && sending == true) { if (m_requests.remove(m_request) == false) { // request already timed out - m_request = NULL; - return setState(bs_sendSyn, RESULT_ERR_TIMEOUT); + return setState(bs_skip, RESULT_ERR_TIMEOUT); } // check arbitration if (recvSymbol == sendSymbol) { // arbitration successful @@ -237,8 +254,12 @@ result_t BusHandler::handleSymbol() m_repeat = false; return setState(bs_sendCmd, RESULT_OK); } - // arbitration lost - m_request = NULL; + // arbitration lost. if same priority class found, try again after next AUTO-SYN + m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; + if ((recvSymbol & 0x0f) != (sendSymbol & 0x0f) + && m_lockCount > m_remainLockCount) + // if different priority class found, try again after N AUTO-SYN symbols (at least next AUTO-SYN) + m_remainLockCount = m_lockCount; setState(m_state, RESULT_ERR_BUS_LOST); // try again later } result = m_command.push_back(recvSymbol, false); // expect no escaping for master address @@ -263,7 +284,7 @@ result_t BusHandler::handleSymbol() m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); if (m_commandCrcValid) { if (dstAddress == BROADCAST) { - transferCompleted(tt_broadcast); + receiveCompleted(); return setState(bs_skip, RESULT_OK); } //if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress) @@ -289,11 +310,10 @@ result_t BusHandler::handleSymbol() if (m_request != NULL) { if (isMaster(m_request->m_master[1]) == true) { - transferCompleted(tt_masterMaster); return setState(bs_sendSyn, RESULT_OK); } } else if (isMaster(m_command[1]) == true) { - transferCompleted(tt_masterMaster); + receiveCompleted(); return setState(bs_skip, RESULT_OK); } @@ -311,12 +331,12 @@ result_t BusHandler::handleSymbol() return setState(bs_recvCmd, RESULT_ERR_NAK); } if (m_request != NULL) - return setState(bs_sendSyn, RESULT_ERR_NAK); + return setState(bs_skip, RESULT_ERR_NAK); return setState(bs_skip, RESULT_ERR_NAK); } if (m_request != NULL) - return setState(bs_sendSyn, RESULT_ERR_ACK); + return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK); @@ -326,7 +346,7 @@ result_t BusHandler::handleSymbol() result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos); if (result < RESULT_OK) { if (m_request != NULL) - return setState(bs_sendSyn, result); + return setState(bs_skip, result); return setState(bs_skip, result); } @@ -340,7 +360,7 @@ result_t BusHandler::handleSymbol() } if (m_repeat == true) { if (m_request != NULL) - return setState(bs_sendSyn, RESULT_ERR_CRC); + return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC); } @@ -356,7 +376,7 @@ result_t BusHandler::handleSymbol() if (m_responseCrcValid == false) return setState(bs_skip, RESULT_ERR_ACK); - transferCompleted(tt_masterSlave); + receiveCompleted(); return setState(bs_skip, RESULT_OK); } if (recvSymbol == NAK) { @@ -385,7 +405,7 @@ result_t BusHandler::handleSymbol() return RESULT_OK; } } - return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG); + return setState(bs_skip, RESULT_ERR_INVALID_ARG); case bs_sendResAck: if (m_request != NULL && sending == true) { @@ -394,7 +414,7 @@ result_t BusHandler::handleSymbol() return setState(bs_sendSyn, RESULT_OK); } } - return setState(bs_sendSyn, RESULT_ERR_INVALID_ARG); + return setState(bs_skip, RESULT_ERR_INVALID_ARG); case bs_sendSyn: if (sending == true) { @@ -412,25 +432,26 @@ result_t BusHandler::handleSymbol() result_t BusHandler::setState(BusState state, result_t result) { - if (state == m_state) - return result; - - if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) - L.log(bus, error, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state)); - else if (m_request != NULL || state == bs_sendCmd || state==bs_sendResAck || state==bs_sendSyn) - L.log(bus, trace, " switching from %s to %s", getStateCode(m_state), getStateCode(state)); if (m_request != NULL) { - if (state == bs_sendSyn) { -// L.log(bus, trace, "notify request (syn): %s", getResultCode(result)); - m_request->m_slave = m_response; // TODO nicer + if (result != RESULT_OK) { + L.log(bus, debug, "notify request: %s", getResultCode(result)); m_request->notify(result); m_request = NULL; - } else if (result != RESULT_OK) { -// L.log(bus, trace, "notify request: %s", getResultCode(result)); + } else if (state == bs_sendSyn) { + L.log(bus, debug, "notify request (syn): %s", getResultCode(result)); + m_request->m_slave = m_response; // TODO nicer m_request->notify(result); m_request = NULL; } } + + if (state == m_state) + return result; + + if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) + L.log(bus, debug, " %s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state)); + else if (m_request != NULL || state == bs_sendCmd || state==bs_sendResAck || state==bs_sendSyn) + L.log(bus, debug, " switching from %s to %s", getStateCode(m_state), getStateCode(state)); m_state = state; if (state == bs_ready || state == bs_skip) { @@ -444,7 +465,7 @@ result_t BusHandler::setState(BusState state, result_t result) return result; } -void BusHandler::transferCompleted(TransferType type) +void BusHandler::receiveCompleted() { Message* msg = m_messages->find(m_command); if (msg != NULL) { @@ -458,16 +479,10 @@ void BusHandler::transferCompleted(TransferType type) L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); return; } - switch (type) - { - case tt_broadcast: + if (m_command[1] == BROADCAST) L.log(bus, trace, "received broadcast %s", m_command.getDataStr().c_str()); - break; - case tt_masterMaster: - L.log(bus, trace, "received master %s", m_command.getDataStr().c_str()); - break; - case tt_masterSlave: - L.log(bus, trace, "received master %s, slave %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); - break; - } + else if (isMaster(m_command[1]) == true) + L.log(bus, trace, "received master-master %s", m_command.getDataStr().c_str()); + else + L.log(bus, trace, "received master-slave %s / %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 299abb67..d77eba91 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -35,13 +35,13 @@ using namespace std; /** the maximum allowed time [us] for retrieving a symbol from an addressed slave. */ -#define SLAVE_RECV_TIMEOUT 10000 -/** the maximum allowed time [us] for retrieving the AUTO-SYN symbol (should be generated in <45ms). */ -#define SYN_TIMEOUT 50000 -/** the maximum duration [us] of a single symbol. */ -#define SYMBOL_DURATION 5100 -/** the maximum allowed time [us] for retrieving back a sent symbol. */ -#define SEND_TIMEOUT 6000 +//#define SLAVE_RECV_TIMEOUT 10000 +/** the maximum allowed time [us] for retrieving the AUTO-SYN symbol (45ms + 2*1,2% + 1 Symbol). */ +#define SYN_TIMEOUT 50800 +/** the maximum duration [us] of a single symbol (Start+8Bit+Stop+Extra @ 2400Bd-2*1,2%). */ +#define SYMBOL_DURATION 4700 +/** the maximum allowed time [us] for retrieving back a sent symbol (2x symbol duration). */ +#define SEND_TIMEOUT (2*SYMBOL_DURATION) /** the possible bus states. */ enum BusState { @@ -58,13 +58,6 @@ enum BusState { bs_sendSyn, // send SYN for completed transfer [active set+get] }; -/** the possible message transfer types. */ -enum TransferType { - tt_broadcast, // broadcast transfer - tt_masterMaster, // master to master transfer - tt_masterSlave // master to slave transfer -}; - /** the possible combinations of participants in a single message exchange. */ enum MessageDirection { md_thisToAll, // message from us to all (broadcast) @@ -147,11 +140,23 @@ public: * @param messages the @a MessageMap instance with all known @a Message instances. * @param ownMasterAddress the own master address to react on master-master messages, or @a SYN to ignore. * @param ownSlaveAddress the own slave address to react on master-slave messages, or @a SYN to ignore. + * @param busLostRetries the number of times a send is repeated due to lost arbitration. + * @param failedSendRetries the number of times a failed send is repeated (other than lost arbitration). + * @param slaveRecvTimeout the maximum time in microseconds an addressed slave is expected to acknowledge. + * @param busAcquireTimeout the maximum time in microseconds for bus acquisition. + * @param lockCount the number of AUTO-SYN symbols before sending is allowed after lost arbitration. */ - BusHandler(Port* port, MessageMap* messages, unsigned char ownMasterAddress, - unsigned char ownSlaveAddress) - : m_port(port), m_messages(messages), m_ownMasterAddress(ownMasterAddress), - m_ownSlaveAddress(ownSlaveAddress), m_request(NULL), m_nextSendPos(0), + BusHandler(Port* port, MessageMap* messages, + const unsigned char ownMasterAddress, const unsigned char ownSlaveAddress, + const unsigned int busLostRetries, const unsigned int failedSendRetries, + const unsigned int busAcquireTimeout, const unsigned int slaveRecvTimeout, + const unsigned int lockCount) + : m_port(port), m_messages(messages), + m_ownMasterAddress(ownMasterAddress), m_ownSlaveAddress(ownSlaveAddress), + m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries), + m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout), + m_lockCount(lockCount), m_remainLockCount(lockCount), + m_request(NULL), m_nextSendPos(0), m_state(bs_skip), m_repeat(false), m_commandCrcValid(false), m_responseCrcValid(false) {} @@ -189,10 +194,9 @@ private: result_t setState(BusState state, result_t result); /** - * @brief Called when a transfer was successfully completed. - * @param type the @a TransferType. + * @brief Called when a passive reception was successfully completed. */ - void transferCompleted(TransferType type); + void receiveCompleted(); /** the @a Port instance for accessing the bus. */ Port* m_port; @@ -201,10 +205,28 @@ private: MessageMap* m_messages; /** the own master address to react on master-master messages, or @a SYN to ignore. */ - unsigned char m_ownMasterAddress; + const unsigned char m_ownMasterAddress; /** the own slave address to react on master-slave messages, or @a SYN to ignore. */ - unsigned char m_ownSlaveAddress; + const unsigned char m_ownSlaveAddress; + + /** the number of times a send is repeated due to lost arbitration. */ + const unsigned int m_busLostRetries; + + /** the number of times a failed send is repeated (other than lost arbitration). */ + const unsigned int m_failedSendRetries; + + /** the maximum time in microseconds for bus acquisition. */ + const unsigned int m_busAcquireTimeout; + + /** the maximum time in microseconds an addressed slave is expected to acknowledge. */ + const unsigned int m_slaveRecvTimeout; + + /** the number of AUTO-SYN symbols before sending is allowed after lost arbitration. */ + const unsigned int m_lockCount; + + /** the remaining number of AUTO-SYN symbols before sending is allowed again. */ + unsigned int m_remainLockCount; /** the queue of @a BusRequests that shall be handled. */ WQueue m_requests; diff --git a/src/ebusd/ebusd.cpp b/src/ebusd/ebusd.cpp index aad7f47f..61749241 100644 --- a/src/ebusd/ebusd.cpp +++ b/src/ebusd/ebusd.cpp @@ -67,8 +67,8 @@ void define_args() A.addOption("recvtimeout", "", OptVal(15000), dt_long, ot_mandatory, "receive timeout in 'us' (15000)"); - A.addOption("acquiretime", "", OptVal(4200), dt_long, ot_mandatory, - "waiting time for bus acquire in 'us' (4200)\n"); + A.addOption("acquiretimeout", "", OptVal(9400), dt_long, ot_mandatory, + "bus acquisition timeout in 'us' (9400)\n"); A.addOption("pollinterval", "", OptVal(5), dt_int, ot_mandatory, "polling interval in 's' (5)\n"); From 0325625a56f98a30cf795efa4acdd3d63ba75a50 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 22:01:12 +0100 Subject: [PATCH 66/83] avoid cancelling request if part of the message is repeated --- src/ebusd/bushandler.cpp | 14 +++++--------- src/ebusd/bushandler.h | 4 +++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index f66e562f..16216d7b 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -112,7 +112,7 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) for (int sendRetries=m_failedSendRetries+1, lostRetries=m_busLostRetries+1; sendRetries>=0; sendRetries--) { m_requests.add(request); - bool success = request->wait(5); + bool success = request->wait(1); // 1 second is still 3 times the theoretical worst-case request duration if (success == false) m_requests.remove(request); result = success == true ? request->m_result : RESULT_ERR_TIMEOUT; @@ -326,7 +326,7 @@ result_t BusHandler::handleSymbol() m_nextSendPos = 0; m_command.clear(); if (m_request != NULL) - return setState(bs_sendCmd, RESULT_ERR_NAK); + return setState(bs_sendCmd, RESULT_ERR_NAK, true); return setState(bs_recvCmd, RESULT_ERR_NAK); } @@ -383,7 +383,7 @@ result_t BusHandler::handleSymbol() if (m_repeat == false) { m_repeat = true; m_response.clear(); - return setState(bs_recvRes, RESULT_ERR_NAK); + return setState(bs_recvRes, RESULT_ERR_NAK, true); } return setState(bs_skip, RESULT_ERR_NAK); } @@ -430,15 +430,11 @@ result_t BusHandler::handleSymbol() return RESULT_OK; } -result_t BusHandler::setState(BusState state, result_t result) +result_t BusHandler::setState(BusState state, result_t result, bool firstRepetition) { if (m_request != NULL) { - if (result != RESULT_OK) { + if (state == bs_sendSyn || (result != RESULT_OK && firstRepetition == false)) { L.log(bus, debug, "notify request: %s", getResultCode(result)); - m_request->notify(result); - m_request = NULL; - } else if (state == bs_sendSyn) { - L.log(bus, debug, "notify request (syn): %s", getResultCode(result)); m_request->m_slave = m_response; // TODO nicer m_request->notify(result); m_request = NULL; diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index d77eba91..1fd75a92 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -95,6 +95,7 @@ public: /** * @brief Wait for notification. + * @param timeout the maximum time to wait in seconds. * @return the result code. */ bool wait(int timeout); @@ -189,9 +190,10 @@ private: * @brief Set a new @a BusState and add a log message if necessary. * @param state the new @a BusState. * @param result the result code. + * @param firstRepetition true if the first repetition of a message part is being started. * @return the result code. */ - result_t setState(BusState state, result_t result); + result_t setState(BusState state, result_t result, bool firstRepetition=false); /** * @brief Called when a passive reception was successfully completed. From e173ba6ad5130195899d92a03188337612e0e9da Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 22:26:13 +0100 Subject: [PATCH 67/83] removed commented stuff --- src/lib/ebus/message.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 4c975bdb..1338bd4a 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -123,18 +123,6 @@ public: * @return the polling priority, or 0 for no polling at all. */ unsigned char getPollPriority() const { return m_pollPriority; } - /** - * @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 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, ostringstream& output, - // bool verbose=false, char separator=';') = 0; /** * @brief Prepare master @a SymbolString for sending to the bus. * @param masterData the master data @a SymbolString for writing symbols to. From 97d4e40172832f6335d623655b16731d04f79cba Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 22:26:58 +0100 Subject: [PATCH 68/83] added set --- src/ebusd/baseloop.cpp | 148 ++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 82 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 3f408c79..53174c4d 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -199,6 +199,7 @@ string BaseLoop::decodeMessage(const string& data) string token; istringstream stream(data); vector cmd; + Message* message; while (getline(stream, token, ' ') != 0) cmd.push_back(token); @@ -217,116 +218,99 @@ string BaseLoop::decodeMessage(const string& data) break; } - { - Message* message; - if (cmd.size() == 2) - message = m_messages->find("", cmd[1], false); - else - message = m_messages->find(cmd[1], cmd[2], false); + if (cmd.size() == 2) + message = m_messages->find("", cmd[1], false); + else + message = m_messages->find(cmd[1], cmd[2], false); - if (message != NULL) { + if (message != NULL) { - /*if (message->getPollPriority() > 0) - // get polldata - polldata = m_commands->getPollData(index); - if (polldata != "") { - // decode data - Command* command = new Command(index, (*m_commands)[index], polldata); - - // return result - result << command->calcResult(cmd); - - delete command; - } else { - result << "no data stored"; - } - - break; - }*/ - - SymbolString master; - istringstream input; - result_t ret = message->prepareMaster(m_ownAddress, master, input); - if (ret != RESULT_OK) { - L.log(bas, error, " prepare message: %s", getResultCode(ret)); - result << getResultCode(ret); - break; - } - L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); - - // send message - SymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); - - if (ret == RESULT_OK) + /*if (message->getPollPriority() > 0) + // get polldata + polldata = m_commands->getPollData(index); + if (polldata != "") { // decode data - ret = message->decode(pt_slaveData, slave, result);// TODO reduce to requested variable only + Command* command = new Command(index, (*m_commands)[index], polldata); - if (ret != RESULT_OK) { - L.log(bas, error, " %s", getResultCode(ret)); - result << getResultCode(ret); + // return result + result << command->calcResult(cmd); + + delete command; + } else { + result << "no data stored"; } - } else { - result << "ebus command not found"; + break; + }*/ + + SymbolString master; + istringstream input; + result_t ret = message->prepareMaster(m_ownAddress, master, input); + if (ret != RESULT_OK) { + L.log(bas, error, " prepare message: %s", getResultCode(ret)); + result << getResultCode(ret); + break; } + L.log(bas, event, " msg: %s", master.getDataStr().c_str()); + + // send message + SymbolString slave; + ret = m_busHandler->sendAndWait(master, slave); + + if (ret == RESULT_OK) { + // TODO reduce to requested variable only + ret = message->decode(pt_slaveData, slave, result); // decode data + } + if (ret != RESULT_OK) { + L.log(bas, error, " %s", getResultCode(ret)); + result << getResultCode(ret); + } + + } else { + result << "ebus command not found"; } break; - /*case ct_set: + case ct_set: if (cmd.size() != 4) { result << "usage: 'set class cmd value'"; break; } - index = m_commands->findCommand(data.substr(0, data.find(cmd[3])-1)); + message = m_messages->find(cmd[1], cmd[2], true); - if (index >= 0) { + if (message != NULL) { - string busCommand(A.getOptVal("address")); - busCommand += m_commands->getBusCommand(index); - - // encode data - Command* command = new Command(index, (*m_commands)[index], cmd[3]); - string value = command->calcData(); - if (value[0] != '-') { - busCommand += value; - } else { - L.log(bas, error, " %s", value.c_str()); - delete command; + SymbolString master; + istringstream input(cmd[3]); + result_t ret = message->prepareMaster(m_ownAddress, master, input); + if (ret != RESULT_OK) { + L.log(bas, error, " prepare message: %s", getResultCode(ret)); + result << getResultCode(ret); break; } + L.log(bas, event, " msg: %s", master.getDataStr().c_str()); - transform(busCommand.begin(), busCommand.end(), busCommand.begin(), ::tolower); - - BusMessage* message = new BusMessage(busCommand, false, false); - L.log(bas, event, " msg: %s", busCommand.c_str()); // send message - m_busloop->addMessage(message); - message->waitSignal(); + SymbolString slave; + ret = m_busHandler->sendAndWait(master, slave); - if (!message->isErrorResult()) { - // decode result - if (message->getType()==broadcast) - result << "done"; - else if (message->getMessageStr().substr(message->getMessageStr().length()-8) == "00000000") // TODO use getResult() + if (ret == RESULT_OK) { + if (master[1] == BROADCAST || isMaster(master[1])) result << "done"; else - result << "error"; - - } else { - L.log(bas, error, " %s", message->getResultCodeCStr()); - result << message->getResultCodeCStr(); + ret = message->decode(pt_slaveData, slave, result); // decode data + } + if (ret != RESULT_OK) { + L.log(bas, error, " %s", getResultCode(ret)); + result << getResultCode(ret); } - - delete message; - delete command; } else { result << "ebus command not found"; } - break;*/ + break; /*case ct_cyc: if (cmd.size() < 3 || cmd.size() > 4) { @@ -369,7 +353,7 @@ string BaseLoop::decodeMessage(const string& data) msg << hex << setw(2) << setfill('0') << static_cast(m_ownAddress); msg << cmd[1]; SymbolString master(msg.str()); - L.log(bas, trace, " msg: %s", master.getDataStr().c_str()); + L.log(bas, event, " msg: %s", master.getDataStr().c_str()); // send message SymbolString slave; @@ -377,7 +361,7 @@ string BaseLoop::decodeMessage(const string& data) if (ret == RESULT_OK) // decode data - result << slave.getDataStr(); // TODO find suitable message?, message->decode(master, slave, result); + result << slave.getDataStr(); if (ret != RESULT_OK) { L.log(bas, error, " %s", getResultCode(ret)); From c0c1cf3966f0bc2b29108d977756f3428a1b3bf9 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 23:41:14 +0100 Subject: [PATCH 69/83] allow passive messages to be found as well, added leadingSeparator to decode(), fixed default part for passive set --- src/lib/ebus/message.cpp | 61 +++++++++++++++--------------- src/lib/ebus/message.h | 6 ++- src/lib/ebus/test/test_message.cpp | 3 +- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index d233c5a7..1ac94290 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -113,7 +113,7 @@ result_t Message::create(vector::iterator& it, const vector::ite defaultsChar = 'r'; } else { // any other: passive set/get isPassive = true; - isSet = strncasecmp(str+1, "R", 1) == 0; + isSet = strncasecmp(str+1, "W", 1) == 0; defaultsChar = str[0]; } @@ -272,14 +272,14 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma } result_t Message::decode(const PartType partType, SymbolString& data, - ostringstream& output, char separator) + ostringstream& output, bool leadingSeparator, char separator) { unsigned char offset; if (partType == pt_masterData) offset = m_id.size() - 2; else offset = 0; - result_t result = m_data->read(partType, data, offset, output, false, false, separator); + result_t result = m_data->read(partType, data, offset, output, leadingSeparator, false, separator); if (result != RESULT_OK) return result; /*if (m_isPassive == false && answer == true) { @@ -294,35 +294,36 @@ result_t Message::decode(const PartType partType, SymbolString& data, result_t MessageMap::add(Message* message) { - if (message->isPassive() == false) { - bool isSet = message->isSet(); - string clazz = message->getClass(); - string name = message->getName(); - string key = string(isSet ? "W" : "R") + clazz + ";" + name; - map::iterator nameIt = m_messagesByName.find(key); - if (nameIt != m_messagesByName.end()) { + unsigned long long pkey = message->getKey(); + bool isPassive = message->isPassive(); + if (isPassive == true) { + map::iterator keyIt = m_passiveMessagesByKey.find(pkey); + if (keyIt != m_passiveMessagesByKey.end()) { return RESULT_ERR_DUPLICATE; // duplicate key } - - m_messagesByName[key] = message; - - key = string(isSet ? "-W" : "-R") + name; // also store without class - m_messagesByName[key] = message; - return RESULT_OK; } - - unsigned long long key = message->getKey(); - map::iterator keyIt = m_passiveMessagesByKey.find(key); - if (keyIt != m_passiveMessagesByKey.end()) { + bool isSet = message->isSet(); + string clazz = message->getClass(); + string name = message->getName(); + string key = string(isPassive ? "P" : (isSet ? "W" : "R")) + clazz + ";" + name; + map::iterator nameIt = m_messagesByName.find(key); + if (nameIt != m_messagesByName.end()) { return RESULT_ERR_DUPLICATE; // duplicate key } - unsigned char idLength = message->getId().size() - 2; - if (idLength < m_minIdLength) - m_minIdLength = idLength; - if (idLength > m_maxIdLength) - m_maxIdLength = idLength; - m_passiveMessagesByKey[key] = message; + m_messagesByName[key] = message; + + key = string(isPassive ? "-P;" : (isSet ? "-W;" : "-R;")) + name; // also store without class + m_messagesByName[key] = message; // last key without class overrides previous + + if (message->isPassive() == true) { + unsigned char idLength = message->getId().size() - 2; + if (idLength < m_minIdLength) + m_minIdLength = idLength; + if (idLength > m_maxIdLength) + m_maxIdLength = idLength; + m_passiveMessagesByKey[pkey] = message; + } return RESULT_OK; } @@ -353,14 +354,14 @@ result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, v return result; } -Message* MessageMap::find(const string& clazz, const string& name, const bool isSet) +Message* MessageMap::find(const string& clazz, const string& name, const bool isSet,const bool isPassive) { - string key; for (int i=0; i<2; i++) { + string key; if (i==0) - key = string(isSet ? "W" : "R") + clazz + ";" + name; + key = string(isPassive ? "P" : (isSet ? "W" : "R")) + clazz + ";" + name; else - key = string(isSet ? "-W" : "-R") + name; // second try: without class + key = string(isPassive ? "-P;" : (isSet ? "-W;" : "-R;")) + name; // second try: without class map::iterator it = m_messagesByName.find(key); if (it != m_messagesByName.end()) return it->second; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 1338bd4a..6e10b64a 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -137,11 +137,12 @@ public: * @param partType the @a PartType of the data. * @param data the unescaped data @a SymbolString for reading binary data. * @param output the @a ostringstream to append the formatted value to. + * @param leadingSeparator whether to prepend a separator before the formatted value. * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ result_t decode(const PartType partType, SymbolString& data, - ostringstream& output, char separator=';'); + ostringstream& output, bool leadingSeparator=false, char separator=';'); private: @@ -200,10 +201,11 @@ public: * @param class the optional device class. * @param name the message name. * @param isSet whether this is a set message. + * @param isPassive whether this is a passive message. * @return the @a Message instance, or NULL. * Note: the caller may not free the returned instance. */ - Message* find(const string& clazz, const string& name, const bool isSet); + Message* find(const string& clazz, const string& name, const bool isSet, const bool isPassive=false); /** * @brief Find the @a Message instance for the specified master data. * @param master the master @a SymbolString for identifying the @a Message. diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 5509a8f5..dbd69e08 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -52,6 +52,7 @@ int main() {"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, {"u;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "pm"}, + {"uw;ehp;test;Test;;08;B5de;ab;;;power;;;;;s;hex:1", "8;39", "1008b5de02ab08", "0139", "pm"}, {"","55.50;ok","1025b50903290000","050000780300",""}, {"","no;25","10feb505042700190023","",""}, }; @@ -151,7 +152,7 @@ int main() ostringstream output; result = message->decode(pt_masterData, mstr, output); if (result == RESULT_OK) - result = message->decode(pt_slaveData, sstr, output); + result = message->decode(pt_slaveData, sstr, output, output.str().empty() == false); if (result != RESULT_OK) { cout << " \"" << inputStr << "\": decode error: " << getResultCode(result) << endl; From 5bbdcac5d48f0ded6bdf50c240a97643565a3d7c Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 23:42:41 +0100 Subject: [PATCH 70/83] store received data --- src/ebusd/bushandler.cpp | 30 +++++++++++++++++++++++------- src/ebusd/bushandler.h | 10 ++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 16216d7b..04b71c0c 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -463,16 +463,21 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit void BusHandler::receiveCompleted() { - Message* msg = m_messages->find(m_command); - if (msg != NULL) { + Message* message = m_messages->find(m_command); + if (message != NULL) { + string clazz = message->getClass(); + string name = message->getName(); ostringstream output; - result_t result = msg->decode(pt_masterData, m_command, output); + result_t result = message->decode(pt_masterData, m_command, output); if (result == RESULT_OK) - result = msg->decode(pt_slaveData, m_response, output); + result = message->decode(pt_slaveData, m_response, output, output.str().empty() == false); if (result != RESULT_OK) - L.log(bus, error, "unable to parse %s %s from %s / %s: %s", msg->getClass().c_str(), msg->getName().c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result)); - else - L.log(bus, trace, "%s %s: %s", msg->getClass().c_str(), msg->getName().c_str(), output.str().c_str()); + L.log(bus, error, "unable to parse %s %s from %s / %s: %s", clazz.c_str(), name.c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result)); + else { + string data = output.str(); + L.log(bus, trace, "%s %s: %s", clazz.c_str(), name.c_str(), data.c_str()); + m_receivedData[clazz+";"+name] = data; + } return; } if (m_command[1] == BROADCAST) @@ -482,3 +487,14 @@ void BusHandler::receiveCompleted() else L.log(bus, trace, "received master-slave %s / %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); } + +string BusHandler::getReceivedData(Message* message) { + if (message == NULL) + return NULL; + string clazz = message->getClass(); + string name = message->getName(); + map::iterator it = m_receivedData.find(clazz+";"+name); + if (it == m_receivedData.end()) + return NULL; + return it->second; +} diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 1fd75a92..c68b3a5c 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -178,6 +178,13 @@ public: */ virtual void run(); + /** + * @brief Get the last received data for the @a Message. + * @param message the @a Message instance. + * @return the last received data for the @a Message, or the empty string if not available. + */ + string getReceivedData(Message* message); + private: /** @@ -258,6 +265,9 @@ private: /** whether the response CRC is valid. */ bool m_responseCrcValid; + /** the last received data by "class;name". */ + map m_receivedData; + }; From 8ef841870297a09cf6d799652690f9e3ac1b0279 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 23:43:04 +0100 Subject: [PATCH 71/83] added cyc command --- src/ebusd/baseloop.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 53174c4d..3091e52b 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -312,25 +312,21 @@ string BaseLoop::decodeMessage(const string& data) break; - /*case ct_cyc: - if (cmd.size() < 3 || cmd.size() > 4) { - result << "usage: 'cyc class cmd (sub)'"; + case ct_cyc: + if (cmd.size() < 2 || cmd.size() > 3) { + result << "usage: 'cyc [class] cmd'"; break; } - index = m_commands->findCommand(data); + if (cmd.size() == 2) + message = m_messages->find("", cmd[1], false, true); + else + message = m_messages->find(cmd[1], cmd[2], false, true); - if (index >= 0) { - // get cycdata - cycdata = m_commands->getCycData(index); - if (cycdata != "") { - // decode data - Command* command = new Command(index, (*m_commands)[index], cycdata); - - // return result - result << command->calcResult(cmd); - - delete command; + if (message != NULL) { + token = m_busHandler->getReceivedData(message); + if (token.empty() == false) { + result << token; } else { result << "no data stored"; } @@ -338,7 +334,7 @@ string BaseLoop::decodeMessage(const string& data) result << "ebus command not found"; } - break;*/ + break; case ct_hex: if (cmd.size() != 2) { From f3f2e1a451d7ad4978836ec740de20beed02d4b6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 23:49:00 +0100 Subject: [PATCH 72/83] removed debug code --- src/ebusd/baseloop.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index 3091e52b..b5291666 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -177,16 +177,12 @@ void BaseLoop::start() return; } } -static unsigned char _lastRecvSymbol = SYN; void BaseLoop::logRaw(const unsigned char byte, bool received) { if (received == true) { - if (byte != SYN || byte !=_lastRecvSymbol) - L.log(bus, event, "<%02x", byte); - _lastRecvSymbol = byte; + L.log(bus, event, "<%02x", byte); } else { L.log(bus, event, ">%02x", byte); - _lastRecvSymbol = ESC; } } From 8089dab4b44b5137a8701c6da5f7f15f64949f12 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 6 Dec 2014 23:50:31 +0100 Subject: [PATCH 73/83] solved todo --- src/lib/ebus/port.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ebus/port.cpp b/src/lib/ebus/port.cpp index c9adc96c..97e32ea3 100644 --- a/src/lib/ebus/port.cpp +++ b/src/lib/ebus/port.cpp @@ -63,7 +63,7 @@ bool Device::isValid() ssize_t Device::sendBytes(const unsigned char* buffer, size_t nbytes) { if (isValid() == false) - return -1; // TODO RESULT_ERR_DEVICE + return RESULT_ERR_DEVICE; // write bytes to device return write(m_fd, buffer, nbytes); From 4ffc6155a1dacbea3b3477e26c71c128a8c458e3 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 09:43:49 +0100 Subject: [PATCH 74/83] fixed escaping and crc --- src/lib/ebus/message.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 1ac94290..87d6c2bc 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -242,32 +242,33 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma if (m_isPassive == true) return RESULT_ERR_INVALID_ARG; // prepare not possible - masterData.clear(); - result_t result = masterData.push_back(srcAddress, false); + SymbolString master; + master.clear(); + result_t result = master.push_back(srcAddress, false, false); if (result != RESULT_OK) return result; - result = masterData.push_back(m_dstAddress, false); + result = master.push_back(m_dstAddress, false, false); if (result != RESULT_OK) return result; - result = masterData.push_back(m_id[0], false); + result = master.push_back(m_id[0], false, false); if (result != RESULT_OK) return result; - result = masterData.push_back(m_id[1], false); + result = master.push_back(m_id[1], false, false); if (result != RESULT_OK) return result; unsigned char addData = m_data->getLength(pt_masterData); - result = masterData.push_back(m_id.size() - 2 + addData, false); + result = master.push_back(m_id.size() - 2 + addData, false, false); if (result != RESULT_OK) return result; for (size_t i=2; iwrite(input, pt_masterData, masterData, m_id.size() - 2, separator); + result = m_data->write(input, pt_masterData, master, m_id.size() - 2, separator); if (result != RESULT_OK) return result; - result = masterData.push_back(masterData.getCRC(), false, false); // TODO only if calculated + masterData = SymbolString(master); return result; } @@ -325,6 +326,8 @@ result_t MessageMap::add(Message* message) m_passiveMessagesByKey[pkey] = message; } + //m_pollMessages.push() + return RESULT_OK; } From d33cede5ead16ab9b8be38612adbba906d56fb0b Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 10:00:26 +0100 Subject: [PATCH 75/83] store last value in Message with update time --- src/ebusd/baseloop.cpp | 2 +- src/lib/ebus/message.cpp | 12 ++++++++---- src/lib/ebus/message.h | 18 ++++++++++++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp index b5291666..42bd1ce0 100644 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -320,7 +320,7 @@ string BaseLoop::decodeMessage(const string& data) message = m_messages->find(cmd[1], cmd[2], false, true); if (message != NULL) { - token = m_busHandler->getReceivedData(message); + token = message->getLastValue(); if (token.empty() == false) { result << token; } else { diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 87d6c2bc..4e245ae0 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -35,7 +35,8 @@ Message::Message(const string clazz, const string name, const bool isSet, : m_class(clazz), m_name(name), m_isSet(isSet), m_isPassive(isPassive), m_comment(comment), m_srcAddress(srcAddress), m_dstAddress(dstAddress), - m_id(id), m_data(data), m_pollPriority(pollPriority) + m_id(id), m_data(data), m_pollPriority(pollPriority), + m_lastUpdateTime(0) { int exp = 7; unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5); @@ -280,9 +281,14 @@ result_t Message::decode(const PartType partType, SymbolString& data, offset = m_id.size() - 2; else offset = 0; + int startPos = output.str().length(); result_t result = m_data->read(partType, data, offset, output, leadingSeparator, false, separator); - if (result != RESULT_OK) + time(&m_lastUpdateTime); + if (result != RESULT_OK) { + m_lastValue.clear(); return result; + } + m_lastValue = output.str().substr(startPos); /*if (m_isPassive == false && answer == true) { 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); @@ -292,7 +298,6 @@ result_t Message::decode(const PartType partType, SymbolString& data, return RESULT_OK; } - result_t MessageMap::add(Message* message) { unsigned long long pkey = message->getKey(); @@ -422,4 +427,3 @@ void MessageMap::clear() m_passiveMessagesByKey.clear(); m_maxIdLength = 0; } - diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 6e10b64a..a5bef802 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -144,6 +144,18 @@ public: result_t decode(const PartType partType, SymbolString& data, ostringstream& output, bool leadingSeparator=false, char separator=';'); + /** + * @brief Get the last decoded value. + * @return the last decoded value, or the empty string if it was not successful. + */ + string getLastValue() { return m_lastValue; } + + /** + * @brief Get the system time when @a m_lastValue was updated. + * @return the system time when @a m_lastValue was updated, or 0 if this message was not decoded yet. + */ + time_t getLastUpdateTime() { return m_lastUpdateTime; } + private: /** the optional device class. */ @@ -169,7 +181,10 @@ private: DataField* m_data; /** the priority for polling, or 0 for no polling at all. */ const unsigned char m_pollPriority; - + /** the last decoded value. */ + string m_lastValue; + /** the system time when @a m_lastValue was updated. */ + time_t m_lastUpdateTime; }; /** @@ -218,7 +233,6 @@ public: */ void clear(); - private: /** the minimum ID length used by any of the known @a Message instances. */ From 3599378364b7142a6dbd3c3c5d997ee1ce1a81c5 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 10:00:57 +0100 Subject: [PATCH 76/83] removed getReceivedData() --- src/ebusd/bushandler.cpp | 12 ------------ src/ebusd/bushandler.h | 3 --- 2 files changed, 15 deletions(-) diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 04b71c0c..30d43e08 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -476,7 +476,6 @@ void BusHandler::receiveCompleted() else { string data = output.str(); L.log(bus, trace, "%s %s: %s", clazz.c_str(), name.c_str(), data.c_str()); - m_receivedData[clazz+";"+name] = data; } return; } @@ -487,14 +486,3 @@ void BusHandler::receiveCompleted() else L.log(bus, trace, "received master-slave %s / %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str()); } - -string BusHandler::getReceivedData(Message* message) { - if (message == NULL) - return NULL; - string clazz = message->getClass(); - string name = message->getName(); - map::iterator it = m_receivedData.find(clazz+";"+name); - if (it == m_receivedData.end()) - return NULL; - return it->second; -} diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index c68b3a5c..8ad6e474 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -265,9 +265,6 @@ private: /** whether the response CRC is valid. */ bool m_responseCrcValid; - /** the last received data by "class;name". */ - map m_receivedData; - }; From 0a87e9d853279168de79bd945d47c08025ec50a8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:23:55 +0100 Subject: [PATCH 77/83] avoid copying SymbolString --- src/lib/ebus/test/test_data.cpp | 8 ++++---- src/lib/ebus/test/test_symbol.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) mode change 100644 => 100755 src/lib/ebus/test/test_data.cpp mode change 100644 => 100755 src/lib/ebus/test/test_symbol.cpp diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp old mode 100644 new mode 100755 index 4096b032..96f1bfb4 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -190,8 +190,8 @@ int main() 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); + SymbolString mstr(check[2], false); + SymbolString sstr(check[3], false); string flags = check[4]; bool isSet = flags.find('s') != string::npos; bool failedCreate = flags.find('c') != string::npos; @@ -247,8 +247,8 @@ int main() } ostringstream output; - SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false); - SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false); + SymbolString writeMstr(mstr.getDataStr().substr(0, 10), false); + SymbolString writeSstr(sstr.getDataStr().substr(0, 2), false); result = fields->read(pt_masterData, mstr, 0, output, false, verbose); if (result == RESULT_OK) { result = fields->read(pt_slaveData, sstr, 0, output, output.str().empty() == false, verbose); diff --git a/src/lib/ebus/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp old mode 100644 new mode 100755 index a3858469..7115b2b2 --- a/src/lib/ebus/test/test_symbol.cpp +++ b/src/lib/ebus/test/test_symbol.cpp @@ -25,7 +25,7 @@ using namespace std; int main () { - SymbolString sstr = SymbolString("10feb5050427a915aa"); + SymbolString sstr("10feb5050427a915aa"); std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177"; From 2663c0ca762ca8d1a363d77f0c93cb93aaef2ee2 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:23:55 +0100 Subject: [PATCH 78/83] avoid copying SymbolString --- src/lib/ebus/test/test_message.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) mode change 100644 => 100755 src/lib/ebus/test/test_message.cpp diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp old mode 100644 new mode 100755 index dbd69e08..9c8b7cc8 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -76,8 +76,8 @@ int main() 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); + SymbolString mstr(check[2], false); + SymbolString sstr(check[3], false); string flags = check[4]; bool dontMap = flags.find('m') != string::npos; bool failedCreate = flags.find('c') != string::npos; @@ -147,7 +147,7 @@ int main() message = deleteMessage; } istringstream input(inputStr); - SymbolString writeMstr = SymbolString(); + SymbolString writeMstr; if (message->isPassive() == true) { ostringstream output; result = message->decode(pt_masterData, mstr, output); From dc6f5a098026be29ec99e30cacd5ae1318e6c79d Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:44:14 +0100 Subject: [PATCH 79/83] removed misleading SymbolString copy constructor --- src/lib/ebus/symbol.cpp | 12 ++++++------ src/lib/ebus/symbol.h | 14 +++++++++++--- src/lib/ebus/test/test_message.cpp | 12 ++++++------ 3 files changed, 23 insertions(+), 15 deletions(-) mode change 100644 => 100755 src/lib/ebus/symbol.cpp diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp old mode 100644 new mode 100755 index 253236d4..49573b9f --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -60,15 +60,15 @@ SymbolString::SymbolString(const string& str) //TODO use a factory method instea push_back(m_crc, false, false); } -SymbolString::SymbolString(const SymbolString& str) - : m_unescapeState(0), m_crc(0) +SymbolString::SymbolString(const SymbolString& str, const bool escape, const bool addCrc) + : m_unescapeState(escape == true ? 0 : 1), m_crc(0) { - // escape for (size_t i = 0; i < str.size(); i++) { - push_back(str[i], false, true); + push_back(str[i], str.m_unescapeState == 0, true); } - // add CRC + escape - push_back(m_crc, false, false); + if (addCrc == true) + // add CRC + push_back(m_crc, false, false); } SymbolString::SymbolString(const string& str, bool isEscaped) diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index b90a51d8..14c2d90d 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -52,10 +52,10 @@ public: */ SymbolString(const string& str); /** - * @brief Creates a new escaped instance from an unescaped @a SymbolString and adds the calculated CRC. - * @param str the unescaped SymbolString. + * @brief Creates a new escaped or unescaped instance from another @a SymbolString and adds the calculated CRC. + * @param str the @a SymbolString top copy from. */ - SymbolString(const SymbolString& str); + SymbolString(const SymbolString& str, const bool escape, const bool addCrc=true); /** * @brief Creates a new unescaped instance from a hex string. * @param isEscaped whether the hex string is escaped and shall be unescaped. @@ -125,6 +125,14 @@ public: void clear() { m_data.clear(); m_unescapeState = m_unescapeState==0 ? 0 : 1; m_crc = 0; } private: + + /** + * @brief Hidden copy constructor. + * @param str the @a SymbolString to copy from. + */ + SymbolString(const SymbolString& str) + : m_data(str.m_data), m_unescapeState(str.m_unescapeState), m_crc(str.m_crc) {} + /** * @brief Updates the calculated CRC in @a m_crc by adding a value. * @param value the (escaped) value to add to the calculated CRC in @a m_crc. diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 9c8b7cc8..febaaf19 100755 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -47,10 +47,10 @@ int main() // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { // "message", "flags" - {"u;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"}, - {"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"}, - {"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"}, - {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"}, + {"u;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe07000426100614", "00", "p"}, + {"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b50906040026100614", "00", "m"}, + {"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800", "0311000f", "m"}, + {"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d2900", "03170b0e", "m"}, {"u;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "pm"}, {"uw;ehp;test;Test;;08;B5de;ab;;;power;;;;;s;hex:1", "8;39", "1008b5de02ab08", "0139", "pm"}, {"","55.50;ok","1025b50903290000","050000780300",""}, @@ -76,8 +76,8 @@ int main() string check[5] = checks[i]; istringstream isstr(check[0]); string inputStr = check[1]; - SymbolString mstr(check[2], false); - SymbolString sstr(check[3], false); + SymbolString mstr(check[2]); + SymbolString sstr(check[3]); string flags = check[4]; bool dontMap = flags.find('m') != string::npos; bool failedCreate = flags.find('c') != string::npos; From a8c1343218aed35d2d74e6522e7803f58c8f1fb6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:45:33 +0100 Subject: [PATCH 80/83] added polling by priority --- src/lib/ebus/message.cpp | 42 +++++++++++++++++++++++++-- src/lib/ebus/message.h | 61 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 7 deletions(-) mode change 100644 => 100755 src/lib/ebus/message.cpp diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp old mode 100644 new mode 100755 index 4e245ae0..ed8aa0a4 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -36,7 +36,7 @@ Message::Message(const string clazz, const string name, const bool isSet, m_isPassive(isPassive), m_comment(comment), m_srcAddress(srcAddress), m_dstAddress(dstAddress), m_id(id), m_data(data), m_pollPriority(pollPriority), - m_lastUpdateTime(0) + m_lastUpdateTime(0), m_pollCount(0), m_lastPollTime(0) { int exp = 7; unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5); @@ -269,7 +269,7 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma result = m_data->write(input, pt_masterData, master, m_id.size() - 2, separator); if (result != RESULT_OK) return result; - masterData = SymbolString(master); + masterData = SymbolString(master, true); return result; } @@ -298,6 +298,18 @@ result_t Message::decode(const PartType partType, SymbolString& data, return RESULT_OK; } +bool Message::isLessPollWeight(Message* other) { + if (m_pollPriority * m_pollCount < other->m_pollPriority * other->m_pollCount) + return true; + if (m_pollPriority < other->m_pollPriority) + return true; + if (m_lastPollTime < other->m_lastPollTime) + return true; + + return false; +} + + result_t MessageMap::add(Message* message) { unsigned long long pkey = message->getKey(); @@ -318,6 +330,7 @@ result_t MessageMap::add(Message* message) } m_messagesByName[key] = message; + m_messageCount++; key = string(isPassive ? "-P;" : (isSet ? "-W;" : "-R;")) + name; // also store without class m_messagesByName[key] = message; // last key without class overrides previous @@ -331,7 +344,8 @@ result_t MessageMap::add(Message* message) m_passiveMessagesByKey[pkey] = message; } - //m_pollMessages.push() + if (message->getPollPriority() > 0) + m_pollMessages.push(message); return RESULT_OK; } @@ -418,12 +432,34 @@ Message* MessageMap::find(SymbolString& master) void MessageMap::clear() { + // clear poll messages + while (m_pollMessages.empty() == false) { + m_pollMessages.top(); + m_pollMessages.pop(); + } + // free message instances for (map::iterator it=m_messagesByName.begin(); it!=m_messagesByName.end(); it++) { if (it->first[0] != '-') // avoid double free delete it->second; it->second = NULL; } + // clear messages by name + m_messageCount = 0; m_messagesByName.clear(); + // clear messages by key m_passiveMessagesByKey.clear(); + m_minIdLength = 4; m_maxIdLength = 0; } + +Message* MessageMap::getNextPoll() +{ + if (m_pollMessages.empty() == true) + return NULL; + Message* ret = m_pollMessages.top(); + m_pollMessages.pop(); + ret->m_pollCount++; + time(&(ret->m_lastPollTime)); + m_pollMessages.push(ret); // re-insert at new position + return ret; +} diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a5bef802..b26d240b 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -29,11 +29,14 @@ using namespace std; +class MessageMap; + /** * @brief Defines parameters of a message sent or received on the bus. */ class Message { + friend class MessageMap; public: /** @@ -151,11 +154,24 @@ public: string getLastValue() { return m_lastValue; } /** - * @brief Get the system time when @a m_lastValue was updated. - * @return the system time when @a m_lastValue was updated, or 0 if this message was not decoded yet. + * @brief Get the time when @a m_lastValue was updated. + * @return the time when @a m_lastValue was updated, or 0 if this message was not decoded yet. */ time_t getLastUpdateTime() { return m_lastUpdateTime; } + /** + * @brief Get the time when this message was last polled for. + * @return the time when this message was last polled for, or 0 for never. + */ + time_t getLastPollTime() { return m_lastPollTime; } + + /** + * @brief Return whether this @a Message needs to be polled before the other one. + * @param other the other @a Message to compare with. + * @return true if this @a Message needs to be polled before the other one. + */ + bool isLessPollWeight(Message* other); + private: /** the optional device class. */ @@ -183,10 +199,24 @@ private: const unsigned char m_pollPriority; /** the last decoded value. */ string m_lastValue; - /** the system time when @a m_lastValue was updated. */ + /** the system time when @a m_lastValue was updated, 0 for never. */ time_t m_lastUpdateTime; + /** the number of times this messages was already polled for. */ + unsigned int m_pollCount; + /** the system time when this message was last polled for, 0 for never. */ + time_t m_lastPollTime; + }; + +/** + * @brief A function that compares the poll priority of two @a Message instances. + */ +struct compareMessagePriority : binary_function { + bool operator() (Message* x, Message* y) const { return x->isLessPollWeight(y) == false; }; +}; + + /** * @brief Holds a map of all known @a Message instances. */ @@ -197,7 +227,7 @@ public: /** * @brief Construct a new instance. */ - MessageMap() : FileReader(true), m_minIdLength(4), m_maxIdLength(0) {} + MessageMap() : FileReader(true), m_minIdLength(4), m_maxIdLength(0), m_messageCount(0) {} /** * @brief Destructor. */ @@ -232,6 +262,23 @@ public: * @brief Removes all @a Message instances. */ void clear(); + /** + * @brief Get the number of stored @a Message instances. + * @param passiveOnly true to count only passive messages, false to count all messages. + * @return the the number of stored @a Message instances. + */ + int size(const bool passiveOnly=false) { return passiveOnly ? m_passiveMessagesByKey.size() : m_messageCount; } + /** + * @brief Get the number of stored @a Message instances with a poll priority. + * @return the the number of stored @a Message instances with a poll priority. + */ + int sizePoll() { return m_pollMessages.size(); } + /** + * @brief Get the next @a Message to poll. + * @return the next @a Message to poll, or NULL. + * Note: the caller may not free the returned instance. + */ + Message* getNextPoll(); private: @@ -241,12 +288,18 @@ private: /** the maximum ID length used by any of the known @a Message instances. */ unsigned char m_maxIdLength; + /** the number of distinct @a Message instances stored in @a m_messagesByName. */ + int m_messageCount; + /** the known @a Message instances by class and name. */ map m_messagesByName; /** the known passive @a Message instances by key. */ map m_passiveMessagesByKey; + /** the known @a Message instances to poll, by priority. */ + priority_queue, compareMessagePriority> m_pollMessages; + }; #endif // LIBEBUS_MESSAGE_H_ From 1a138dfe1c89da23382cb83c50fc269f4793d72f Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:49:44 +0100 Subject: [PATCH 81/83] added polling by priority --- src/ebusd/baseloop.cpp | 33 +++++----- src/ebusd/baseloop.h | 3 + src/ebusd/bushandler.cpp | 57 ++++++++++++++-- src/ebusd/bushandler.h | 139 +++++++++++++++++++++++++++++---------- 4 files changed, 175 insertions(+), 57 deletions(-) mode change 100644 => 100755 src/ebusd/baseloop.cpp mode change 100644 => 100755 src/ebusd/bushandler.cpp diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp old mode 100644 new mode 100755 index 42bd1ce0..93a78098 --- a/src/ebusd/baseloop.cpp +++ b/src/ebusd/baseloop.cpp @@ -47,9 +47,9 @@ BaseLoop::BaseLoop() else L.log(bas, error, "error reading config files: %s", getResultCode(result)); - /*L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB()); - L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); - L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());*/ + L.log(bas, event, "commands DB: %d ", m_messages->size()); + L.log(bas, event, " cycle DB: %d ", m_messages->size(true)); + L.log(bas, event, " polling DB: %d ", m_messages->sizePoll()); m_ownAddress = A.getOptVal("address") & 0xff; const bool answer = A.getOptVal("answer"); @@ -65,6 +65,12 @@ BaseLoop::BaseLoop() const unsigned int busAcquireWaitTime = A.getOptVal("acquiretimeout"); const unsigned int slaveRecvTimeout = A.getOptVal("recvtimeout"); const unsigned int lockCount = A.getOptVal("lockcounter"); + int pollInterval = A.getOptVal("pollinterval"); + if (pollInterval <= 0) { + m_pollActive = false; + pollInterval = 0; + } else + m_pollActive = true; // create Port m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &BaseLoop::logRaw, dumpRaw, dumpRawFile, dumpRawMaxSize); @@ -75,10 +81,10 @@ BaseLoop::BaseLoop() // create BusHandler m_busHandler = new BusHandler(m_port, m_messages, - answer ? m_ownAddress : SYN, answer ? (m_ownAddress+5)&0xff : SYN, + m_ownAddress, answer, busLostRetries, failedSendRetries, busAcquireWaitTime, slaveRecvTimeout, - lockCount); + lockCount, pollInterval); m_busHandler->start("bushandler"); // create network @@ -221,23 +227,16 @@ string BaseLoop::decodeMessage(const string& data) if (message != NULL) { - /*if (message->getPollPriority() > 0) + if (m_pollActive == true && message->getPollPriority() > 0) { // get polldata - polldata = m_commands->getPollData(index); - if (polldata != "") { - // decode data - Command* command = new Command(index, (*m_commands)[index], polldata); - - // return result - result << command->calcResult(cmd); - - delete command; + token = message->getLastValue(); + if (token.empty() == false) { + result << token; } else { result << "no data stored"; } - break; - }*/ + } SymbolString master; istringstream input; diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h index 73f6407b..79343201 100644 --- a/src/ebusd/baseloop.h +++ b/src/ebusd/baseloop.h @@ -96,6 +96,9 @@ private: /** the own master address for sending on the bus. */ unsigned char m_ownAddress; + /** whether polling the messages is active. */ + bool m_pollActive; + /** the @a Port instance. */ Port* m_port; diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp old mode 100644 new mode 100755 index 30d43e08..a37906af --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -58,20 +58,41 @@ const char* getStateCode(BusState state) { } -BusRequest::BusRequest(SymbolString& master, SymbolString& slave) - : m_master(master), m_slave(slave), m_finished(false), m_result(RESULT_SYN) +result_t PollRequest::prepare(unsigned char ownMasterAddress) +{ + istringstream input; + result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input); + if (result == RESULT_OK) + L.log(bus, event, " poll msg: %s", m_master.getDataStr().c_str()); + return result; +} + +void PollRequest::notify(result_t result) +{ + ostringstream output; + if (result == RESULT_OK) { + result = m_message->decode(pt_slaveData, m_slave, output); // decode data + } + if (result != RESULT_OK) + L.log(bus, error, "poll %s failed: %s", m_message->getName().c_str(), getResultCode(result)); + else + L.log(bus, event, "poll %s: %s", m_message->getName().c_str(), output.str().c_str()); +} + +ActiveBusRequest::ActiveBusRequest(SymbolString& master, SymbolString& slave) + : BusRequest(master, slave, false), m_finished(false), m_result(RESULT_SYN) { pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cond, NULL); } -BusRequest::~BusRequest() +ActiveBusRequest::~ActiveBusRequest() { pthread_mutex_destroy(&m_mutex); pthread_cond_destroy(&m_cond); } -bool BusRequest::wait(int timeout) +bool ActiveBusRequest::wait(int timeout) { m_finished = false; m_result = RESULT_SYN; @@ -93,7 +114,7 @@ bool BusRequest::wait(int timeout) return result == 0; } -void BusRequest::notify(result_t result) +void ActiveBusRequest::notify(result_t result) { pthread_mutex_lock(&m_mutex); @@ -108,7 +129,7 @@ void BusRequest::notify(result_t result) result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) { result_t result = RESULT_SYN; - BusRequest* request = new BusRequest(master, slave); + ActiveBusRequest* request = new ActiveBusRequest(master, slave); for (int sendRetries=m_failedSendRetries+1, lostRetries=m_busLostRetries+1; sendRetries>=0; sendRetries--) { m_requests.add(request); @@ -172,6 +193,26 @@ result_t BusHandler::handleSymbol() setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up if (m_remainLockCount == 0) { m_request = m_requests.next(false); + if (m_request == NULL && m_pollInterval > 0) { // check for poll/scan + time_t now; + time(&now); + if (m_lastPoll == 0 || difftime(now, m_lastPoll) > m_pollInterval) { + Message* message = m_messages->getNextPoll(); + if (message != NULL) { + m_lastPoll = now; + PollRequest* request = new PollRequest(m_response, message); + result_t ret = request->prepare(m_ownMasterAddress); + if (ret != RESULT_OK) { + L.log(bus, error, " prepare poll message: %s", getResultCode(ret)); + delete request; + } + else { + m_request = request; + m_requests.add(request); + } + } + } + } if (m_request != NULL) { // initiate arbitration sendSymbol = m_request->m_master[0]; sending = true; @@ -435,8 +476,10 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit if (m_request != NULL) { if (state == bs_sendSyn || (result != RESULT_OK && firstRepetition == false)) { L.log(bus, debug, "notify request: %s", getResultCode(result)); - m_request->m_slave = m_response; // TODO nicer + m_request->m_slave = SymbolString(m_response, false, false); m_request->notify(result); + if (m_request->m_isPoll == true) + delete m_request; m_request = NULL; } } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 8ad6e474..268a1d3d 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -58,23 +58,10 @@ enum BusState { bs_sendSyn, // send SYN for completed transfer [active set+get] }; -/** the possible combinations of participants in a single message exchange. */ -enum MessageDirection { - md_thisToAll, // message from us to all (broadcast) - md_thisToMaster, // message from us to another master - md_thisToSlave, // message from us to another slave - md_otherToAll, // message from a master (other than us) to all (broadcast) - md_otherToMaster, // message from a master (other than us) to another master (other than us) - md_otherToSlave, // message from a master (other than us) to another slave (other than us) - md_otherToThisMaster, // message from a master (other than us) to us (as master) - md_otherToThisSlave, // message from a master (other than us) to us (as slave) - md_undefined, -}; - class BusHandler; /** - * @brief Handles input from and output to the bus with respect to the ebus protocol. + * @brief Generic request for sending to and receiving from the bus. */ class BusRequest { @@ -85,13 +72,96 @@ public: * @brief Constructor. * @param master the master data @a SymbolString to send. * @param slave the slave data @a SymbolString received. + * @param isPoll whether this is a poll request. */ - BusRequest(SymbolString& master, SymbolString& slave); + BusRequest(SymbolString& master, SymbolString& slave, bool isPoll) + : m_master(master), m_slave(slave), m_isPoll(isPoll) {} /** * @brief Destructor. */ - virtual ~BusRequest(); + virtual ~BusRequest() {} + + /** + * @brief Notify all waiting threads. + */ + virtual void notify(result_t result) = 0; + +protected: + + /** the master data @a SymbolString to send. */ + SymbolString& m_master; + + /** the slave data @a SymbolString received. */ + SymbolString& m_slave; + + /** whether this is a poll request. */ + bool m_isPoll; + +}; + + +/** + * @brief A poll @a BusRequest handled by @a BusHandler itself. + */ +class PollRequest : public BusRequest +{ + friend class BusHandler; +public: + + /** + * @brief Constructor. + * @param slave the slave data @a SymbolString received. + * @param message the associated @a Message. + */ + PollRequest(SymbolString& slave, Message* message) + : BusRequest(m_master, slave, true), m_message(message) {} + + /** + * @brief Destructor. + */ + virtual ~PollRequest() {} + + /** + * @brief Prepare the master data. + * @param masterAddress the master bus address to use. + * @return the result code. + */ + result_t prepare(unsigned char masterAddress); + + // @copydoc + virtual void notify(result_t result); + +private: + + /** the master data @a SymbolString. */ + SymbolString m_master; + + /** the associated @a Message. */ + Message* m_message; + +}; + + +/** + * @brief An active @a BusRequest that can be waited for. + */ +class ActiveBusRequest : public BusRequest +{ + friend class BusHandler; +public: + + /** + * @brief Constructor. + * @param master the master data @a SymbolString to send. + * @param slave the slave data @a SymbolString received. + */ + ActiveBusRequest(SymbolString& master, SymbolString& slave); + + /** + * @brief Destructor. + */ + virtual ~ActiveBusRequest(); /** * @brief Wait for notification. @@ -100,19 +170,11 @@ public: */ bool wait(int timeout); - /** - * @brief Notify all waiting threads. - */ - void notify(result_t result); + // @copydoc + virtual void notify(result_t result); private: - /** the master data @a SymbolString to send. */ - SymbolString& m_master; - - /** the slave data @a SymbolString received. */ - SymbolString& m_slave; - /** true once the request is finished. */ bool m_finished; @@ -139,24 +201,26 @@ public: * @brief Construct a new instance. * @param port the @a Port instance for accessing the bus. * @param messages the @a MessageMap instance with all known @a Message instances. - * @param ownMasterAddress the own master address to react on master-master messages, or @a SYN to ignore. - * @param ownSlaveAddress the own slave address to react on master-slave messages, or @a SYN to ignore. + * @param ownAddress the own master address. + * @param answer whether to answer queries for the own master/slave address. * @param busLostRetries the number of times a send is repeated due to lost arbitration. * @param failedSendRetries the number of times a failed send is repeated (other than lost arbitration). * @param slaveRecvTimeout the maximum time in microseconds an addressed slave is expected to acknowledge. * @param busAcquireTimeout the maximum time in microseconds for bus acquisition. * @param lockCount the number of AUTO-SYN symbols before sending is allowed after lost arbitration. + * @param pollInterval the interval in seconds in which poll messages are cycled, or 0 if disabled. */ BusHandler(Port* port, MessageMap* messages, - const unsigned char ownMasterAddress, const unsigned char ownSlaveAddress, + const unsigned char ownAddress, const bool answer, const unsigned int busLostRetries, const unsigned int failedSendRetries, const unsigned int busAcquireTimeout, const unsigned int slaveRecvTimeout, - const unsigned int lockCount) + const unsigned int lockCount, const unsigned int pollInterval) : m_port(port), m_messages(messages), - m_ownMasterAddress(ownMasterAddress), m_ownSlaveAddress(ownSlaveAddress), + m_ownMasterAddress(ownAddress), m_ownSlaveAddress((ownAddress+5)&0xff), m_answer(answer), m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout), m_lockCount(lockCount), m_remainLockCount(lockCount), + m_pollInterval(pollInterval), m_lastPoll(0), m_request(NULL), m_nextSendPos(0), m_state(bs_skip), m_repeat(false), m_commandCrcValid(false), m_responseCrcValid(false) {} @@ -213,12 +277,15 @@ private: /** the @a MessageMap instance with all known @a Message instances. */ MessageMap* m_messages; - /** the own master address to react on master-master messages, or @a SYN to ignore. */ + /** the own master address. */ const unsigned char m_ownMasterAddress; - /** the own slave address to react on master-slave messages, or @a SYN to ignore. */ + /** the own slave address. */ const unsigned char m_ownSlaveAddress; + /** whether to answer queries for the own master/slave address. */ + const bool m_answer; + /** the number of times a send is repeated due to lost arbitration. */ const unsigned int m_busLostRetries; @@ -237,6 +304,12 @@ private: /** the remaining number of AUTO-SYN symbols before sending is allowed again. */ unsigned int m_remainLockCount; + /** the interval in seconds in which poll messages are cycled, or 0 if disabled. */ + const unsigned int m_pollInterval; + + /** the time of the last poll, or 0 for never. */ + time_t m_lastPoll; + /** the queue of @a BusRequests that shall be handled. */ WQueue m_requests; From 41152a4031d41d278ab788421ffb5dd277db389d Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:57:05 +0100 Subject: [PATCH 82/83] file mode --- src/ebusd/baseloop.cpp | 0 src/ebusd/bushandler.cpp | 0 src/lib/ebus/message.cpp | 0 src/lib/ebus/symbol.cpp | 0 src/lib/ebus/test/test_data.cpp | 0 src/lib/ebus/test/test_message.cpp | 0 src/lib/ebus/test/test_symbol.cpp | 0 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/ebusd/baseloop.cpp mode change 100755 => 100644 src/ebusd/bushandler.cpp mode change 100755 => 100644 src/lib/ebus/message.cpp mode change 100755 => 100644 src/lib/ebus/symbol.cpp mode change 100755 => 100644 src/lib/ebus/test/test_data.cpp mode change 100755 => 100644 src/lib/ebus/test/test_message.cpp mode change 100755 => 100644 src/lib/ebus/test/test_symbol.cpp diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp old mode 100755 new mode 100644 diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp old mode 100755 new mode 100644 diff --git a/src/lib/ebus/test/test_symbol.cpp b/src/lib/ebus/test/test_symbol.cpp old mode 100755 new mode 100644 From 51bf3dcd4ef95e4936126afa5fc2342808276df9 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 7 Dec 2014 14:59:13 +0100 Subject: [PATCH 83/83] documentation --- src/ebusd/bushandler.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 268a1d3d..27989530 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -83,7 +83,8 @@ public: virtual ~BusRequest() {} /** - * @brief Notify all waiting threads. + * @brief Notify the request of the specified result. + * @param result the result of the request. */ virtual void notify(result_t result) = 0;