Merge remote-tracking branch 'origin/master' into enhanced_device
# Conflicts: # src/lib/ebus/device.cpp
This commit is contained in:
Executable → Regular
+25
-11
@@ -647,8 +647,11 @@ size_t SingleDataField::getLength(PartType partType, size_t maxLength) const {
|
||||
return remainder ? maxLength : m_length;
|
||||
}
|
||||
|
||||
bool SingleDataField::hasFullByteOffset(bool after) const {
|
||||
bool SingleDataField::hasFullByteOffset(bool after, int16_t& previousFirstBit) const {
|
||||
if (m_length > 1) {
|
||||
if (after) {
|
||||
previousFirstBit = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
int16_t firstBit;
|
||||
@@ -658,8 +661,15 @@ bool SingleDataField::hasFullByteOffset(bool after) const {
|
||||
} else {
|
||||
firstBit = 0;
|
||||
}
|
||||
return (m_dataType->getBitCount() % 8) == 0
|
||||
|| (after && firstBit + (m_dataType->getBitCount() % 8) >= 8);
|
||||
bool ret = (m_dataType->getBitCount() % 8) == 0
|
||||
|| (firstBit == previousFirstBit) || (after && firstBit + (m_dataType->getBitCount() % 8) >= 8);
|
||||
// std::cout<<(after?"after,":"before,")<<"prev="<<static_cast<unsigned>(previousFirstBit)<<",first="
|
||||
// <<static_cast<unsigned>(firstBit)<<",length="<<static_cast<unsigned>(m_dataType->getBitCount())
|
||||
// <<" => "<<(ret?"true":"false")<<"\n";
|
||||
if (after) {
|
||||
previousFirstBit = ret ? -1 : firstBit;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t SingleDataField::getCount(PartType partType, const char* fieldName) const {
|
||||
@@ -915,9 +925,10 @@ const DataFieldSet* DataFieldSet::clone() const {
|
||||
size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const {
|
||||
size_t length = 0;
|
||||
bool previousFullByteOffset[] = { true, true, true, true };
|
||||
int16_t previousFirstBit[] = { -1, -1, -1, -1 };
|
||||
for (const auto field : m_fields) {
|
||||
if (field->getPartType() == partType) {
|
||||
if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) {
|
||||
if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false, previousFirstBit[partType])) {
|
||||
length--;
|
||||
}
|
||||
size_t fieldLength = field->getLength(partType, maxLength);
|
||||
@@ -928,7 +939,7 @@ size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const {
|
||||
}
|
||||
length = length + fieldLength;
|
||||
|
||||
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
|
||||
previousFullByteOffset[partType] = field->hasFullByteOffset(true, previousFirstBit[partType]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,12 +1021,13 @@ void DataFieldSet::dump(bool prependFieldSeparator, bool asJson, ostream* output
|
||||
result_t DataFieldSet::read(const SymbolString& data, size_t offset,
|
||||
const char* fieldName, ssize_t fieldIndex, unsigned int* output) const {
|
||||
bool previousFullByteOffset = true, found = false, findFieldIndex = fieldIndex >= 0;
|
||||
int16_t previousFirstBit = -1;
|
||||
PartType partType = data.isMaster() ? pt_masterData : pt_slaveData;
|
||||
for (const auto field : m_fields) {
|
||||
if (field->getPartType() != partType) {
|
||||
continue;
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) {
|
||||
offset--;
|
||||
}
|
||||
result_t result = field->read(data, offset, fieldName, fieldIndex, output);
|
||||
@@ -1023,7 +1035,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset,
|
||||
return result;
|
||||
}
|
||||
offset += field->getLength(partType, data.getDataSize()-offset);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit);
|
||||
if (result != RESULT_EMPTY) {
|
||||
found = true;
|
||||
}
|
||||
@@ -1049,6 +1061,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset,
|
||||
bool leadingSeparator, const char* fieldName, ssize_t fieldIndex,
|
||||
OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const {
|
||||
bool previousFullByteOffset = true, found = false, findFieldIndex = fieldIndex >= 0;
|
||||
int16_t previousFirstBit = -1;
|
||||
if (outputIndex < 0 && (!m_uniqueNames || ((outputFormat & OF_JSON) && !(outputFormat & OF_NAMES)))) {
|
||||
outputIndex = 0;
|
||||
}
|
||||
@@ -1060,7 +1073,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) {
|
||||
offset--;
|
||||
}
|
||||
result_t result = field->read(data, offset, leadingSeparator, fieldName, fieldIndex,
|
||||
@@ -1069,7 +1082,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset,
|
||||
return result;
|
||||
}
|
||||
offset += field->getLength(partType, data.getDataSize()-offset);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit);
|
||||
if (result != RESULT_EMPTY) {
|
||||
found = true;
|
||||
leadingSeparator = true;
|
||||
@@ -1099,12 +1112,13 @@ result_t DataFieldSet::write(char separator, size_t offset, istringstream* input
|
||||
string token;
|
||||
PartType partType = data->isMaster() ? pt_masterData : pt_slaveData;
|
||||
bool previousFullByteOffset = true;
|
||||
int16_t previousFirstBit = -1;
|
||||
size_t baseOffset = offset;
|
||||
for (const auto field : m_fields) {
|
||||
if (field->getPartType() != partType) {
|
||||
continue;
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) {
|
||||
offset--;
|
||||
}
|
||||
result_t result;
|
||||
@@ -1124,7 +1138,7 @@ result_t DataFieldSet::write(char separator, size_t offset, istringstream* input
|
||||
return result;
|
||||
}
|
||||
offset += fieldLength;
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit);
|
||||
}
|
||||
|
||||
if (usedLength != nullptr) {
|
||||
|
||||
+4
-1
@@ -401,10 +401,13 @@ class SingleDataField : public DataField {
|
||||
/**
|
||||
* Get whether this field uses a full byte offset.
|
||||
* @param after @p true to check after consuming the bits, @p false to check before.
|
||||
* @param previousFirstBit the index to the first bit of the previous field, or -1
|
||||
* if the previous field used a full byte offset. Will be updated during the call
|
||||
* when after was true.
|
||||
* @return @p true if this field uses a full byte offset, @p false if this field
|
||||
* only consumes a part of a byte and a subsequent field may re-use the same offset.
|
||||
*/
|
||||
bool hasFullByteOffset(bool after) const;
|
||||
bool hasFullByteOffset(bool after, int16_t& previousFirstBit) const;
|
||||
|
||||
// @copydoc
|
||||
size_t getCount(PartType partType = pt_any, const char* fieldName = nullptr) const override;
|
||||
|
||||
@@ -696,7 +696,7 @@ result_t NumberDataType::readSymbols(size_t offset, size_t length, const SymbolS
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (isnan(val)) {
|
||||
if (val != val) { // !isnan(val)
|
||||
if (outputFormat & OF_JSON) {
|
||||
*output << "null";
|
||||
} else {
|
||||
|
||||
+20
-3
@@ -30,6 +30,9 @@
|
||||
#ifdef HAVE_LINUX_SERIAL
|
||||
# include <linux/serial.h>
|
||||
#endif
|
||||
#ifdef HAVE_FREEBSD_UFTDI
|
||||
# include <dev/usb/uftdiio.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
@@ -392,7 +395,7 @@ result_t SerialDevice::open() {
|
||||
struct termios newSettings;
|
||||
|
||||
// open file descriptor
|
||||
m_fd = ::open(m_name, O_RDWR | O_NOCTTY);
|
||||
m_fd = ::open(m_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
if (m_fd < 0) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
@@ -415,13 +418,24 @@ result_t SerialDevice::open() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREEBSD_UFTDI
|
||||
int param = 0;
|
||||
// flush tx/rx and set low latency on uftdi device
|
||||
if (ioctl(m_fd, UFTDIIOC_GET_LATENCY, ¶m) == 0) {
|
||||
ioctl(m_fd, UFTDIIOC_RESET_IO, ¶m);
|
||||
param = 1;
|
||||
ioctl(m_fd, UFTDIIOC_SET_LATENCY, ¶m);
|
||||
}
|
||||
#endif
|
||||
|
||||
// save current settings
|
||||
tcgetattr(m_fd, &m_oldSettings);
|
||||
|
||||
// create new settings
|
||||
memset(&newSettings, 0, sizeof(newSettings));
|
||||
|
||||
newSettings.c_cflag |= ((m_enhancedProto ? B115200 : B2400) | CS8 | CLOCAL | CREAD);
|
||||
cfsetspeed(&newSettings, m_enhancedProto ? B115200 : B2400);
|
||||
newSettings.c_cflag |= (CS8 | CLOCAL | CREAD);
|
||||
newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode
|
||||
newSettings.c_iflag |= IGNPAR; // ignore parity errors
|
||||
newSettings.c_oflag &= ~OPOST;
|
||||
@@ -434,7 +448,10 @@ result_t SerialDevice::open() {
|
||||
tcflush(m_fd, TCIFLUSH);
|
||||
|
||||
// activate new settings of serial device
|
||||
tcsetattr(m_fd, TCSAFLUSH, &newSettings);
|
||||
if (tcsetattr(m_fd, TCSAFLUSH, &newSettings)) {
|
||||
close();
|
||||
return RESULT_ERR_DEVICE;
|
||||
}
|
||||
|
||||
// set serial device into blocking mode
|
||||
fcntl(m_fd, F_SETFL, fcntl(m_fd, F_GETFL) & ~O_NONBLOCK);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
@@ -120,7 +120,7 @@ void FileReader::tolower(string* str) {
|
||||
|
||||
static size_t hashFunction(const string& str) {
|
||||
size_t hash = 0;
|
||||
for (char c : str) {
|
||||
for (unsigned char c : str) {
|
||||
hash = (31 * hash) ^ c;
|
||||
}
|
||||
return hash;
|
||||
|
||||
Executable → Regular
+82
-55
@@ -45,12 +45,24 @@ using std::endl;
|
||||
/** the bit mask for the ID length and combined ID bytes in the message key. */
|
||||
#define ID_LENGTH_AND_IDS_MASK ((7LL << (8 * 7 + 5)) | 0xffffffffLL)
|
||||
|
||||
/** the bits in the @a ID_SOURCE_MASK for arbitrary source and active read message. */
|
||||
/** the bits in the @a ID_SOURCE_MASK for arbitrary source and active write message. */
|
||||
#define ID_SOURCE_ACTIVE_WRITE (0x1fLL << (8 * 7))
|
||||
|
||||
/** the bits in the @a ID_SOURCE_MASK for arbitrary source and active write message. */
|
||||
/** the bits in the @a ID_SOURCE_MASK for arbitrary source and active read message. */
|
||||
#define ID_SOURCE_ACTIVE_READ (0x1eLL << (8 * 7))
|
||||
|
||||
/**
|
||||
* the bits in the @a ID_SOURCE_MASK for arbitrary source and active write message
|
||||
* to a master (same value as ID_SOURCE_ACTIVE_WRITE for now).
|
||||
*/
|
||||
#define ID_SOURCE_ACTIVE_WRITE_MASTER (0x1fLL << (8 * 7))
|
||||
|
||||
/**
|
||||
* the bits in the @a ID_SOURCE_MASK for arbitrary source and active read message
|
||||
* to a master (same value as ID_SOURCE_ACTIVE_WRITE for now).
|
||||
*/
|
||||
#define ID_SOURCE_ACTIVE_READ_MASTER (0x1eLL << (8 * 7))
|
||||
|
||||
/** special value for invalid message key. */
|
||||
#define INVALID_KEY 0xffffffffffffffffLL
|
||||
|
||||
@@ -79,6 +91,9 @@ static const char* defaultMessageFieldMap[] = { // access level not included in
|
||||
"*name", "part", "type", "divisor/values", "unit", "comment",
|
||||
};
|
||||
|
||||
/** the m_pollOrder of the last polled message. */
|
||||
static unsigned int g_lastPollOrder = 0;
|
||||
|
||||
extern DataFieldTemplates* getTemplates(const string& filename);
|
||||
|
||||
extern result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose,
|
||||
@@ -99,7 +114,7 @@ Message::Message(const string& circuit, const string& level, const string& name,
|
||||
m_data(data), m_deleteData(deleteData),
|
||||
m_pollPriority(pollPriority),
|
||||
m_usedByCondition(false), m_isScanMessage(false), m_condition(condition),
|
||||
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) {
|
||||
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollOrder(0), m_lastPollTime(0) {
|
||||
if (circuit == "scan") {
|
||||
setScanMessage();
|
||||
m_pollPriority = 0;
|
||||
@@ -116,7 +131,7 @@ Message::Message(const string& circuit, const string& level, const string& name,
|
||||
m_data(data), m_deleteData(deleteData),
|
||||
m_pollPriority(0),
|
||||
m_usedByCondition(false), m_isScanMessage(true), m_condition(nullptr),
|
||||
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) {
|
||||
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollOrder(0), m_lastPollTime(0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +173,8 @@ uint64_t Message::createKey(const vector<symbol_t>& id, bool isWrite, bool isPas
|
||||
if (isPassive) {
|
||||
key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25
|
||||
} else {
|
||||
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
key |= isMaster(dstAddress) ? (isWrite ? ID_SOURCE_ACTIVE_WRITE_MASTER : ID_SOURCE_ACTIVE_READ_MASTER)
|
||||
: (isWrite ? ID_SOURCE_ACTIVE_WRITE : ID_SOURCE_ACTIVE_READ); // special values for active
|
||||
}
|
||||
key |= (uint64_t)dstAddress << (8 * 6);
|
||||
int exp = 5;
|
||||
@@ -199,7 +215,7 @@ uint64_t Message::createKey(const MasterSymbolString& master, size_t maxIdLength
|
||||
|
||||
uint64_t Message::createKey(symbol_t pb, symbol_t sb, bool broadcast) {
|
||||
uint64_t key = 0;
|
||||
key |= (broadcast ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
key |= broadcast ? ID_SOURCE_ACTIVE_WRITE : ID_SOURCE_ACTIVE_READ; // special values for active
|
||||
key |= (uint64_t)(broadcast ? BROADCAST : SYN) << (8 * 6);
|
||||
key |= (uint64_t)pb << (8 * 5);
|
||||
key |= (uint64_t)sb << (8 * 4);
|
||||
@@ -596,9 +612,29 @@ bool Message::setPollPriority(size_t priority) {
|
||||
}
|
||||
bool ret = m_pollPriority == 0 && usePriority > 0;
|
||||
m_pollPriority = usePriority;
|
||||
if (ret || m_pollOrder > g_lastPollOrder+(unsigned int)m_pollPriority) {
|
||||
// ensure a later increased or newly set priority does not prefer that message before all others
|
||||
m_pollOrder = g_lastPollOrder+(unsigned int)m_pollPriority;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Message::isLessPollWeight(const Message* other) const {
|
||||
if (m_pollOrder > other->m_pollOrder) {
|
||||
return true;
|
||||
}
|
||||
if (m_pollOrder < other->m_pollOrder) {
|
||||
return false;
|
||||
}
|
||||
if (m_pollPriority > other->m_pollPriority) {
|
||||
return true;
|
||||
}
|
||||
if (m_pollPriority < other->m_pollPriority) {
|
||||
return false;
|
||||
}
|
||||
return m_lastPollTime > other->m_lastPollTime;
|
||||
}
|
||||
|
||||
void Message::setUsedByCondition() {
|
||||
if (m_usedByCondition) {
|
||||
return;
|
||||
@@ -786,26 +822,6 @@ result_t Message::decodeLastDataNumField(const char* fieldName, ssize_t fieldInd
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Message::isLessPollWeight(const Message* other) const {
|
||||
size_t tprio = m_pollPriority;
|
||||
size_t oprio = other->m_pollPriority;
|
||||
size_t tw = tprio * m_pollCount;
|
||||
size_t ow = oprio * other->m_pollCount;
|
||||
if (tw > ow) {
|
||||
return true;
|
||||
}
|
||||
if (tw < ow) {
|
||||
return false;
|
||||
}
|
||||
if (tprio > oprio) {
|
||||
return true;
|
||||
}
|
||||
if (tprio < oprio) {
|
||||
return false;
|
||||
}
|
||||
return m_lastPollTime > other->m_lastPollTime;
|
||||
}
|
||||
|
||||
void Message::dumpHeader(const vector<string>* fieldNames, ostream* output) {
|
||||
bool first = true;
|
||||
if (fieldNames == nullptr) {
|
||||
@@ -1267,6 +1283,7 @@ void ChainedMessage::dumpField(const string& fieldName, bool withConditions, ost
|
||||
* @param sameIdExtAs the optional @a MasterSymbolString to check for having the same ID.
|
||||
* @param onlyAvailable true to include only available messages (default true), false to also include messages that
|
||||
* are currently not available (e.g. due to unresolved or false conditions).
|
||||
* @return the first available @a Message from the list.
|
||||
*/
|
||||
Message* getFirstAvailable(const vector<Message*>& messages, const MasterSymbolString* sameIdExtAs,
|
||||
const bool onlyAvailable = true) {
|
||||
@@ -1287,6 +1304,7 @@ Message* getFirstAvailable(const vector<Message*>& messages, const MasterSymbolS
|
||||
* @param sameIdExtAs the optional @a Message to check for having the same ID.
|
||||
* @param onlyAvailable true to include only available messages (default true), false to also include messages that
|
||||
* are currently not available (e.g. due to unresolved or false conditions).
|
||||
* @return the first available @a Message from the list.
|
||||
*/
|
||||
Message* getFirstAvailable(const vector<Message*>& messages, const Message* sameIdExtAs = nullptr,
|
||||
const bool onlyAvailable = true) {
|
||||
@@ -2566,6 +2584,14 @@ void MessageMap::findAll(const string& circuit, const string& name, const string
|
||||
}
|
||||
}
|
||||
|
||||
Message* MessageMap::getFirstAvailableFromIterator(const map<uint64_t, vector<Message*> >::const_iterator& it,
|
||||
const MasterSymbolString* sameIdExtAs, bool onlyAvailable) const {
|
||||
if (it != m_messagesByKey.end()) {
|
||||
return getFirstAvailable(it->second, sameIdExtAs, onlyAvailable);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination,
|
||||
bool withRead, bool withWrite, bool withPassive, bool onlyAvailable) const {
|
||||
if (anyDestination && master.size() >= 5 && master[4] == 0 && master[2] == 0x07 && master[3] == 0x04) {
|
||||
@@ -2576,6 +2602,7 @@ Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination,
|
||||
if (baseKey == INVALID_KEY) {
|
||||
return nullptr;
|
||||
}
|
||||
bool isWriteDest = isMaster(master[1]) || master[1] == BROADCAST;
|
||||
size_t maxIdLength = Message::getKeyLength(baseKey);
|
||||
for (size_t idLength = maxIdLength; true; idLength--) {
|
||||
uint64_t key = baseKey;
|
||||
@@ -2591,44 +2618,39 @@ Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination,
|
||||
}
|
||||
}
|
||||
}
|
||||
map<uint64_t, vector<Message*> >::const_iterator it;
|
||||
Message* message;
|
||||
if (withPassive) {
|
||||
it = m_messagesByKey.find(key);
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master, onlyAvailable);
|
||||
message = getFirstAvailableFromIterator(m_messagesByKey.find(key), &master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
if ((key & ID_SOURCE_MASK) != 0) {
|
||||
key &= ~ID_SOURCE_MASK;
|
||||
if (withPassive) {
|
||||
// try again without specific source master
|
||||
message = getFirstAvailableFromIterator(m_messagesByKey.find(key), &master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
if ((key & ID_SOURCE_MASK) != 0) {
|
||||
key &= ~ID_SOURCE_MASK;
|
||||
it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
key &= ~ID_SOURCE_MASK;
|
||||
}
|
||||
if (withRead) {
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
// try again with special value for active read
|
||||
message = getFirstAvailableFromIterator(
|
||||
m_messagesByKey.find(key | (isWriteDest ? ID_SOURCE_ACTIVE_READ_MASTER : ID_SOURCE_ACTIVE_READ)),
|
||||
&master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
if (withWrite) {
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
// try again with special value for active write
|
||||
message = getFirstAvailableFromIterator(
|
||||
m_messagesByKey.find(key | (isWriteDest ? ID_SOURCE_ACTIVE_WRITE_MASTER : ID_SOURCE_ACTIVE_WRITE)),
|
||||
&master, onlyAvailable);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
if (idLength == 0) {
|
||||
@@ -2751,11 +2773,16 @@ Message* MessageMap::getNextPoll() {
|
||||
if (m_pollMessages.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
lock();
|
||||
Message* ret = m_pollMessages.top();
|
||||
m_pollMessages.pop();
|
||||
ret->m_pollCount++;
|
||||
if (ret->m_pollOrder > g_lastPollOrder) {
|
||||
g_lastPollOrder = ret->m_pollOrder;
|
||||
}
|
||||
ret->m_pollOrder += (unsigned int)ret->m_pollPriority;
|
||||
time(&(ret->m_lastPollTime));
|
||||
m_pollMessages.push(ret); // re-insert at new position
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Executable → Regular
+14
-3
@@ -642,8 +642,8 @@ class Message : public AttributedItem {
|
||||
/** the system time when the message content was last changed, 0 for never. */
|
||||
time_t m_lastChangeTime;
|
||||
|
||||
/** the number of times this messages was already polled for. */
|
||||
unsigned int m_pollCount;
|
||||
/** the polling order of this message (roughly number of polls * priority). */
|
||||
unsigned int m_pollOrder;
|
||||
|
||||
/** the system time when this message was last polled for, 0 for never. */
|
||||
time_t m_lastPollTime;
|
||||
@@ -1403,13 +1403,24 @@ class MessageMap : public MappedFileReader {
|
||||
* address), or 0 to ignore.
|
||||
* @param until the end time to which to add updates (exclusive, also removes messages with unset destination
|
||||
* address), or 0 to ignore.
|
||||
* @changedSince true to use the last change time for the since/until range, false to use the last seen time.
|
||||
* @param changedSince true to use the last change time for the since/until range, false to use the last seen time.
|
||||
* @param messages the @a deque to which to add the found @a Message instances.
|
||||
*/
|
||||
void findAll(const string& circuit, const string& name, const string& levels,
|
||||
bool completeMatch, bool withRead, bool withWrite, bool withPassive, bool includeEmptyLevel, bool onlyAvailable,
|
||||
time_t since, time_t until, bool changedSince, deque<Message*>* messages) const;
|
||||
|
||||
/**
|
||||
* Get the first available @a Message from the first map iterator entry.
|
||||
* @param it the map iterator with list of @a Message instances to check.
|
||||
* @param sameIdExtAs the optional @a MasterSymbolString to check for having the same ID.
|
||||
* @param onlyAvailable true to include only available messages (default true), false to also include messages that
|
||||
* are currently not available (e.g. due to unresolved or false conditions).
|
||||
* @return the first available @a Message from the first map iterator entry.
|
||||
*/
|
||||
Message* getFirstAvailableFromIterator(const map<uint64_t, vector<Message*> >::const_iterator& it,
|
||||
const MasterSymbolString* sameIdExtAs, bool onlyAvailable) const;
|
||||
|
||||
/**
|
||||
* Find the @a Message instance for the specified master data.
|
||||
* @param master the @a MasterSymbolString for identifying the @a Message.
|
||||
|
||||
@@ -228,6 +228,9 @@ int main() {
|
||||
{"x,,ttq", "23:45", "10fe0700015f", "00", ""},
|
||||
{"x,,ttq", "24:00", "10fe07000160", "00", ""},
|
||||
{"x,,ttq", "-:-", "10fe07000100", "00", ""},
|
||||
{"x,,ttq,,,,,,ttq", "23:00;05:45", "10fe0700025c17", "00", ""},
|
||||
{"x,,ttq,,,,,,bi7,,,,,,ttq", "23:00;0;05:45", "10fe0700025c17", "00", ""},
|
||||
{"x,,ttq,,,,,,bi7,,,,,,ttq", "23:00;1;05:45", "10fe070002dc17", "00", ""},
|
||||
{"x,,ttq", "", "10fe07000161", "00", "rw"},
|
||||
{"x,,ttq,2", "", "", "", "c"},
|
||||
{"x,,ttq,,,,y,,bi7", "23:45;0", "10fe0700015f", "00", ""}, // bit combination
|
||||
|
||||
Executable → Regular
+6
-2
@@ -173,7 +173,11 @@ int main() {
|
||||
{"w,,x,,,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:6,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "1;1;1;0;0;0", "ff08b509030e0700", "00", "di" },
|
||||
{"w,,x,,,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:6,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "1;0;0;0;0;1", "ff08b509030e0104", "00", "di" },
|
||||
{"w,,x,,,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:6,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "0;0;1;0;1;1", "ff08b509030e0406", "00", "di" },
|
||||
{"*r,cir*cuit#level,na*me,com*ment,ff,75,b509,0d", "", "", "", "" },
|
||||
{"r,470,ccTimer.Monday,,,15,B515,0002,,,IGN:1,,,,from,,TTM", "", "", "", "M"},
|
||||
{"w,470,ccTimer.Monday,,,10,B515,0002,from,,TTM", "", "", "", "kM*"},
|
||||
{"", "19:00", "3115b515020002", "080272", "kd"},
|
||||
{"", "19:00", "3110b51503000272", "00", "kd"},
|
||||
{"*r,cir*cuit#level,na*me,com*ment,ff,75,b509,0d", "", "", "", ""},
|
||||
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH", "r,cirCIRCUITcuit,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42", "ff75b509030d0100", "012a", "DN"},
|
||||
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH",
|
||||
// "\"naNAMEme\": {r,cirCIRCUITcuit,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42"
|
||||
@@ -420,7 +424,7 @@ int main() {
|
||||
result = message->decodeLastData(false, nullptr, -1,
|
||||
(decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), &output);
|
||||
if (result != RESULT_OK) {
|
||||
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: "
|
||||
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error " << (message->isWrite() ? "write: " : "read: ")
|
||||
<< getResultCode(result) << endl;
|
||||
error = true;
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user