diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index fc249d91..a244db05 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -36,12 +36,13 @@ using namespace std; Message::Message(const string clazz, const string name, const bool isWrite, const bool isPassive, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, - const vector id, DataField* data, + const vector id, DataField* data, const bool deleteData, const unsigned char pollPriority) : m_class(clazz), m_name(name), m_isWrite(isWrite), 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_deleteData(deleteData), + m_pollPriority(pollPriority), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) { int exp = 7; @@ -62,7 +63,7 @@ Message::Message(const bool isWrite, const bool isPassive, : m_class(), m_name(), m_isWrite(isWrite), m_isPassive(isPassive), m_comment(), m_srcAddress(SYN), m_dstAddress(SYN), - m_data(data), m_pollPriority(0), + m_data(data), m_deleteData(true), m_pollPriority(0), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) { m_id.push_back(pb); @@ -88,7 +89,7 @@ string getDefault(const string value, vector* defaults, size_t pos) result_t Message::create(vector::iterator& it, const vector::iterator end, vector< vector >* defaultsRows, - DataFieldTemplates* templates, Message*& returnValue) + DataFieldTemplates* templates, vector& messages) { // [type],[class],name,[comment],[QQ],[ZZ],id,fields... result_t result; @@ -167,15 +168,28 @@ result_t Message::create(vector::iterator& it, const vector::ite str = getDefault(*it++, defaults, defaultPos++).c_str(); if (it == end) return RESULT_ERR_EOF; - unsigned char dstAddress; - if (*str == 0) - dstAddress = SYN; // no specific destination - else { - dstAddress = (unsigned char)parseInt(str, 16, 0, 0xff, result); - if (result != RESULT_OK) - return result; - if (!isValidAddress(dstAddress)) - return RESULT_ERR_INVALID_ADDR; + vector dstAddresses; + bool isBroadcastOrMasterDestination = false; + if (*str == 0) { + dstAddresses.push_back(SYN); // no specific destination + } else { + istringstream stream(str); + string token; + bool first = true; + while (getline(stream, token, VALUE_SEPARATOR) != 0) { + unsigned char dstAddress = (unsigned char)parseInt(token.c_str(), 16, 0, 0xff, result); + if (result != RESULT_OK) + return result; + if (!isValidAddress(dstAddress)) + return RESULT_ERR_INVALID_ADDR; + bool broadcastOrMaster = (dstAddress == BROADCAST) || isMaster(dstAddress); + if (first) { + isBroadcastOrMasterDestination = broadcastOrMaster; + first = false; + } else if (isBroadcastOrMasterDestination != broadcastOrMaster) + return RESULT_ERR_INVALID_ADDR; + dstAddresses.push_back(dstAddress); + } } vector id; @@ -240,7 +254,7 @@ result_t Message::create(vector::iterator& it, const vector::ite } } DataField* data = NULL; - result = DataField::create(it, realEnd, templates, data, isWrite, dstAddress==SYN ? ESC : dstAddress); + result = DataField::create(it, realEnd, templates, data, isWrite, false, isBroadcastOrMasterDestination); if (result != RESULT_OK) { return result; } @@ -249,7 +263,18 @@ result_t Message::create(vector::iterator& it, const vector::ite delete data; return RESULT_ERR_INVALID_POS; } - returnValue = new Message(clazz, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data, pollPriority); + size_t index = 0; + bool multiple = dstAddresses.size()>1; + char num[10]; + for (vector::iterator it = dstAddresses.begin(); it != dstAddresses.end(); it++, index++) { + unsigned char dstAddress = *it; + string useClass = clazz; + if (multiple) { + sprintf(num, ".%ld", index); + useClass = useClass + num; + } + messages.push_back(new Message(useClass, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data, pollPriority, index==0)); + } return RESULT_OK; } @@ -516,18 +541,21 @@ result_t MessageMap::addFromFile(vector::iterator& begin, const vector messages; while (getline(stream, type, VALUE_SEPARATOR) != 0) { *restart = type; begin = restart; - Message* message = NULL; - result = Message::create(begin, end, defaults, arg, message); + messages.clear(); + result = Message::create(begin, end, defaults, arg, messages); + for (vector::iterator it = messages.begin(); it != messages.end(); it++) { + Message* message = *it; + if (result == RESULT_OK) + result = add(message); + if (result != RESULT_OK) + delete message; // delete all remaining messages on error + } if (result != RESULT_OK) return result; - result = add(message); - if (result != RESULT_OK) { - delete message; - return result; - } begin = restart; } return result; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a7d0c26d..101fcbb0 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -54,12 +54,13 @@ public: * @param dstAddress the destination address, or @a SYN for any (set later). * @param id the primary, secondary, and optional further ID bytes. * @param data the @a DataField for encoding/decoding the message. + * @param deleteData whether to delete the @a DataField during destruction. * @param pollPriority the priority for polling, or 0 for no polling at all. */ Message(const string clazz, const string name, const bool isWrite, const bool isPassive, const string comment, const unsigned char srcAddress, const unsigned char dstAddress, - const vector id, DataField* data, + const vector id, DataField* data, const bool deleteData, const unsigned char pollPriority); /** @@ -78,21 +79,21 @@ public: /** * Destructor. */ - virtual ~Message() { delete m_data; } + virtual ~Message() { if (m_deleteData) delete m_data; } /** - * Factory method for creating a new instance. + * 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 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. + * @param messages the @a vector to which to add created instances. * @return @a RESULT_OK on success, or an error code. - * Note: the caller needs to free the created instance. + * Note: the caller needs to free the created instances. */ static result_t create(vector::iterator& it, const vector::iterator end, vector< vector >* defaultsRows, - DataFieldTemplates* templates, Message*& returnValue); + DataFieldTemplates* templates, vector& messages); /** * Get the optional device class. @@ -286,6 +287,9 @@ private: /** the @a DataField for encoding/decoding the message. */ DataField* m_data; + /** whether to delete the @a DataField during destruction. */ + const bool m_deleteData; + /** the priority for polling, or 0 for no polling at all. */ const unsigned char m_pollPriority; diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index e13f41d1..69eeae71 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -59,6 +59,8 @@ int main() {"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""}, {"w,,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", "m"}, {"r,ehp,time,,,08,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "md"}, + {"r,ehp,time,,,08;10,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "c"}, + {"r,ehp,time,,,08;09,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "md*"}, {"r,ehp,date,,,08,b509,0d2900,,,date", "23.11.2014", "ff08b509030d2900", "03170b0e", "md"}, {"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"}, @@ -72,7 +74,7 @@ int main() MessageMap* messages = new MessageMap(); Message* message = NULL; - Message* deleteMessage = NULL; + vector deleteMessages; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; istringstream isstr(check[0]); @@ -97,15 +99,19 @@ int main() bool decode = flags.find('d') != string::npos; bool failedPrepare = flags.find('p') != string::npos; bool failedPrepareMatch = flags.find('P') != string::npos; + bool multi = flags.find('*') != string::npos; string item; vector entries; while (getline(isstr, item, FIELD_SEPARATOR) != 0) entries.push_back(item); - if (deleteMessage != NULL) { - delete deleteMessage; - deleteMessage = NULL; + if (deleteMessages.size()>0) { + for (vector::iterator it = deleteMessages.begin(); it!=deleteMessages.end(); it++) { + Message* deleteMessage = *it; + delete deleteMessage; + } + deleteMessages.clear(); } if (isTemplate) { // store new template @@ -138,7 +144,8 @@ int main() } else { vector::iterator it = entries.begin(); - result = Message::create(it, entries.end(), NULL, templates, deleteMessage); + + result = Message::create(it, entries.end(), NULL, templates, deleteMessages); if (failedCreate) { if (result == RESULT_OK) cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; @@ -152,7 +159,7 @@ int main() printErrorPos(entries.begin(), entries.end(), it, "", 0, result); continue; } - if (deleteMessage == NULL) { + if (deleteMessages.size()==0) { cout << "\"" << check[0] << "\": create error: NULL" << endl; continue; } @@ -160,17 +167,31 @@ int main() cout << "\"" << check[0] << "\": create error: trailing input" << endl; continue; } + if (multi && deleteMessages.size()==1) { + cout << "\"" << check[0] << "\": create error: single message instead of multiple" << endl; + continue; + } + if (!multi && deleteMessages.size()>1) { + cout << "\"" << check[0] << "\": create error: multiple messages instead of single" << endl; + continue; + } cout << "\"" << check[0] << "\": create OK" << endl; if (!dontMap) { - result_t result = messages->add(deleteMessage); - if (result != RESULT_OK) { - cout << "\"" << check[0] << "\": add error: " - << getResultCode(result) << endl; - continue; + result_t result = RESULT_OK; + for (vector::iterator it = deleteMessages.begin(); it!=deleteMessages.end(); it++) { + Message* deleteMessage = *it; + result_t result = messages->add(deleteMessage); + if (result != RESULT_OK) { + cout << "\"" << check[0] << "\": add error: " + << getResultCode(result) << endl; + break; + } } + if (result!=RESULT_OK) + continue; cout << " map OK" << endl; - message = deleteMessage; - deleteMessage = NULL; + message = deleteMessages.front(); + deleteMessages.clear(); if (onlyMap) continue; Message* foundMessage = messages->find(mstr); @@ -182,7 +203,7 @@ int main() cout << " find error: different" << endl; } else - message = deleteMessage; + message = deleteMessages.front(); } if (message->isPassive() || decode) { @@ -222,9 +243,12 @@ int main() } } - if (deleteMessage != NULL) { - delete deleteMessage; - deleteMessage = NULL; + if (deleteMessages.size()>0) { + for (vector::iterator it = deleteMessages.begin(); it!=deleteMessages.end(); it++) { + Message* deleteMessage = *it; + delete deleteMessage; + } + deleteMessages.clear(); } delete templates;