code style

This commit is contained in:
john30
2017-01-14 19:00:47 +01:00
parent ebcb260d5f
commit 5bf2f124b3
42 changed files with 1347 additions and 1066 deletions
+76 -61
View File
@@ -89,12 +89,14 @@ bool PollRequest::notify(result_t result, SymbolString& slave) {
}
ostringstream output;
if (result == RESULT_OK) {
result = m_message->decodeLastData(output); // decode data
result = m_message->decodeLastData(output); // decode data
}
if (result < RESULT_OK) {
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), getResultCode(result));
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(),
getResultCode(result));
} else {
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), output.str().c_str());
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(),
output.str().c_str());
}
return false;
}
@@ -105,11 +107,12 @@ result_t ScanRequest::prepare(unsigned char ownMasterAddress) {
return RESULT_ERR_EOF;
}
unsigned char dstAddress = m_slaves.front();
if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
m_busHandler->setScanResult(dstAddress, "");
}
istringstream input;
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index);
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress,
m_index);
if (result >= RESULT_OK) {
logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getDataStr().c_str());
}
@@ -123,12 +126,12 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
Message* message = m_messageMap->getScanMessage(dstAddress);
if (message != NULL) {
m_message = message;
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
}
} else if (m_message->getDstAddress() == SYN) {
m_message = m_message->derive(dstAddress, true);
m_messageMap->add(m_message);
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
}
result = m_message->storeLastData(pt_slaveData, slave, m_index);
if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
@@ -139,7 +142,7 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
}
}
if (result == RESULT_OK) {
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
}
}
if (result < RESULT_OK) {
@@ -151,14 +154,14 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
} else {
logError(lf_bus, "scan %2.2x failed (%d slaves left): %s", dstAddress, m_slaves.size(), getResultCode(result));
}
m_messages.clear(); // skip remaining secondary messages
m_messages.clear(); // skip remaining secondary messages
} else if (m_messages.empty()) {
if (!m_slaves.empty()) {
m_slaves.pop_front();
}
logNotice(lf_bus, "scan %2.2x completed (%d slaves left)", dstAddress, m_slaves.size());
}
if (m_messages.empty()) { // last message for this address
if (m_messages.empty()) { // last message for this address
m_busHandler->setScanResult(dstAddress, m_scanResult.str());
}
if (m_slaves.empty()) {
@@ -176,7 +179,7 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
m_messages.pop_front();
if (prepare(m_master[0]) < RESULT_OK) {
m_busHandler->setScanFinished();
return false; // give up
return false; // give up
}
return true;
}
@@ -337,10 +340,10 @@ result_t BusHandler::handleSymbol() {
case bs_ready:
if (m_currentRequest != NULL) {
setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up
setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up
} else if (m_remainLockCount == 0) {
startRequest = m_nextRequests.peek();
if (startRequest == NULL && m_pollInterval > 0) { // check for poll/scan
if (startRequest == NULL && m_pollInterval > 0) { // check for poll/scan
time_t now;
time(&now);
if (m_lastPoll == 0 || difftime(now, m_lastPoll) > m_pollInterval) {
@@ -359,7 +362,7 @@ result_t BusHandler::handleSymbol() {
}
}
}
if (startRequest != NULL) { // initiate arbitration
if (startRequest != NULL) { // initiate arbitration
sendSymbol = m_ownMasterAddress;
sending = true;
}
@@ -385,7 +388,7 @@ result_t BusHandler::handleSymbol() {
case bs_sendCmd:
if (m_currentRequest != NULL) {
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command
sending = true;
}
break;
@@ -406,7 +409,7 @@ result_t BusHandler::handleSymbol() {
case bs_sendRes:
if (m_answer) {
sendSymbol = m_response[m_nextSendPos]; // escaped response
sendSymbol = m_response[m_nextSendPos]; // escaped response
sending = true;
}
break;
@@ -431,7 +434,7 @@ result_t BusHandler::handleSymbol() {
sending = false;
timeout = SYN_TIMEOUT;
if (startRequest != NULL && m_nextRequests.remove(startRequest)) {
m_currentRequest = startRequest; // force the failed request to be notified
m_currentRequest = startRequest; // force the failed request to be notified
}
setState(bs_skip, result);
}
@@ -471,9 +474,10 @@ result_t BusHandler::handleSymbol() {
time(&now);
if (result != RESULT_OK) {
if (sending && startRequest != NULL && m_nextRequests.remove(startRequest)) {
m_currentRequest = startRequest; // force the failed request to be notified
m_currentRequest = startRequest; // force the failed request to be notified
}
if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1) // at least one full second has passed since last received symbol
if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1)
// at least one full second has passed since last received symbol
|| m_state == bs_noSignal) {
return setState(bs_noSignal, result);
}
@@ -485,7 +489,7 @@ result_t BusHandler::handleSymbol() {
if (!sending && m_remainLockCount > 0 && m_command.size() != 1) {
m_remainLockCount--;
} else if (!sending && m_remainLockCount == 0 && m_command.size() == 1) {
m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority)
m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority)
}
return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN);
}
@@ -507,20 +511,20 @@ result_t BusHandler::handleSymbol() {
}
m_currentRequest = startRequest;
// check arbitration
if (recvSymbol == sendSymbol) { // arbitration successful
if (recvSymbol == sendSymbol) { // arbitration successful
m_nextSendPos = 1;
m_repeat = false;
return setState(bs_sendCmd, RESULT_OK);
}
// arbitration lost. if same priority class found, try again after next AUTO-SYN
m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try
m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try
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
setState(m_state, RESULT_ERR_BUS_LOST); // try again later
}
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
if (result < RESULT_OK) {
return setState(bs_skip, result);
}
@@ -529,14 +533,16 @@ result_t BusHandler::handleSymbol() {
case bs_recvCmd:
headerLen = 4;
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; // header symbols are never escaped
// header symbols are never escaped
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff;
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
if (result < RESULT_OK) {
return setState(bs_skip, result);
}
if (result == RESULT_OK && crcPos != 0xff && 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];
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); // header symbols are never escaped
// header symbols are never escaped
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC();
if (m_commandCrcValid) {
if (dstAddress == BROADCAST) {
receiveCompleted();
@@ -570,7 +576,7 @@ result_t BusHandler::handleSymbol() {
if (isMaster(m_currentRequest->m_master[1])) {
return setState(bs_sendSyn, RESULT_OK);
}
} else if (isMaster(m_command[1])) { // header symbols are never escaped
} else if (isMaster(m_command[1])) { // header symbols are never escaped
receiveCompleted();
return setState(bs_skip, RESULT_OK);
}
@@ -599,7 +605,7 @@ result_t BusHandler::handleSymbol() {
if (result < RESULT_OK) {
return setState(bs_skip, result);
}
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
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_responseCrcValid) {
if (m_currentRequest != NULL) {
@@ -681,14 +687,14 @@ result_t BusHandler::handleSymbol() {
return setState(bs_skip, RESULT_ERR_ACK);
}
if (isMaster(m_command[1])) {
receiveCompleted(); // decode command and store value
receiveCompleted(); // decode command and store value
return setState(bs_skip, RESULT_OK);
}
m_nextSendPos = 0;
m_repeat = false;
Message* message;
istringstream input; // TODO create input from database of internal variables
istringstream input; // TODO create input from database of internal variables
message = m_messages->find(m_command);
if (message == NULL) {
message = m_messages->find(m_command, true);
@@ -697,13 +703,14 @@ result_t BusHandler::handleSymbol() {
}
}
if (message == NULL || message->isWrite()) {
return setState(bs_skip, RESULT_ERR_INVALID_ARG); // don't know this request or definition has wrong direction, deny
// don't know this request or definition has wrong direction, deny
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
}
if (message == m_messages->getScanMessage(m_ownSlaveAddress)) {
input.str(SCAN_ANSWER);
}
// build response and store in m_response for sending back to requesting master
m_response.clear(true); // escape while sending response
m_response.clear(true); // escape while sending response
result = message->prepareSlave(input, m_response);
if (result != RESULT_OK) {
return setState(bs_skip, result);
@@ -739,7 +746,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
if (result == RESULT_ERR_BUS_LOST && m_currentRequest->m_busLostRetries < m_busLostRetries) {
logDebug(lf_bus, "%s during %s, retry", getResultCode(result), getStateCode(m_state));
m_currentRequest->m_busLostRetries++;
m_nextRequests.push(m_currentRequest); // repeat
m_nextRequests.push(m_currentRequest); // repeat
m_currentRequest = NULL;
} else if (state == bs_sendSyn || (result != RESULT_OK && !firstRepetition)) {
logDebug(lf_bus, "notify request: %s", getResultCode(result));
@@ -748,7 +755,8 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
addSeenAddress(dstAddress);
}
bool restart = m_currentRequest->notify(
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes) ? RESULT_ERR_TIMEOUT : result, m_response);
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes)
? RESULT_ERR_TIMEOUT : result, m_response);
if (restart) {
m_currentRequest->m_busLostRetries = 0;
m_nextRequests.push(m_currentRequest);
@@ -761,11 +769,11 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
}
}
if (state == bs_noSignal) { // notify all requests
m_response.clear(false); // notify with empty response
if (state == bs_noSignal) { // notify all requests
m_response.clear(false); // notify with empty response
while ((m_currentRequest = m_nextRequests.pop()) != NULL) {
bool restart = m_currentRequest->notify(RESULT_ERR_NO_SIGNAL, m_response);
if (restart) { // should not occur with no signal
if (restart) { // should not occur with no signal
m_currentRequest->m_busLostRetries = 0;
m_nextRequests.push(m_currentRequest);
} else if (m_currentRequest->m_deleteOnFinish) {
@@ -780,7 +788,8 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
return result;
}
if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) {
logDebug(lf_bus, "%s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state));
logDebug(lf_bus, "%s during %s, switching to %s", getResultCode(result), getStateCode(m_state),
getStateCode(state));
} else if (m_currentRequest != NULL || state == bs_sendCmd || state == bs_sendResAck || state == bs_sendSyn) {
logDebug(lf_bus, "switching from %s to %s", getStateCode(m_state), getStateCode(state));
}
@@ -794,7 +803,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
if (state == bs_ready || state == bs_skip) {
m_command.clear();
m_commandCrcValid = false;
m_response.clear(false); // unescape while receiving response
m_response.clear(false); // unescape while receiving response
m_responseCrcValid = false;
m_nextSendPos = 0;
}
@@ -883,7 +892,7 @@ void BusHandler::receiveCompleted() {
if (message) {
key = message->getKey();
} else {
key = Message::createKey(m_command, 4); // up to 4 DD bytes
key = Message::createKey(m_command, 4); // up to 4 DD bytes
}
m_grabbedMessages[key].setLastData(m_command, m_response);
}
@@ -893,7 +902,8 @@ void BusHandler::receiveCompleted() {
} else if (master) {
logNotice(lf_update, "unknown MM cmd: %s", m_command.getDataStr().c_str());
} else {
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str());
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getDataStr().c_str(),
m_response.getDataStr().c_str());
}
} else {
m_messages->invalidateCache(message);
@@ -905,18 +915,21 @@ void BusHandler::receiveCompleted() {
result = message->decodeLastData(output);
}
if (result < RESULT_OK) {
logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result));
logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(),
m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result));
} else {
string data = output.str();
if (m_answer && dstAddress == (master ? m_ownMasterAddress : m_ownSlaveAddress)) {
logNotice(lf_update, "self-update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, data.c_str()); // TODO store in database of internal variables
} else if (message->getDstAddress() == SYN) { // any destination
if (message->getSrcAddress() == SYN) { // any destination and any source
logNotice(lf_update, "update %s %s QQ=%2.2x ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, dstAddress, data.c_str());
logNotice(lf_update, "self-update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress,
data.c_str()); // TODO store in database of internal variables
} else if (message->getDstAddress() == SYN) { // any destination
if (message->getSrcAddress() == SYN) { // any destination and any source
logNotice(lf_update, "update %s %s QQ=%2.2x ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress,
dstAddress, data.c_str());
} else {
logNotice(lf_update, "update %s %s ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), dstAddress, data.c_str());
}
} else if (message->getSrcAddress() == SYN) { // any source
} else if (message->getSrcAddress() == SYN) { // any source
logNotice(lf_update, "update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, data.c_str());
} else {
logNotice(lf_update, "update %s %s: %s", circuit.c_str(), name.c_str(), data.c_str());
@@ -930,7 +943,7 @@ result_t BusHandler::startScan(bool full) {
for (deque<Message*>::iterator it = messages.begin(); it < messages.end(); it++) {
Message* message = *it;
if (message->getPrimaryCommand() == 0x07 && message->getSecondaryCommand() == 0x04) {
messages.erase(it--); // query pb 0x07 / sb 0x04 only once
messages.erase(it--); // query pb 0x07 / sb 0x04 only once
}
}
@@ -941,12 +954,12 @@ result_t BusHandler::startScan(bool full) {
m_scanResults.clear();
deque<unsigned char> slaves;
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (!isValidAddress(slave, false) || isMaster(slave)) {
continue;
}
if (!full && (m_seenAddresses[slave]&SEEN) == 0) {
unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already
unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already
if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
continue;
}
@@ -985,7 +998,7 @@ void BusHandler::formatScanResult(ostringstream& output) {
output << static_cast<unsigned>(m_runningScans) << " scan(s) still running" << endl;
}
bool first = true;
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
map<unsigned char, string>::iterator it = m_scanResults.find(slave);
if (it != m_scanResults.end()) {
if (first) {
@@ -998,7 +1011,7 @@ void BusHandler::formatScanResult(ostringstream& output) {
}
if (first) {
// fallback to autoscan results
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (isValidAddress(slave, false) && !isMaster(slave) && (m_seenAddresses[slave]&SCAN_DONE) != 0) {
Message* message = m_messages->getScanMessage(slave);
if (message != NULL && message->getLastUpdateTime() > 0) {
@@ -1018,8 +1031,8 @@ void BusHandler::formatScanResult(ostringstream& output) {
void BusHandler::formatSeenInfo(ostringstream& output) {
unsigned char address = 0;
for (int index = 0; index < 256; index++, address++) {
if (isValidAddress(address, false)
&& ((m_seenAddresses[address]&SEEN) != 0 || (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)))) {
if (isValidAddress(address, false) && ((m_seenAddresses[address]&SEEN) != 0
|| (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)))) {
output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address);
unsigned char master;
if (isMaster(address)) {
@@ -1081,17 +1094,18 @@ result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
Message* message = m_messages->getScanMessage(dstAddress);
if (message != NULL && message != scanMessage) {
scanMessage = message;
scanMessage->storeLastData(pt_masterData, master, 0); // update the cache, expected to work since this is a clone
// update the cache, expected to work since this is a clone
scanMessage->storeLastData(pt_masterData, master, 0);
}
}
if (result != RESULT_ERR_NO_SIGNAL) {
m_seenAddresses[dstAddress] |= SCAN_DONE;
}
}
if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
return result;
}
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
}
bool BusHandler::enableGrab(bool enable) {
@@ -1110,7 +1124,8 @@ void BusHandler::formatGrabResult(const bool unknown, ostringstream& output) {
output << "grab disabled";
} else {
bool first = true;
for (map<uint64_t, GrabbedMessage>::iterator it = m_grabbedMessages.begin(); it != m_grabbedMessages.end(); it++) {
for (map<uint64_t, GrabbedMessage>::iterator it = m_grabbedMessages.begin(); it != m_grabbedMessages.end();
it++) {
if (it->second.dump(unknown, m_messages, first, output)) {
first = false;
}
@@ -1122,7 +1137,7 @@ unsigned char BusHandler::getNextScanAddress(unsigned char lastAddress, bool& sc
if (lastAddress == SYN) {
return SYN;
}
while (++lastAddress != 0) { // 0 is known to be a master
while (++lastAddress != 0) { // 0 is known to be a master
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) {
continue;
}
@@ -1147,4 +1162,4 @@ void BusHandler::setScanConfigLoaded(unsigned char address, string file) {
}
}
} // namespace ebusd
} // namespace ebusd
+18 -16
View File
@@ -99,7 +99,7 @@ class BusHandler;
class BusRequest {
friend class BusHandler;
public:
public:
/**
* Constructor.
* @param master the escaped master data @a SymbolString to send.
@@ -123,7 +123,7 @@ class BusRequest {
virtual bool notify(result_t result, SymbolString& slave) = 0;
protected:
protected:
/** the escaped master data @a SymbolString to send. */
SymbolString& m_master;
@@ -141,7 +141,7 @@ class BusRequest {
class PollRequest : public BusRequest {
friend class BusHandler;
public:
public:
/**
* Constructor.
* @param message the associated @a Message.
@@ -165,7 +165,7 @@ class PollRequest : public BusRequest {
virtual bool notify(result_t result, SymbolString& slave);
private:
private:
/** the escaped master data @a SymbolString. */
SymbolString m_master;
@@ -183,7 +183,7 @@ class PollRequest : public BusRequest {
class ScanRequest : public BusRequest {
friend class BusHandler;
public:
public:
/**
* Constructor.
* @param messageMap the @a MessageMap instance.
@@ -192,7 +192,8 @@ class ScanRequest : public BusRequest {
* @param busHandler the @a BusHandler instance to notify of final scan result.
*/
ScanRequest(MessageMap* messageMap, deque<Message*> messages, deque<unsigned char> slaves, BusHandler* busHandler)
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages), m_slaves(slaves), m_busHandler(busHandler) {
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages),
m_slaves(slaves), m_busHandler(busHandler) {
m_message = m_messages.front();
m_messages.pop_front();
}
@@ -213,7 +214,7 @@ class ScanRequest : public BusRequest {
virtual bool notify(result_t result, SymbolString& slave);
private:
private:
/** the @a MessageMap instance. */
MessageMap* m_messageMap;
@@ -249,7 +250,7 @@ class ScanRequest : public BusRequest {
class ActiveBusRequest : public BusRequest {
friend class BusHandler;
public:
public:
/**
* Constructor.
* @param master the escaped master data @a SymbolString to send.
@@ -267,7 +268,7 @@ class ActiveBusRequest : public BusRequest {
virtual bool notify(result_t result, SymbolString& slave);
private:
private:
/** the result of handling the request. */
result_t m_result;
@@ -280,7 +281,7 @@ class ActiveBusRequest : public BusRequest {
* Helper class for keeping track of grabbed messages.
*/
class GrabbedMessage {
public:
public:
/**
* Construct a new instance.
*/
@@ -313,7 +314,7 @@ class GrabbedMessage {
bool dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output);
private:
private:
/** the last master @a SymbolString. */
SymbolString m_lastMaster;
@@ -329,7 +330,7 @@ class GrabbedMessage {
* Handles input from and output to the bus with respect to the eBUS protocol.
*/
class BusHandler : public WaitThread {
public:
public:
/**
* Construct a new instance.
* @param device the @a Device instance for accessing the bus.
@@ -356,7 +357,8 @@ class BusHandler : public WaitThread {
m_answer(answer), m_addressConflict(false),
m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries),
m_transferLatency(transferLatency), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout),
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0), m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0),
m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
m_generateSynInterval(generateSyn ? SYN_TIMEOUT*getMasterNumber(ownAddress)+SYMBOL_DURATION : 0),
m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0),
m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0),
@@ -513,7 +515,7 @@ class BusHandler : public WaitThread {
void setScanConfigLoaded(unsigned char address, string file);
private:
private:
/**
* Handle the next symbol on the bus.
* @return RESULT_OK on success, or an error code.
@@ -653,6 +655,6 @@ class BusHandler : public WaitThread {
map<uint64_t, GrabbedMessage> m_grabbedMessages;
};
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_BUSHANDLER_H_
#endif // EBUSD_BUSHANDLER_H_
+1 -1
View File
@@ -71,4 +71,4 @@ void DataSink::notifyUpdate(Message* message) {
m_updatedMessages[message]++;
}
} // namespace ebusd
} // namespace ebusd
+7 -7
View File
@@ -58,7 +58,7 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
* Base class for all kinds of data handlers.
*/
class DataHandler {
public:
public:
/**
* Constructor.
*/
@@ -92,7 +92,7 @@ class DataHandler {
* Base class for listening to data updates.
*/
class DataSink : virtual public DataHandler {
public:
public:
/**
* Constructor.
*/
@@ -113,7 +113,7 @@ class DataSink : virtual public DataHandler {
virtual bool isDataSink() { return true; }
protected:
protected:
/** a map of updated @p Message instances. */
map<Message*, int> m_updatedMessages;
};
@@ -123,7 +123,7 @@ class DataSink : virtual public DataHandler {
* Base class providing data to be sent on the bus.
*/
class DataSource : virtual public DataHandler {
public:
public:
/**
* Constructor.
* @param busHandler the @a BusHandler instance.
@@ -140,11 +140,11 @@ class DataSource : virtual public DataHandler {
virtual bool isDataSource() { return true; }
protected:
protected:
/** the @a BusHandler instance. */
BusHandler* m_busHandler;
};
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_DATAHANDLER_H_
#endif // EBUSD_DATAHANDLER_H_
+126 -103
View File
@@ -75,38 +75,38 @@ static bool isDaemon = false;
/** the program options. */
static struct options opt = {
"/dev/ttyUSB0", // device
false, // noDeviceCheck
false, // readOnly
false, // initialSend
-1, // latency
CONFIG_PATH, // configPath
false, // scanConfig
BROADCAST, // initialScan
0, // checkConfig
5, // pollInterval
0x31, // address
false, // answer
9400, // acquireTimeout
3, // acquireRetries
2, // sendRetries
SLAVE_RECV_TIMEOUT*5/3, // receiveTimeout
0, // masterCount
false, // generateSyn
false, // foreground
false, // enableHex
PID_FILE_NAME, // pidFile
8888, // port
false, // localOnly
0, // httpPort
"/var/" PACKAGE "/html", // htmlPath
PACKAGE_LOGFILE, // logFile
false, // logRaw
PACKAGE_LOGFILE, // logRawFile
100, // logRawSize
false, // dump
"/tmp/" PACKAGE "_dump.bin", // dumpFile
100, // dumpSize
"/dev/ttyUSB0", // device
false, // noDeviceCheck
false, // readOnly
false, // initialSend
-1, // latency
CONFIG_PATH, // configPath
false, // scanConfig
BROADCAST, // initialScan
0, // checkConfig
5, // pollInterval
0x31, // address
false, // answer
9400, // acquireTimeout
3, // acquireRetries
2, // sendRetries
SLAVE_RECV_TIMEOUT*5/3, // receiveTimeout
0, // masterCount
false, // generateSyn
false, // foreground
false, // enableHex
PID_FILE_NAME, // pidFile
8888, // port
false, // localOnly
0, // httpPort
"/var/" PACKAGE "/html", // htmlPath
PACKAGE_LOGFILE, // logFile
false, // logRaw
PACKAGE_LOGFILE, // logRawFile
100, // logRawSize
false, // dump
"/tmp/" PACKAGE "_dump.bin", // dumpFile
100, // dumpSize
};
/** the @a MessageMap instance, or NULL. */
@@ -161,7 +161,10 @@ static const struct argp_option argpoptions[] = {
{NULL, 0, NULL, 0, "Message configuration options:", 2 },
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 },
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR=\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, default is broadcast ident message). If combined with --checkconfig, you can add scan message data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
"default is broadcast ident message). If combined with --checkconfig, you can add scan message data as "
"arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
{"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 },
{"dumpconfig", O_DMPCFG, NULL, 0, "Check and dump CSV config files, then stop", 0 },
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
@@ -187,8 +190,10 @@ static const struct argp_option argpoptions[] = {
{NULL, 0, NULL, 0, "Log options:", 5 },
{"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon) [" PACKAGE_LOGFILE "]", 0 },
{"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main,network,bus,update,all [all]", 0 },
{"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error/notice/info/debug [notice]", 0 },
{"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main,network,bus,update,all "
"[all]", 0 },
{"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error/notice/info/debug "
"[notice]", 0 },
{NULL, 0, NULL, 0, "Raw logging options:", 6 },
{"lograwdata", O_RAW, NULL, 0, "Log each received/sent byte on the bus", 0 },
@@ -224,27 +229,27 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
switch (key) {
// Device options:
case 'd': // --device=/dev/ttyUSB0
case 'd': // --device=/dev/ttyUSB0
if (arg == NULL || arg[0] == 0) {
argp_error(state, "invalid device");
return EINVAL;
}
opt->device = arg;
break;
case 'n': // --nodevicecheck
case 'n': // --nodevicecheck
opt->noDeviceCheck = true;
break;
case 'r': // --readonly
case 'r': // --readonly
opt->readOnly = true;
if (opt->scanConfig || opt->answer || opt->generateSyn) {
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
return EINVAL;
}
break;
case O_INISND: // --initsend
case O_INISND: // --initsend
opt->initialSend = true;
break;
case O_DEVLAT: // --latency=10000
case O_DEVLAT: // --latency=10000
opt->latency = parseInt(arg, 10, 0, 200000, result);
if (result != RESULT_OK) {
argp_error(state, "invalid latency");
@@ -253,14 +258,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
break;
// Message configuration options:
case 'c': // --configpath=/etc/ebusd
case 'c': // --configpath=/etc/ebusd
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid configpath");
return EINVAL;
}
opt->configPath = arg;
break;
case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>)
case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>)
opt->scanConfig = true;
if (opt->readOnly) {
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
@@ -287,15 +292,15 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
}
}
break;
case O_CHKCFG: // --checkconfig
case O_CHKCFG: // --checkconfig
if (opt->checkConfig == 0) {
opt->checkConfig = 1;
}
break;
case O_DMPCFG: // --dumpconfig
case O_DMPCFG: // --dumpconfig
opt->checkConfig = 2;
break;
case O_POLINT: // --pollinterval=5
case O_POLINT: // --pollinterval=5
opt->pollInterval = parseInt(arg, 10, 0, 3600, result);
if (result != RESULT_OK) {
argp_error(state, "invalid pollinterval");
@@ -308,56 +313,56 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
break;
// eBUS options:
case 'a': // --address=31
case 'a': // --address=31
opt->address = (unsigned char)parseInt(arg, 16, 0, 0xff, result);
if (result != RESULT_OK || !isMaster(opt->address)) {
argp_error(state, "invalid address");
return EINVAL;
}
break;
case O_ANSWER: // --answer
case O_ANSWER: // --answer
opt->answer = true;
if (opt->readOnly) {
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
return EINVAL;
}
break;
case O_ACQTIM: // --acquiretimeout=9400
case O_ACQTIM: // --acquiretimeout=9400
opt->acquireTimeout = parseInt(arg, 10, 1000, 100000, result);
if (result != RESULT_OK) {
argp_error(state, "invalid acquiretimeout");
return EINVAL;
}
break;
case O_ACQRET: // --acquireretries=3
case O_ACQRET: // --acquireretries=3
opt->acquireRetries = parseInt(arg, 10, 0, 10, result);
if (result != RESULT_OK) {
argp_error(state, "invalid acquireretries");
return EINVAL;
}
break;
case O_SNDRET: // --sendretries=2
case O_SNDRET: // --sendretries=2
opt->sendRetries = parseInt(arg, 10, 0, 10, result);
if (result != RESULT_OK) {
argp_error(state, "invalid sendretries");
return EINVAL;
}
break;
case O_RCVTIM: // --receivetimeout=25000
case O_RCVTIM: // --receivetimeout=25000
opt->receiveTimeout = parseInt(arg, 10, 1000, 100000, result);
if (result != RESULT_OK) {
argp_error(state, "invalid receivetimeout");
return EINVAL;
}
break;
case O_MASCNT: // --numbermasters=0
case O_MASCNT: // --numbermasters=0
opt->masterCount = parseInt(arg, 10, 0, 25, result);
if (result != RESULT_OK) {
argp_error(state, "invalid numbermasters");
return EINVAL;
}
break;
case O_GENSYN: // --generatesyn
case O_GENSYN: // --generatesyn
opt->generateSyn = true;
if (opt->readOnly) {
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
@@ -366,37 +371,37 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
break;
// Daemon options:
case 'f': // --foreground
case 'f': // --foreground
opt->foreground = true;
break;
case O_HEXCMD: // --enablehex
case O_HEXCMD: // --enablehex
opt->enableHex = true;
break;
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid pidfile");
return EINVAL;
}
opt->pidFile = arg;
break;
case 'p': // --port=8888
case 'p': // --port=8888
opt->port = (uint16_t)parseInt(arg, 10, 1, 65535, result);
if (result != RESULT_OK) {
argp_error(state, "invalid port");
return EINVAL;
}
break;
case O_LOCAL: // --localhost
case O_LOCAL: // --localhost
opt->localOnly = true;
break;
case O_HTTPPT: // --httpport=0
case O_HTTPPT: // --httpport=0
opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, result);
if (result != RESULT_OK) {
argp_error(state, "invalid httpport");
return EINVAL;
}
break;
case O_HTMLPA: // --htmlpath=/var/ebusd/html
case O_HTMLPA: // --htmlpath=/var/ebusd/html
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid htmlpath");
return EINVAL;
@@ -405,20 +410,20 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
break;
// Log options:
case 'l': // --logfile=/var/log/ebusd.log
case 'l': // --logfile=/var/log/ebusd.log
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid logfile");
return EINVAL;
}
opt->logFile = arg;
break;
case O_LOGARE: // --logareas=all
case O_LOGARE: // --logareas=all
if (!setLogFacilities(arg)) {
argp_error(state, "invalid logareas");
return EINVAL;
}
break;
case O_LOGLEV: // --loglevel=notice
case O_LOGLEV: // --loglevel=notice
if (!setLogLevel(arg)) {
argp_error(state, "invalid loglevel");
return EINVAL;
@@ -429,14 +434,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
case O_RAW: // --lograwdata
opt->logRaw = true;
break;
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid lograwdatafile");
return EINVAL;
}
opt->logRawFile = arg;
break;
case O_RAWSIZ: // --lograwdatasize=100
case O_RAWSIZ: // --lograwdatasize=100
opt->logRawSize = (unsigned int)parseInt(arg, 10, 1, 1000000, result);
if (result != RESULT_OK) {
argp_error(state, "invalid lograwdatasize");
@@ -449,14 +454,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
case 'D': // --dump
opt->dump = true;
break;
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
argp_error(state, "invalid dumpfile");
return EINVAL;
}
opt->dumpFile = arg;
break;
case O_DMPSIZ: // --dumpsize=100
case O_DMPSIZ: // --dumpsize=100
opt->dumpSize = (unsigned int)parseInt(arg, 10, 1, 1000000, result);
if (result != RESULT_OK) {
argp_error(state, "invalid dumpsize");
@@ -514,10 +519,10 @@ void daemonize() {
// create pid file and try to lock it
pidFile = fopen(opt.pidFile, "w+");
umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750
umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750
if (pidFile != NULL) {
setbuf(pidFile, NULL); // disable buffering
setbuf(pidFile, NULL); // disable buffering
if (lockf(fileno(pidFile), F_TLOCK, 0) < 0
|| fprintf(pidFile, "%d\n", getpid()) <= 0) {
fclose(pidFile);
@@ -640,7 +645,8 @@ static result_t collectConfigFiles(const string path, const string prefix, const
if (hasTemplates) {
*hasTemplates = true;
}
} else if (prefix.length() == 0 || (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
} else if (prefix.length() == 0
|| (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
files.push_back(p);
}
}
@@ -692,7 +698,8 @@ static bool readTemplates(const string path, const string extension, bool availa
if (result == RESULT_OK) {
logInfo(lf_main, "read templates in %s", path.c_str());
} else {
logError(lf_main, "error reading templates in %s: %s, last error: %s", path.c_str(), getResultCode(result), templates->getLastError().c_str());
logError(lf_main, "error reading templates in %s: %s, last error: %s", path.c_str(), getResultCode(result),
templates->getLastError().c_str());
}
return templates;
}
@@ -706,7 +713,8 @@ static bool readTemplates(const string path, const string extension, bool availa
* @param verbose whether to verbosely log problems.
* @return the result code.
*/
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose) {
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive,
bool verbose) {
vector<string> files, dirs;
bool hasTemplates = false;
result_t result = collectConfigFiles(path, "", extension, files, &dirs, &hasTemplates);
@@ -746,7 +754,8 @@ void readMessage(Message* message) {
BusHandler* busHandler = s_mainLoop->getBusHandler();
result_t result = busHandler->readFromBus(message, "");
if (result != RESULT_OK) {
logError(lf_main, "error reading message %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result));
logError(lf_main, "error reading message %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(result));
}
}
@@ -758,23 +767,27 @@ void readMessage(Message* message) {
void executeInstructions(MessageMap* messages, bool verbose) {
result_t result = messages->resolveConditions(verbose);
if (result != RESULT_OK) {
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), messages->getLastError().c_str());
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result),
messages->getLastError().c_str());
}
ostringstream log;
result = messages->executeInstructions(log, readMessage);
if (result != RESULT_OK) {
logError(lf_main, "error executing instructions: %s, last error: %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
logError(lf_main, "error executing instructions: %s, last error: %s, %s", getResultCode(result),
messages->getLastError().c_str(), log.str().c_str());
} else if (verbose && log.tellp() > 0) {
logInfo(lf_main, log.str().c_str());
}
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(),
messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
}
result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) {
logInfo(lf_main, "loading configuration files from %s", opt.configPath);
messages->clear();
s_globalTemplates.clear();
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) {
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end();
it++) {
if (it->second != &s_globalTemplates) {
delete it->second;
}
@@ -782,41 +795,44 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
}
s_templatesByPath.clear();
result_t result = readConfigFiles(string(opt.configPath), ".csv", messages, (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose);
result_t result = readConfigFiles(string(opt.configPath), ".csv", messages,
(!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose);
if (result == RESULT_OK) {
logInfo(lf_main, "read config files");
} else {
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result), messages->getLastError().c_str());
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result),
messages->getLastError().c_str());
}
executeInstructions(messages, verbose);
return RESULT_OK;
}
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose) {
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile,
bool verbose) {
PartType partType;
if (isMaster(address)) {
address = (unsigned char)(data[0]+5); // slave address of sending master
address = (unsigned char)(data[0]+5); // slave address of sending master
partType = pt_masterData;
if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
logError(lf_main, "unable to load scan config %2.2x: master part too short", address);
return RESULT_EMPTY;
}
} else {
partType = pt_slaveData;
if (data.size() < 1+1+5+2+2) { // skip NN
if (data.size() < 1+1+5+2+2) { // skip NN
logError(lf_main, "unable to load scan config %2.2x: slave part too short", address);
return RESULT_EMPTY;
}
}
DataFieldSet* identFields = DataFieldSet::getIdentFields();
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
unsigned int sw, hw;
ostringstream out;
unsigned char offset = 0;
size_t field = 0;
result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
if (result == RESULT_ERR_NOTFOUND) {
result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
}
if (result == RESULT_OK) {
path = out.str();
@@ -828,17 +844,17 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
out.str("");
out.clear();
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
}
if (result == RESULT_OK) {
ident = out.str();
out.str("");
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
}
if (result == RESULT_OK) {
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
}
if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result));
@@ -849,14 +865,17 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), getResultCode(result));
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(),
getResultCode(result));
return result;
}
if (files.empty()) {
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(), prefix.c_str());
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(),
prefix.c_str());
return RESULT_ERR_NOTFOUND;
}
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(),
prefix.c_str(), getResultCode(result));
for (string::iterator it = ident.begin(); it != ident.end(); it++) {
if (::isspace(*it)) {
ident.erase(it--);
@@ -872,7 +891,8 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
unsigned char checkDest;
string checkIdent, useCircuit, useSuffix;
unsigned int checkSw, checkHw;
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit,
useSuffix, checkSw, checkHw)) {
continue;
}
if (address != checkDest || (checkSw != UINT_MAX && sw != checkSw) || (checkHw != UINT_MAX && hw != checkHw)) {
@@ -890,10 +910,10 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
if (remain[remain.length()-1] < '0' || remain[remain.length()-1] > '9') {
break;
}
remain.erase(remain.length()-1); // remove trailing digit
remain.erase(remain.length()-1); // remove trailing digit
}
if (!matches) {
continue; // IDENT mismatch
continue; // IDENT mismatch
}
match += remain.length();
}
@@ -905,7 +925,9 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
}
if (best.empty()) {
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d", address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw);
logError(lf_main,
"unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d",
address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw);
return RESULT_ERR_NOTFOUND;
}
@@ -916,11 +938,11 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
if (result == RESULT_OK && !files.empty()) {
for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
string name = *it;
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
if (name == "_templates.") { // skip templates
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
if (name == "_templates.") { // skip templates
continue;
}
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
name = *it;
result = messages->readFromFile(name, opt.checkConfig);
if (result == RESULT_OK) {
@@ -934,7 +956,8 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
}
result = messages->readFromFile(best, opt.checkConfig, "", ident);
if (result != RESULT_OK) {
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), ident.c_str(), sw, hw, getResultCode(result));
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(),
ident.c_str(), sw, hw, getResultCode(result));
return result;
}
logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d", best.c_str(), ident.c_str(), sw, hw);
@@ -943,7 +966,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
return RESULT_OK;
}
} // namespace ebusd
} // namespace ebusd
using namespace ebusd;
@@ -985,7 +1008,7 @@ int main(int argc, char* argv[]) {
logError(lf_main, "invalid scan message %s: %s", arg.c_str(), getResultCode(res));
continue;
}
if (master.size() < 5) { // skip QQ ZZ PB SB NN
if (master.size() < 5) { // skip QQ ZZ PB SB NN
logError(lf_main, "invalid scan message %s: master part too short", arg.c_str());
continue;
}
@@ -1020,7 +1043,7 @@ int main(int argc, char* argv[]) {
if (!opt.foreground) {
setLogFile(opt.logFile);
daemonize(); // make me daemon
daemonize(); // make me daemon
}
// trap signals that we expect to receive
+40 -36
View File
@@ -31,44 +31,46 @@ namespace ebusd {
/** A structure holding all program options. */
struct options {
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
bool noDeviceCheck; //!< skip serial eBUS device test
bool readOnly; //!< read-only access to the device
bool initialSend; //!< send an initial escape symbol after connecting device
int latency; //!< transfer latency in us [0 for USB, 10000 for IP]
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
bool noDeviceCheck; //!< skip serial eBUS device test
bool readOnly; //!< read-only access to the device
bool initialSend; //!< send an initial escape symbol after connecting device
int latency; //!< transfer latency in us [0 for USB, 10000 for IP]
const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
bool scanConfig; //!< pick configuration files matching initial scan
unsigned char initialScan; //!< the initial address to scan for scanconfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address)
int checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
int pollInterval; //!< poll interval in seconds, 0 to disable [5]
const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
bool scanConfig; //!< pick configuration files matching initial scan
/** the initial address to scan for scanconfig
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
unsigned char initialScan;
int checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
int pollInterval; //!< poll interval in seconds, 0 to disable [5]
unsigned char address; //!< own bus address [31]
bool answer; //!< answer to requests from other masters
int acquireTimeout; //!< bus acquisition timeout in us [9400]
int acquireRetries; //!< number of retries for bus acquisition [3]
int sendRetries; //!< number of retries for failed sends [2]
int receiveTimeout; //!< timeout for receiving answer from slave in us [25000]
int masterCount; //!< expected number of masters for arbitration [0]
bool generateSyn; //!< enable AUTO-SYN symbol generation
unsigned char address; //!< own bus address [31]
bool answer; //!< answer to requests from other masters
int acquireTimeout; //!< bus acquisition timeout in us [9400]
int acquireRetries; //!< number of retries for bus acquisition [3]
int sendRetries; //!< number of retries for failed sends [2]
int receiveTimeout; //!< timeout for receiving answer from slave in us [25000]
int masterCount; //!< expected number of masters for arbitration [0]
bool generateSyn; //!< enable AUTO-SYN symbol generation
bool foreground; //!< run in foreground
bool enableHex; //!< enable hex command
const char* pidFile; //!< PID file name [/var/run/ebusd.pid]
uint16_t port; //!< port to listen for command line connections [8888]
bool localOnly; //!< listen on 127.0.0.1 interface only
uint16_t httpPort; //!< optional port to listen for HTTP connections, 0 to disable [0]
const char* htmlPath; //!< path for HTML files served by the HTTP port [/var/ebusd/html]
bool foreground; //!< run in foreground
bool enableHex; //!< enable hex command
const char* pidFile; //!< PID file name [/var/run/ebusd.pid]
uint16_t port; //!< port to listen for command line connections [8888]
bool localOnly; //!< listen on 127.0.0.1 interface only
uint16_t httpPort; //!< optional port to listen for HTTP connections, 0 to disable [0]
const char* htmlPath; //!< path for HTML files served by the HTTP port [/var/ebusd/html]
const char* logFile; //!< log file name [/var/log/ebusd.log]
const char* logFile; //!< log file name [/var/log/ebusd.log]
bool logRaw; //!< raw log each received/sent byte on the bus
const char* logRawFile; //!< name of raw log file [/var/log/ebusd.log]
unsigned int logRawSize; //!< maximum size of raw log file in kB [100]
bool logRaw; //!< raw log each received/sent byte on the bus
const char* logRawFile; //!< name of raw log file [/var/log/ebusd.log]
unsigned int logRawSize; //!< maximum size of raw log file in kB [100]
bool dump; //!< binary dump received bytes
const char* dumpFile; //!< name of dump file [/tmp/ebusd_dump.bin]
unsigned int dumpSize; //!< maximum size of dump file in kB [100]
bool dump; //!< binary dump received bytes
const char* dumpFile; //!< name of dump file [/tmp/ebusd_dump.bin]
unsigned int dumpSize; //!< maximum size of dump file in kB [100]
};
/**
@@ -90,14 +92,16 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose = false, bool denyRe
/**
* Load the message definitions from a configuration file matching the scan result.
* @param messages the @a MessageMap to load the messages into.
* @param address the address of the scan participant (either master for broadcast master data or slave for read slave data).
* @param address the address of the scan participant
* (either master for broadcast master data or slave for read slave data).
* @param data the scan @a SymbolString for which to load the configuration file.
* @param relativeFile the string in which the name of the configuration file is stored on success.
* @param verbose whether to verbosely log problems.
* @return the result code.
*/
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose = false);
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile,
bool verbose = false);
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_MAIN_H_
#endif // EBUSD_MAIN_H_
+129 -102
View File
@@ -150,7 +150,7 @@ void MainLoop::run() {
bool reload = true;
time_t lastTaskRun, now, lastSignal = 0, since, sinkSince = 1;
int taskDelay = 5;
unsigned char lastScanAddress = 0; // 0 is known to be a master
unsigned char lastScanAddress = 0; // 0 is known to be a master
time(&now);
lastTaskRun = now;
ostringstream updates;
@@ -196,7 +196,7 @@ void MainLoop::run() {
Message* message = m_messages->getScanMessage(m_initialScan);
if (result == RESULT_OK && message != NULL) {
ostringstream ret;
result = message->decodeLastData(ret, 0, true); // decode data
result = message->decodeLastData(ret, 0, true); // decode data
if (result == RESULT_OK) {
logNotice(lf_main, "initial scan result: %2.2x%s", m_initialScan, ret.str().c_str());
}
@@ -277,7 +277,7 @@ void MainLoop::run() {
logDebug(lf_main, "<<< %s", result.c_str());
}
if (result.length() == 0) {
result = "\n"; // only for HTTP
result = "\n"; // only for HTTP
} else if (!netMessage->isHttp()) {
result += "\n\n";
}
@@ -331,7 +331,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
escaped = false;
}
token = previous + " " + token;
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
continue;
} else if (token[0] == '"') {
token.erase(0, 1);
@@ -364,11 +364,13 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
const char* str = args[0].c_str();
if (args.size() == 2) {
// check for "CMD -h"
if (strcasecmp(args[1].c_str(), "-h") == 0 || strcasecmp(args[1].c_str(), "-?") == 0 || strcasecmp(args[1].c_str(), "--help") == 0) {
args.clear(); // empty args is used as command help indicator
} else if (strcasecmp(args[0].c_str(), "H") == 0 || strcasecmp(args[0].c_str(), "HELP") == 0) { // check for "HELP CMD"
if (strcasecmp(args[1].c_str(), "-h") == 0 || strcasecmp(args[1].c_str(), "-?") == 0 ||
strcasecmp(args[1].c_str(), "--help") == 0) {
args.clear(); // empty args is used as command help indicator
} else if (strcasecmp(args[0].c_str(), "H") == 0 || strcasecmp(args[0].c_str(), "HELP") == 0) {
// check for "HELP CMD"
str = args[1].c_str();
args.clear(); // empty args is used as command help indicator
args.clear(); // empty args is used as command help indicator
}
}
if (strcasecmp(str, "R") == 0 || strcasecmp(str, "READ") == 0) {
@@ -431,7 +433,7 @@ result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, SymbolStr
}
msg << args[argPos++];
}
if (msg.str().size() < 4*2) { // at least ZZ, PB, SB, NN
if (msg.str().size() < 4*2) { // at least ZZ, PB, SB, NN
return RESULT_ERR_INVALID_ARG;
}
result_t ret;
@@ -485,24 +487,24 @@ string MainLoop::executeRead(vector<string> &args) {
result_t result;
maxAge = parseInt(args[argPos].c_str(), 10, 0, 24*60*60, result);
if (result != RESULT_OK) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else if (args[argPos] == "-c") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
circuit = args[argPos];
} else if (args[argPos] == "-d") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
result_t ret;
@@ -513,7 +515,7 @@ string MainLoop::executeRead(vector<string> &args) {
} else if (args[argPos] == "-p") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
result_t ret;
@@ -524,18 +526,19 @@ string MainLoop::executeRead(vector<string> &args) {
} else if (args[argPos] == "-i") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
params = args[argPos];
} else {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
argPos++;
}
if (hex && (dstAddress != SYN || !circuit.empty() || verbosity != 0 || numeric || pollPriority > 0 || args.size() < argPos + 1)) {
argPos = 0; // print usage
if (hex && (dstAddress != SYN || !circuit.empty() || verbosity != 0 || numeric || pollPriority > 0
|| args.size() < argPos + 1)) {
argPos = 0; // print usage
}
time_t now;
@@ -562,7 +565,7 @@ string MainLoop::executeRead(vector<string> &args) {
return getResultCode(RESULT_ERR_INVALID_ARG);
}
if (circuit.length() > 0 && circuit != message->getCircuit()) {
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
}
if (message->getLastUpdateTime() + maxAge > now || (message->isPassive() && message->getLastUpdateTime() != 0)) {
SymbolString& slave = message->getLastSlaveData();
@@ -583,36 +586,40 @@ string MainLoop::executeRead(vector<string> &args) {
ret = message->decodeLastData(result);
}
if (ret >= RESULT_OK) {
logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
result.str().c_str());
} else {
logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
}
return slave.getDataStr(true, false);
}
logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
return getResultCode(ret);
}
if (argPos == 0 || args.size() < argPos + 1 || args.size() > argPos + 2) {
return "usage: read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
" or: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
" Read value(s) or hex message.\n"
" -f force reading from the bus (same as '-m 0')\n"
" -m SECONDS only return cached value if age is less than SECONDS [300]\n"
" -c CIRCUIT limit to messages of CIRCUIT\n"
" -d ZZ override destination address ZZ\n"
" -p PRIO set the message poll priority (1-9)\n"
" -v increase verbosity (include names/units/comments)\n"
" -V be very verbose (include names, units, and comments)\n"
" -n use numeric value of value=name pairs\n"
" -i VALUE read additional message parameters from VALUE\n"
" NAME NAME of the message to send\n"
" FIELD only retrieve the field named FIELD\n"
" N only retrieve the N'th field named FIELD (0-based)\n"
" -h send hex read message (or answer from cache):\n"
" ZZ destination address\n"
" PB SB primary/secondary command byte\n"
" NN number of following data bytes\n"
" Dx data byte(s) to send";
return "usage: read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME "
"[FIELD[.N]]\n"
" or: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
" Read value(s) or hex message.\n"
" -f force reading from the bus (same as '-m 0')\n"
" -m SECONDS only return cached value if age is less than SECONDS [300]\n"
" -c CIRCUIT limit to messages of CIRCUIT\n"
" -d ZZ override destination address ZZ\n"
" -p PRIO set the message poll priority (1-9)\n"
" -v increase verbosity (include names/units/comments)\n"
" -V be very verbose (include names, units, and comments)\n"
" -n use numeric value of value=name pairs\n"
" -i VALUE read additional message parameters from VALUE\n"
" NAME NAME of the message to send\n"
" FIELD only retrieve the field named FIELD\n"
" N only retrieve the N'th field named FIELD (0-based)\n"
" -h send hex read message (or answer from cache):\n"
" ZZ destination address\n"
" PB SB primary/secondary command byte\n"
" NN number of following data bytes\n"
" Dx data byte(s) to send";
}
string fieldName;
char fieldIndex = -2;
@@ -641,26 +648,31 @@ string MainLoop::executeRead(vector<string> &args) {
Message* cacheMessage = m_messages->find(circuit, args[argPos], false, true);
bool hasCache = cacheMessage != NULL;
if (!hasCache || (message != NULL && message->getLastUpdateTime() > cacheMessage->getLastUpdateTime())) {
cacheMessage = message; // message is newer/better
cacheMessage = message; // message is newer/better
}
if (cacheMessage != NULL && (cacheMessage->getLastUpdateTime() + maxAge > now || (cacheMessage->isPassive() && cacheMessage->getLastUpdateTime() != 0))) {
if (cacheMessage != NULL
&& (cacheMessage->getLastUpdateTime() + maxAge > now
|| (cacheMessage->isPassive() && cacheMessage->getLastUpdateTime() != 0))) {
if (verbosity & OF_NAMES) {
result << cacheMessage->getCircuit() << " " << cacheMessage->getName() << " ";
}
result_t ret = cacheMessage->decodeLastData(result, verbosity|(numeric?OF_NUMERIC:0), false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
result_t ret = cacheMessage->decodeLastData(result, verbosity|(numeric?OF_NUMERIC:0), false,
fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
if (ret != RESULT_OK) {
if (ret < RESULT_OK) {
logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(), getResultCode(ret));
logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(),
cacheMessage->getName().c_str(), getResultCode(ret));
}
return getResultCode(ret);
}
logInfo(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(), result.str().c_str());
logInfo(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(),
result.str().c_str());
return result.str();
}
if (message == NULL && hasCache) {
return "ERR: no data stored";
} // else: read directly from bus
} // else: read directly from bus
}
if (message == NULL) {
@@ -677,9 +689,11 @@ string MainLoop::executeRead(vector<string> &args) {
if (verbosity & OF_NAMES) {
result << message->getCircuit() << " " << message->getName() << " ";
}
ret = message->decodeLastData(pt_slaveData, result, verbosity|(numeric?OF_NUMERIC:0), false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
ret = message->decodeLastData(pt_slaveData, result, verbosity|(numeric?OF_NUMERIC:0), false,
fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
if (ret < RESULT_OK) {
logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
result.str("");
result << getResultCode(ret) << " in decode";
return result.str();
@@ -702,7 +716,7 @@ string MainLoop::executeWrite(vector<string> &args) {
} else if (args[argPos] == "-d") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
result_t ret;
@@ -713,19 +727,19 @@ string MainLoop::executeWrite(vector<string> &args) {
} else if (args[argPos] == "-c") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
circuit = args[argPos];
} else {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
argPos++;
}
if (hex && (dstAddress != SYN || !circuit.empty() || args.size() < argPos + 1)) {
argPos = 0; // print usage
argPos = 0; // print usage
}
if (hex && argPos > 0) {
@@ -746,7 +760,7 @@ string MainLoop::executeWrite(vector<string> &args) {
return getResultCode(RESULT_ERR_INVALID_ARG);
}
if (circuit.length() > 0 && circuit != message->getCircuit()) {
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
}
// send message
SymbolString master(true);
@@ -762,9 +776,11 @@ string MainLoop::executeWrite(vector<string> &args) {
ret = message->decodeLastData(result);
}
if (ret >= RESULT_OK) {
logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(),
message->getName().c_str(), result.str().c_str());
} else {
logError(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(),
message->getName().c_str(), getResultCode(ret));
}
if (master[1] == BROADCAST) {
return "done broadcast";
@@ -774,7 +790,8 @@ string MainLoop::executeWrite(vector<string> &args) {
}
return slave.getDataStr(true, false);
}
logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
return getResultCode(ret);
}
@@ -800,40 +817,46 @@ string MainLoop::executeWrite(vector<string> &args) {
if (message->getDstAddress() == SYN && dstAddress == SYN) {
return getResultCode(RESULT_ERR_INVALID_ADDR);
}
result_t ret = m_busHandler->readFromBus(message, args.size() == argPos + 1 ? "" : args[argPos + 1], dstAddress); // allow missing values
// allow missing values
result_t ret = m_busHandler->readFromBus(message, args.size() == argPos + 1 ? "" : args[argPos + 1], dstAddress);
if (ret != RESULT_OK) {
logError(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
return getResultCode(ret);
}
dstAddress = message->getLastMasterData()[1];
ostringstream result;
if (dstAddress == BROADCAST || isMaster(dstAddress)) {
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
if (dstAddress == BROADCAST) {
return "done broadcast";
}
return getResultCode(RESULT_OK);
}
ret = message->decodeLastData(pt_slaveData, result); // decode data
ret = message->decodeLastData(pt_slaveData, result); // decode data
if (ret >= RESULT_OK && result.str().empty()) {
logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
return getResultCode(RESULT_OK);
}
if (ret != RESULT_OK) {
logError(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
logError(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret));
result.str("");
result << getResultCode(ret) << " in decode";
return result.str();
}
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
result.str().c_str());
return result.str();
}
string MainLoop::executeHex(vector<string> &args) {
size_t argPos = 1;
if (args.size() < argPos + 1 || (args.size() > argPos && args[argPos][0] == '-')) {
argPos = 0; // print usage
argPos = 0; // print usage
}
if (argPos > 0) {
@@ -873,7 +896,8 @@ string MainLoop::executeHex(vector<string> &args) {
string MainLoop::executeFind(vector<string> &args) {
size_t argPos = 1;
bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true, onlyWithData = false, hexFormat = false;
bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true,
onlyWithData = false, hexFormat = false;
OutputFormat verbosity = 0;
vector<size_t> columns;
string circuit;
@@ -898,13 +922,13 @@ string MainLoop::executeFind(vector<string> &args) {
} else if (args[argPos] == "-f") {
configFormat = true;
if (hexFormat) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else if (args[argPos] == "-F") {
argPos++;
if (hexFormat || (argPos >= args.size())) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
istringstream input(args[argPos]);
@@ -918,13 +942,13 @@ string MainLoop::executeFind(vector<string> &args) {
}
}
if (idx == columnCount) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
columns.push_back(columnIds[idx]);
}
if (columns.empty()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else if (args[argPos] == "-e") {
@@ -952,13 +976,13 @@ string MainLoop::executeFind(vector<string> &args) {
} else if (args[argPos] == "-h") {
hexFormat = true;
if (configFormat) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else if (args[argPos] == "-i") {
argPos++;
if (argPos >= args.size() || !id.empty()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
result_t result = Message::parseId(args[argPos], id);
@@ -966,18 +990,18 @@ string MainLoop::executeFind(vector<string> &args) {
return getResultCode(result);
}
if (id.empty()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
} else if (args[argPos] == "-c") {
argPos++;
if (argPos >= args.size()) {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
circuit = args[argPos];
} else {
argPos = 0; // print usage
argPos = 0; // print usage
break;
}
argPos++;
@@ -1171,10 +1195,11 @@ string MainLoop::executeScan(vector<string> &args) {
if (result != RESULT_OK) {
return getResultCode(result);
}
Message* message = m_messages->getScanMessage(dstAddress); // never NULL due to scanAndWait() == RESULT_OK && dstAddress != BROADCAST
Message* message = m_messages->getScanMessage(dstAddress);
// never NULL due to scanAndWait() == RESULT_OK && dstAddress != BROADCAST
ostringstream ret;
ret << hex << setw(2) << setfill('0') << static_cast<unsigned>(dstAddress);
result = message->decodeLastData(ret, 0, true); // decode data
result = message->decodeLastData(ret, 0, true); // decode data
if (result != RESULT_OK) {
return getResultCode(result);
}
@@ -1291,27 +1316,29 @@ string MainLoop::executeQuit(vector<string> &args, bool& connected) {
string MainLoop::executeHelp() {
return "usage:\n"
" read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
" Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
" write|w Write value(s): write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n"
" Write hex message: write [-c CIRCUIT] -h ZZPBSBNNDx\n"
" hex Send hex data: hex ZZPBSBNNDx\n"
" find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e] [-c CIRCUIT] [NAME]\n"
" listen|l Listen for updates: listen [stop]\n"
" state|s Report bus state\n"
" info|i Report information about the daemon, the configuration, and seen devices.\n"
" grab|g Grab messages: grab [stop]\n"
" Report the messages: grab result [all]\n"
" scan Scan slaves: scan [full|ZZ]\n"
" Report scan result: scan result\n"
" log Set log area/level: log [AREA[,AREA]*] [LEVEL]\n"
" AREA: main|network|bus|update|all\n"
" LEVEL: error|notice|info|debug\n"
" raw Toggle logging of each byte\n"
" dump Toggle binary dump of received bytes\n"
" reload Reload CSV config files\n"
" quit|q Close connection\n"
" help|h Print help help [COMMAND]";
" read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n]"
" [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
" Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
" write|w Write value(s): write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n"
" Write hex message: write [-c CIRCUIT] -h ZZPBSBNNDx\n"
" hex Send hex data: hex ZZPBSBNNDx\n"
" find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]"
" [-c CIRCUIT] [NAME]\n"
" listen|l Listen for updates: listen [stop]\n"
" state|s Report bus state\n"
" info|i Report information about the daemon, the configuration, and seen devices.\n"
" grab|g Grab messages: grab [stop]\n"
" Report the messages: grab result [all]\n"
" scan Scan slaves: scan [full|ZZ]\n"
" Report scan result: scan result\n"
" log Set log area/level: log [AREA[,AREA]*] [LEVEL]\n"
" AREA: main|network|bus|update|all\n"
" LEVEL: error|notice|info|debug\n"
" raw Toggle logging of each byte\n"
" dump Toggle binary dump of received bytes\n"
" reload Reload CSV config files\n"
" quit|q Close connection\n"
" help|h Print help help [COMMAND]";
}
string MainLoop::executeGet(vector<string> &args, bool& connected) {
@@ -1391,7 +1418,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
if (lastup == 0 && required) {
// read directly from bus
if (message->isPassive()) {
continue; // not possible to actively read this message
continue; // not possible to actively read this message
}
if (m_busHandler->readFromBus(message, "") != RESULT_OK) {
continue;
@@ -1430,7 +1457,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
} else {
string prefix = result.str().substr(0, pos);
result.str("");
result.clear(); // remove written fields
result.clear(); // remove written fields
result << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\"";
}
}
@@ -1542,4 +1569,4 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
return result.str();
}
} // namespace ebusd
} // namespace ebusd
+7 -6
View File
@@ -36,7 +36,7 @@ namespace ebusd {
* The main loop handling requests from connected clients.
*/
class MainLoop : public Thread, DeviceListener {
public:
public:
/**
* Construct the main loop and create network and bus handling components.
* @param opt the program options.
@@ -66,12 +66,12 @@ class MainLoop : public Thread, DeviceListener {
virtual void notifyDeviceData(const unsigned char byte, bool received);
protected:
protected:
// @copydoc
virtual void run();
private:
private:
/**
* Decode and execute client message.
* @param data the data string to decode (may be empty).
@@ -230,7 +230,8 @@ class MainLoop : public Thread, DeviceListener {
/** whether to pick configuration files matching initial scan. */
const bool m_scanConfig;
/** the initial address to scan for @a m_scanConfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
/** the initial address to scan for @a m_scanConfig
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
const unsigned char m_initialScan;
/** whether to enable the hex command. */
@@ -252,6 +253,6 @@ class MainLoop : public Thread, DeviceListener {
list<DataHandler*> m_dataHandlers;
};
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_MAINLOOP_H_
#endif // EBUSD_MAINLOOP_H_
+19 -16
View File
@@ -37,9 +37,9 @@ static const struct argp_option g_mqtt_argp_options[] = {
{NULL, 0, NULL, 0, NULL, 0 },
};
static const char* g_host = "localhost"; //!< MQTT Host to use [localhost]
static uint16_t g_port = 0; //!< optional port of MQTT broker, 0 to disable [0]
static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without wildcards) [ebusd]
static const char* g_host = "localhost"; //!< MQTT Host to use [localhost]
static uint16_t g_port = 0; //!< optional port of MQTT broker, 0 to disable [0]
static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without wildcards) [ebusd]
/**
@@ -52,7 +52,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
result_t result = RESULT_OK;
switch (key) {
case 1: // --mqtthost=localhost
case 1: // --mqtthost=localhost
if (arg == NULL || arg[0] == 0) {
argp_error(state, "invalid mqtthost");
return EINVAL;
@@ -60,7 +60,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
g_host = arg;
break;
case 2: // --mqttport=1883
case 2: // --mqttport=1883
g_port = (uint16_t)parseInt(arg, 10, 1, 65535, result);
if (result != RESULT_OK) {
argp_error(state, "invalid mqttport");
@@ -68,7 +68,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
}
break;
case 3: // --mqtttopic=ebusd
case 3: // --mqtttopic=ebusd
if (arg == NULL || arg[0] == 0 || arg[0] == '/' || arg[strlen(arg)-1] == '/') {
argp_error(state, "invalid mqtttopic");
return EINVAL;
@@ -136,7 +136,7 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
}
for (vector<size_t>::iterator it=cols.begin(); it != cols.end(); it++) {
if (*it == col) {
return false; // duplicate column
return false; // duplicate column
}
}
strs.push_back(topic.substr(lastpos, pos-lastpos));
@@ -178,12 +178,12 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
m_topicStrs[0] = str+"/";
}
}
m_topicCols.push_back(COLUMN_CIRCUIT); // circuit
m_topicCols.push_back(COLUMN_CIRCUIT); // circuit
m_topicStrs.push_back("/");
m_topicCols.push_back(COLUMN_NAME); // name
m_topicCols.push_back(COLUMN_NAME); // name
} else {
for (size_t i = 0; i < m_topicCols.size(); i++) {
if (m_topicCols[i] == COLUMN_FIELDS) { // fields
if (m_topicCols[i] == COLUMN_FIELDS) { // fields
m_publishByField = true;
break;
}
@@ -274,7 +274,7 @@ void MqttHandler::notifyTopic(string topic, string data) {
if (!isWrite && direction != "get") {
return;
}
suffix = suffix.substr(3); // security level
suffix = suffix.substr(3); // security level
logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str());
string remain = topic.substr(0, pos);
size_t last = 0;
@@ -314,7 +314,7 @@ void MqttHandler::notifyTopic(string topic, string data) {
name = field;
break;
case COLUMN_FIELDS:
//field = field; // TODO add support for writing a single field
//field = field; // TODO add support for writing a single field
break;
default:
return;
@@ -339,7 +339,8 @@ void MqttHandler::notifyTopic(string topic, string data) {
if (!message->isPassive()) {
result_t result = m_busHandler->readFromBus(message, data);
if (result != RESULT_OK) {
logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), getResultCode(result));
logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(),
getResultCode(result));
return;
}
logOtherNotice("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), data.c_str());
@@ -436,7 +437,8 @@ string MqttHandler::getTopic(Message* message, signed char fieldIndex) {
void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
result_t result = message->decodeLastData(updates);
if (result != RESULT_OK) {
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result));
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(result));
return;
}
if (m_publishByField) {
@@ -455,7 +457,8 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
void MqttHandler::publishTopic(string topic, string data, bool retain) {
logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str());
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain);
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(),
reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain);
}
} // namespace ebusd
} // namespace ebusd
+5 -5
View File
@@ -55,7 +55,7 @@ DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages);
* The main class supporting MQTT data handling.
*/
class MqttHandler : public DataSink, public DataSource, public Thread {
public:
public:
/**
* Constructor.
* @param busHandler the @a BusHandler instance.
@@ -79,12 +79,12 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
void notifyTopic(string topic, string data);
protected:
protected:
// @copydoc
virtual void run();
private:
private:
/**
* Called regularly to handle MQTT traffic.
*/
@@ -132,6 +132,6 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
struct mosquitto* m_mosquitto;
};
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_MQTTHANDLER_H_
#endif // EBUSD_MQTTHANDLER_H_
+5 -3
View File
@@ -86,7 +86,8 @@ void Connection::run() {
if (ret != 0) {
#ifdef HAVE_PPOLL
// new data from notify
if (ret < 0 || (fds[0].revents & (POLLIN | POLLERR | POLLHUP | POLLRDHUP)) || (fds[1].revents & (POLLERR | POLLHUP))) {
if (ret < 0 || (fds[0].revents & (POLLIN | POLLERR | POLLHUP | POLLRDHUP))
|| (fds[1].revents & (POLLERR | POLLHUP))) {
break;
}
// new data from socket
@@ -282,7 +283,8 @@ void Network::run() {
}
connection->start("connection");
m_connections.push_back(connection);
logInfo(lf_network, "[%05d] %s connection opened %s", connection->getID(), isHttp ? "HTTP" : "client", socket->getIP().c_str());
logInfo(lf_network, "[%05d] %s connection opened %s", connection->getID(), isHttp ? "HTTP" : "client",
socket->getIP().c_str());
}
}
}
@@ -299,4 +301,4 @@ void Network::cleanConnections() {
}
}
} // namespace ebusd
} // namespace ebusd
+13 -13
View File
@@ -39,7 +39,7 @@ class Connection;
* Class for data/message transfer between @a Connection and @a MainLoop.
*/
class NetMessage {
public:
public:
/**
* Constructor.
* @param isHttp whether this is a HTTP message.
@@ -59,7 +59,7 @@ class NetMessage {
}
private:
private:
/**
* Hidden copy constructor.
* @param src the object to copy from.
@@ -67,7 +67,7 @@ class NetMessage {
NetMessage(const NetMessage& src);
public:
public:
/**
* Add request data received from the client.
* @param request the request data from the client.
@@ -82,11 +82,11 @@ class NetMessage {
if (pos != string::npos) {
if (m_isHttp) {
pos = m_request.find("\n");
m_request.resize(pos); // reduce to first line
m_request.resize(pos); // reduce to first line
// typical first line: GET /ehp/outsidetemp HTTP/1.1
pos = m_request.rfind(" HTTP/");
if (pos != string::npos) {
m_request.resize(pos); // remove "HTTP/x.x" suffix
m_request.resize(pos); // remove "HTTP/x.x" suffix
}
pos = 0;
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
@@ -98,7 +98,7 @@ class NetMessage {
m_request.erase(pos+1, 2);
}
} else if (pos+1 == m_request.length()) {
m_request.resize(pos); // reduce to complete lines
m_request.resize(pos); // reduce to complete lines
}
return true;
}
@@ -168,7 +168,7 @@ class NetMessage {
bool isDisconnect() { return m_disconnect; }
private:
private:
/** whether this is a HTTP message. */
const bool m_isHttp;
@@ -201,7 +201,7 @@ class NetMessage {
* class connection which handle client and baseloop communication.
*/
class Connection : public Thread {
public:
public:
/**
* Constructor.
* @param socket the @a TCPSocket for communication.
@@ -231,7 +231,7 @@ class Connection : public Thread {
int getID() { return m_id; }
private:
private:
/** whether this is a HTTP connection. */
const bool m_isHttp;
@@ -255,7 +255,7 @@ class Connection : public Thread {
* class network which listening on tcp socket for incoming connections.
*/
class Network : public Thread {
public:
public:
/**
* create a network instance and listening for incoming connections.
* @param local true to accept connections only for local host.
@@ -281,7 +281,7 @@ class Network : public Thread {
void stop() const { m_notify.notify(); usleep(100000); }
private:
private:
/** the list of active @a Connection instances. */
list<Connection*> m_connections;
@@ -306,6 +306,6 @@ class Network : public Thread {
void cleanConnections();
};
} // namespace ebusd
} // namespace ebusd
#endif // EBUSD_NETWORK_H_
#endif // EBUSD_NETWORK_H_
+1 -1
View File
@@ -26,4 +26,4 @@ bool libebus_contrib_register() {
return true;
}
} // namespace ebusd
} // namespace ebusd
+2 -2
View File
@@ -32,6 +32,6 @@ namespace ebusd {
*/
bool libebus_contrib_register();
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_CONTRIB_CONTRIB_H_
#endif // LIB_EBUS_CONTRIB_CONTRIB_H_
+17 -17
View File
@@ -73,11 +73,11 @@ result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
}
int grp = 0, num = 0;
if (isMaster) {
grp = (value & 0x1f); // grp in bits 0...5
num = ((value >> 8) & 0x7f); // num in bits 8...13
grp = (value & 0x1f); // grp in bits 0...5
num = ((value >> 8) & 0x7f); // num in bits 8...13
} else {
grp = ((value >> 7) & 0x1f); // grp in bits 7...11
num = (value & 0x7f); // num in bits 0...6
grp = ((value >> 7) & 0x1f); // grp in bits 7...11
num = (value & 0x7f); // num in bits 0...6
}
if (outputFormat & OF_JSON) {
output << '"';
@@ -86,7 +86,7 @@ result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
if (outputFormat & OF_JSON) {
output << '"';
}
output << setfill(' ') << setw(0); // reset
output << setfill(' ') << setw(0); // reset
return RESULT_OK;
}
@@ -99,45 +99,45 @@ result_t TemParamDataType::writeSymbols(istringstream& input,
const char* str = input.str().c_str();
if (strcasecmp(str, NULL_VALUE) == 0) {
value = m_replacement; // replacement value
value = m_replacement; // replacement value
} else {
if (input.eof() || !getline(input, token, '-')) {
return RESULT_ERR_EOF; // incomplete
return RESULT_ERR_EOF; // incomplete
}
str = token.c_str();
if (str == NULL || *str == 0) {
return RESULT_ERR_EOF; // input too short
return RESULT_ERR_EOF; // input too short
}
char* strEnd = NULL;
grp = (unsigned int)strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (input.eof() || !getline(input, token, '-')) {
return RESULT_ERR_EOF; // incomplete
return RESULT_ERR_EOF; // incomplete
}
str = token.c_str();
if (str == NULL || *str == 0) {
return RESULT_ERR_EOF; // input too short
return RESULT_ERR_EOF; // input too short
}
strEnd = NULL;
num = (unsigned int)strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (grp < 0 || grp > 0x1f || num < 0 || num > 0x7f) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
if (isMaster) {
value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13
value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13
} else {
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
}
}
if (value < getMinValue() || value > getMaxValue()) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
return writeRawValue(value, offset, length, output, usedLength);
}
} // namespace ebusd
} // namespace ebusd
+3 -3
View File
@@ -41,7 +41,7 @@ namespace ebusd {
* data.
*/
class TemParamDataType : public NumberDataType {
public:
public:
/**
* Constructs a new instance.
* @param id the type identifier.
@@ -68,6 +68,6 @@ class TemParamDataType : public NumberDataType {
*/
void contrib_tem_register();
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_CONTRIB_TEM_H_
#endif // LIB_EBUS_CONTRIB_TEM_H_
+8 -4
View File
@@ -108,7 +108,8 @@ int main() {
fields = NULL;
}
vector<string>::iterator it = entries.begin();
result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1] == BROADCAST || isMaster(mstr[1])));
result = DataField::create(it, entries.end(), templates, fields, isSet, false,
(mstr[1] == BROADCAST || isMaster(mstr[1])));
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl;
error = true;
@@ -132,13 +133,15 @@ int main() {
SymbolString writeMstr(false);
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
if (result != RESULT_OK) {
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) << endl;
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result)
<< endl;
error = true;
}
SymbolString writeSstr(false);
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
if (result != RESULT_OK) {
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) << endl;
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result)
<< endl;
error = true;
}
result = fields->read(pt_masterData, mstr, 0, output, 0, -1, false);
@@ -183,7 +186,8 @@ int main() {
error = true;
} else {
bool match = mstr == writeMstr && sstr == writeSstr;
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " + sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
}
delete fields;
fields = NULL;
+72 -64
View File
@@ -60,7 +60,7 @@ result_t DataField::create(vector<string>::iterator& it,
// template: name,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
// std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
const string name = *it++; // name
const string name = *it++; // name
if (it == end) {
if (!name.empty()) {
result = RESULT_ERR_MISSING_TYPE;
@@ -71,7 +71,7 @@ result_t DataField::create(vector<string>::iterator& it,
if (isTemplate) {
partType = pt_any;
} else {
const char* partStr = (*it++).c_str(); // part
const char* partStr = (*it++).c_str(); // part
hasPartStr = partStr[0] != 0;
if (it == end) {
if (!name.empty() || hasPartStr) {
@@ -81,10 +81,10 @@ result_t DataField::create(vector<string>::iterator& it,
}
if (isBroadcastOrMasterDestination
|| (isWriteMessage && !hasPartStr)
|| strcasecmp(partStr, "M") == 0) { // master data
|| strcasecmp(partStr, "M") == 0) { // master data
partType = pt_masterData;
} else if ((!isWriteMessage && !hasPartStr)
|| strcasecmp(partStr, "S") == 0) { // slave data
|| strcasecmp(partStr, "S") == 0) { // slave data
partType = pt_slaveData;
} else {
result = RESULT_ERR_INVALID_PART;
@@ -97,7 +97,7 @@ result_t DataField::create(vector<string>::iterator& it,
firstComment = comment;
}
const string typeStr = *it++; // basetype[:len]|template[:name]
const string typeStr = *it++; // basetype[:len]|template[:name]
vector<string>::iterator typePos = it;
if (typeStr.empty()) {
if (!name.empty() || hasPartStr) {
@@ -110,13 +110,13 @@ result_t DataField::create(vector<string>::iterator& it,
string constantValue;
bool verifyValue = false;
if (it != end) {
const string divisorStr = *it++; // [divisor|values]
const string divisorStr = *it++; // [divisor|values]
if (!divisorStr.empty()) {
size_t equalPos = divisorStr.find('=');
if (equalPos == string::npos) {
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
} else if (equalPos == 0 && divisorStr.length() > 1) {
verifyValue = divisorStr[1] == '='; // == forced verification of constant value
verifyValue = divisorStr[1] == '='; // == forced verification of constant value
if (verifyValue && divisorStr.length() == 1) {
result = RESULT_ERR_INVALID_LIST;
break;
@@ -131,9 +131,9 @@ result_t DataField::create(vector<string>::iterator& it,
unsigned long id;
if (strncasecmp(str, "0x", 2) == 0) {
str += 2;
id = strtoul(str, &strEnd, 16); // hexadecimal
id = strtoul(str, &strEnd, 16); // hexadecimal
} else {
id = strtoul(str, &strEnd, 10); // decimal
id = strtoul(str, &strEnd, 10); // decimal
}
if (strEnd == NULL || strEnd == str || id > MAX_VALUE) {
result = RESULT_ERR_INVALID_LIST;
@@ -159,7 +159,7 @@ result_t DataField::create(vector<string>::iterator& it,
if (it == end) {
unit = "";
} else {
const string str = *it++; // [unit]
const string str = *it++; // [unit]
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
unit = "";
} else {
@@ -170,7 +170,7 @@ result_t DataField::create(vector<string>::iterator& it,
if (it == end) {
comment = "";
} else {
const string str = *it++; // [comment]
const string str = *it++; // [comment]
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
comment = "";
} else {
@@ -187,11 +187,11 @@ result_t DataField::create(vector<string>::iterator& it,
if (templ == NULL && pos != string::npos) {
templ = templates->get(token.substr(0, pos));
}
if (templ == NULL) { // basetype[:len]
if (templ == NULL) { // basetype[:len]
unsigned char length;
string typeName;
if (pos == string::npos) {
length = 0; // no length specified
length = 0; // no length specified
typeName = token;
} else {
if (pos+2 == token.length() && token[pos+1] == '*') {
@@ -206,29 +206,31 @@ result_t DataField::create(vector<string>::iterator& it,
}
transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper);
SingleDataField* add = NULL;
result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, constantValue, verifyValue, add);
result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "",
firstType ? unit : "", partType, divisor, values, constantValue, verifyValue, add);
if (add != NULL) {
fields.push_back(add);
} else {
it = typePos; // back to type
it = typePos; // back to type
if (result == RESULT_OK) {
result = RESULT_ERR_NOTFOUND; // type not found
result = RESULT_ERR_NOTFOUND; // type not found
}
}
} else if (!constantValue.empty()) {
it = typePos; // back to type
result = RESULT_ERR_INVALID_ARG; // invalid value list
} else { // template[:name]
it = typePos; // back to type
result = RESULT_ERR_INVALID_ARG; // invalid value list
} else { // template[:name]
string fieldName;
bool lastType = stream.eof();
if (pos != string::npos) { // replacement name specified
if (pos != string::npos) { // replacement name specified
fieldName = token.substr(pos+1);
} else {
fieldName = (firstType && lastType) ? name : "";
}
result = templ->derive(fieldName, firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields);
result = templ->derive(fieldName, firstType ? comment : "", firstType ? unit : "", partType, divisor, values,
fields);
if (result != RESULT_OK) {
it = typePos; // back to type
it = typePos; // back to type
}
}
firstType = false;
@@ -236,7 +238,7 @@ result_t DataField::create(vector<string>::iterator& it,
}
if (result != RESULT_OK) {
while (!fields.empty()) { // cleanup already created fields
while (!fields.empty()) { // cleanup already created fields
delete fields.back();
fields.pop_back();
}
@@ -276,19 +278,19 @@ result_t SingleDataField::create(const string id, const unsigned char length,
// check length
if ((bitCount % 8) != 0) {
if (length == 0) {
bitCount = 1; // default bit count: 1 bit
bitCount = 1; // default bit count: 1 bit
} else if (length <= bitCount) {
bitCount = length;
} else {
return RESULT_ERR_OUT_OF_RANGE; // invalid length
return RESULT_ERR_OUT_OF_RANGE; // invalid length
}
byteCount = (unsigned char)((bitCount + 7) / 8);
} else if (length == 0) {
byteCount = 1; //default byte count: 1 byte
byteCount = 1; //default byte count: 1 byte
} else if (length <= byteCount || length == REMAIN_LEN) {
byteCount = length;
} else {
return RESULT_ERR_OUT_OF_RANGE; // invalid length
return RESULT_ERR_OUT_OF_RANGE; // invalid length
}
}
if (!constantValue.empty()) {
@@ -316,14 +318,14 @@ result_t SingleDataField::create(const string id, const unsigned char length,
return RESULT_OK;
}
if (divisor != 0 || !values.empty()) {
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
}
returnField = new SingleDataField(name, comment, unit, dataType, partType, byteCount);
return RESULT_OK;
}
void SingleDataField::dump(ostream& output) {
output << setw(0) << dec; // initialize formatting
output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false);
output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) {
@@ -346,10 +348,10 @@ result_t SingleDataField::read(const PartType partType,
}
switch (m_partType) {
case pt_masterData:
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
offset++; // skip NN
offset++; // skip NN
break;
default:
return RESULT_ERR_INVALID_PART;
@@ -373,10 +375,10 @@ result_t SingleDataField::read(const PartType partType,
}
switch (m_partType) {
case pt_masterData:
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
offset++; // skip NN
offset++; // skip NN
break;
default:
return RESULT_ERR_INVALID_PART;
@@ -394,7 +396,8 @@ result_t SingleDataField::read(const PartType partType,
output << ",";
}
if (outputIndex >= 0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \""
<< m_name << "\"" << ", \"value\": ";
} else {
output << "\n \"" << m_name << "\": {\"value\": ";
}
@@ -439,10 +442,10 @@ result_t SingleDataField::write(istringstream& input,
}
switch (m_partType) {
case pt_masterData:
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
offset++; // skip NN
offset++; // skip NN
break;
default:
return RESULT_ERR_INVALID_PART;
@@ -471,11 +474,11 @@ result_t SingleDataField::derive(string name, string comment,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) {
if (m_partType != pt_any && partType == pt_any) {
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
}
bool numeric = m_dataType->isNumeric();
if (!numeric && (divisor != 0 || !values.empty())) {
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field
}
if (name.empty()) {
name = m_name;
@@ -498,7 +501,8 @@ result_t SingleDataField::derive(string name, string comment,
if (values.empty()) {
fields.push_back(new SingleDataField(name, comment, unit, dataType, partType, m_length));
} else if (numeric) {
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(dataType), partType, m_length, values));
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(dataType),
partType, m_length, values));
} else {
return RESULT_ERR_INVALID_ARG;
}
@@ -537,7 +541,7 @@ result_t ValueListDataField::derive(string name, string comment,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) {
if (m_partType != pt_any && partType == pt_any) {
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
}
if (name.empty()) {
name = m_name;
@@ -549,7 +553,7 @@ result_t ValueListDataField::derive(string name, string comment,
unit = m_unit;
}
if (divisor != 0 && divisor != 1) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
}
if (!m_dataType->isNumeric()) {
return RESULT_ERR_INVALID_ARG;
@@ -557,17 +561,18 @@ result_t ValueListDataField::derive(string name, string comment,
if (!values.empty()) {
NumberDataType* num = reinterpret_cast<NumberDataType*>(m_dataType);
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
}
} else {
values = m_values;
}
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(m_dataType), partType, m_length, values));
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(m_dataType),
partType, m_length, values));
return RESULT_OK;
}
void ValueListDataField::dump(ostream& output) {
output << setw(0) << dec; // initialize formatting
output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false);
output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) {
@@ -576,14 +581,14 @@ void ValueListDataField::dump(ostream& output) {
output << "s";
}
output << FIELD_SEPARATOR;
if (!m_dataType->dump(output, m_length)) { // no divisor appended
if (!m_dataType->dump(output, m_length)) { // no divisor appended
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
if (it != m_values.begin()) {
output << VALUE_SEPARATOR;
}
output << static_cast<unsigned>(it->first) << "=" << it->second;
}
} // else: impossible since divisor is not allowed for ValueListDataField
} // else: impossible since divisor is not allowed for ValueListDataField
dumpString(output, m_unit);
dumpString(output, m_comment);
}
@@ -624,7 +629,8 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
SymbolString& output, const bool isMaster, unsigned char* usedLength) {
NumberDataType* numType = reinterpret_cast<NumberDataType*>(m_dataType);
if (isIgnored()) {
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
// replacement value
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength);
}
const char* str = input.str().c_str();
@@ -634,18 +640,19 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
}
}
if (strcasecmp(str, NULL_VALUE) == 0) {
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
// replacement value
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength);
}
char* strEnd = NULL; // fall back to raw value in input
char* strEnd = NULL; // fall back to raw value in input
unsigned int value;
value = (unsigned int)strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (m_values.find(value) != m_values.end()) {
return numType->writeRawValue(value, offset, m_length, output, usedLength);
}
return RESULT_ERR_NOTFOUND; // value assignment not found
return RESULT_ERR_NOTFOUND; // value assignment not found
}
@@ -658,7 +665,7 @@ result_t ConstantDataField::derive(string name, string comment,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) {
if (m_partType != pt_any && partType == pt_any) {
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
}
if (name.empty()) {
name = m_name;
@@ -670,17 +677,17 @@ result_t ConstantDataField::derive(string name, string comment,
unit = m_unit;
}
if (divisor != 0) {
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
}
if (!values.empty()) {
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
}
fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify));
return RESULT_OK;
}
void ConstantDataField::dump(ostream& output) {
output << setw(0) << dec; // initialize formatting
output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false);
output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) {
@@ -689,9 +696,9 @@ void ConstantDataField::dump(ostream& output) {
output << "s";
}
output << FIELD_SEPARATOR;
if (!m_dataType->dump(output, m_length)) { // no divisor appended
if (!m_dataType->dump(output, m_length)) { // no divisor appended
output << (m_verify?"==":"=") << m_value;
} // else: impossible since divisor is not allowed for ConstantDataField
} // else: impossible since divisor is not allowed for ConstantDataField
dumpString(output, m_unit);
dumpString(output, m_comment);
}
@@ -825,7 +832,7 @@ result_t DataFieldSet::derive(string name, string comment,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) {
if (!values.empty()) {
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
}
bool first = true;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
@@ -919,7 +926,8 @@ result_t DataFieldSet::read(const PartType partType,
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
offset--;
}
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex);
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator,
fieldName, fieldIndex);
if (result < RESULT_OK) {
return result;
}
@@ -1021,7 +1029,7 @@ result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
map<string, DataField*>::iterator it = m_fieldsByName.find(name);
if (it != m_fieldsByName.end()) {
if (!replace) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
delete it->second;
it->second = field;
@@ -1033,8 +1041,8 @@ result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
}
result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo) {
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string& filename, unsigned int lineNo) {
vector<string>::iterator restart = begin;
DataField* field = NULL;
string name;
@@ -1051,7 +1059,7 @@ result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const
}
result = add(field, name, true);
if (result == RESULT_ERR_DUPLICATE_NAME) {
begin = restart+1; // mark name as invalid
begin = restart+1; // mark name as invalid
}
if (result != RESULT_OK) {
delete field;
@@ -1067,4 +1075,4 @@ DataField* DataFieldTemplates::get(const string name) {
return ref->second;
}
} // namespace ebusd
} // namespace ebusd
+30 -20
View File
@@ -55,7 +55,7 @@ class SingleDataField;
* Base class for all kinds of data fields.
*/
class DataField {
public:
public:
/**
* Constructs a new instance.
* @param name the field name.
@@ -205,7 +205,7 @@ class DataField {
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL) = 0;
protected:
protected:
/** the field name. */
const string m_name;
@@ -218,7 +218,7 @@ class DataField {
* A single @a DataField holding a value.
*/
class SingleDataField : public DataField {
public:
public:
/**
* Constructs a new instance.
* @param name the field name.
@@ -322,7 +322,7 @@ class SingleDataField : public DataField {
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
protected:
protected:
/**
* Internal method for reading the field from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from.
@@ -367,7 +367,7 @@ class SingleDataField : public DataField {
* A numeric data field with a list of value=text assignments and a string representation.
*/
class ValueListDataField : public SingleDataField {
public:
public:
/**
* Constructs a new instance.
* @param name the field name.
@@ -402,7 +402,7 @@ class ValueListDataField : public SingleDataField {
virtual void dump(ostream& output);
protected:
protected:
// @copydoc
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset,
@@ -414,7 +414,7 @@ class ValueListDataField : public SingleDataField {
SymbolString& output, const bool isMaster, unsigned char* usedLength);
private:
private:
/** the value=text assignments. */
map<unsigned int, string> m_values;
};
@@ -424,7 +424,7 @@ class ValueListDataField : public SingleDataField {
* A data field with a constant value.
*/
class ConstantDataField : public SingleDataField {
public:
public:
/**
* Constructs a new instance.
* @param name the field name.
@@ -460,7 +460,7 @@ class ConstantDataField : public SingleDataField {
virtual void dump(ostream& output);
protected:
protected:
// @copydoc
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset,
@@ -472,7 +472,7 @@ class ConstantDataField : public SingleDataField {
SymbolString& output, const bool isMaster, unsigned char* usedLength);
private:
private:
/** the constant value. */
const string m_value;
@@ -485,7 +485,7 @@ class ConstantDataField : public SingleDataField {
* A set of @a DataField instances.
*/
class DataFieldSet : public DataField {
public:
public:
/**
* Get the @a DataFieldSet for parsing the identification message (service 0x07 0x04).
* @return the @a DataFieldSet for parsing the identification message. This is:<ul>
@@ -550,14 +550,24 @@ class DataFieldSet : public DataField {
* @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL.
*/
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
SingleDataField* operator[](const size_t index) {
if (index >= m_fields.size()) {
return NULL;
}
return m_fields[index];
}
/**
* Returns the @a SingleDataField at the specified index.
* @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL.
*/
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
const SingleDataField* operator[](const size_t index) const {
if (index >= m_fields.size()) {
return NULL;
}
return m_fields[index];
}
/**
* Returns the number of @a SingleDataFields instances in this set.
@@ -588,7 +598,7 @@ class DataFieldSet : public DataField {
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
private:
private:
/** the @a DataFieldSet containing the ident message @a SingleDataField instances, or NULL. */
static DataFieldSet* s_identFields;
@@ -604,7 +614,7 @@ class DataFieldSet : public DataField {
* A map of template @a DataField instances.
*/
class DataFieldTemplates : public FileReader {
public:
public:
/**
* Constructs a new instance.
*/
@@ -640,8 +650,8 @@ class DataFieldTemplates : public FileReader {
// @copydoc
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo);
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string& filename, unsigned int lineNo);
/**
* Gets the template @a DataField instance with the specified name.
@@ -652,11 +662,11 @@ class DataFieldTemplates : public FileReader {
DataField* get(string name);
private:
private:
/** the known template @a DataField instances by name. */
map<string, DataField*> m_fieldsByName;
};
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_DATA_H_
#endif // LIB_EBUS_DATA_H_
+198 -153
View File
@@ -40,18 +40,19 @@ using std::setfill;
using std::setprecision;
using std::setw;
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length) {
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
result_t& result, unsigned int* length) {
char* strEnd = NULL;
unsigned long ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL) {
@@ -61,18 +62,19 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
return (unsigned int)ret;
}
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length) {
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
unsigned int* length) {
char* strEnd = NULL;
long ret = strtol(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL) {
@@ -82,11 +84,14 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
return static_cast<int>(ret);
}
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
if (pos > begin) {
pos--;
}
out << "Error reading \"" << filename << "\" line " << setw(0) << dec << static_cast<unsigned>(lineNo) << " field " << static_cast<unsigned>(1+pos.base()-begin.base()) << " value \"" << *pos << "\": " << getResultCode(result) << endl;
out << "Error reading \"" << filename << "\" line " << setw(0) << dec << static_cast<unsigned>(lineNo)
<< " field " << static_cast<unsigned>(1+pos.base()-begin.base()) << " value \"" << *pos << "\": "
<< getResultCode(result) << endl;
out << "Erroneous item is here:" << endl;
bool first = true;
int cnt = 0;
@@ -161,7 +166,7 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
} else if (baseOffset + count > input.size()) {
return RESULT_ERR_INVALID_POS;
}
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -187,7 +192,7 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
ch = '?';
} else if (outputFormat & OF_JSON) {
if (ch == '"' || ch == '\\') {
output << '\\'; // escape
output << '\\'; // escape
}
}
output << static_cast<char>(ch);
@@ -209,7 +214,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
unsigned int value = 0;
string token;
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -218,7 +223,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
count = 1;
}
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
}
if (usedLength != NULL) {
*usedLength = (unsigned char)count;
@@ -232,21 +237,21 @@ result_t StringDataType::writeSymbols(istringstream& input,
while (!input.eof() && input.peek() == ' ') {
input.get();
}
if (input.eof()) { // no more digits
value = m_replacement; // fill up with replacement
if (input.eof()) { // no more digits
value = m_replacement; // fill up with replacement
} else {
token.clear();
token.push_back((unsigned char)input.get());
if (input.eof()) {
return RESULT_ERR_INVALID_NUM; // too short hex value
return RESULT_ERR_INVALID_NUM; // too short hex value
}
token.push_back((unsigned char)input.get());
if (input.eof()) {
return RESULT_ERR_INVALID_NUM; // 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) {
return result; // invalid hex value
return result; // invalid hex value
}
}
} else {
@@ -267,13 +272,13 @@ result_t StringDataType::writeSymbols(istringstream& input,
break;
}
if (value > 0xff) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
output[baseOffset + offset] = (unsigned char)value;
}
if (!remainder && i < count) {
return RESULT_ERR_EOF; // input too short
return RESULT_ERR_EOF; // input too short
}
if (usedLength != NULL) {
*usedLength = (unsigned char)((offset-start)*incr);
@@ -298,7 +303,7 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
} else if (baseOffset + count > input.size()) {
return RESULT_ERR_INVALID_POS;
}
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -309,34 +314,34 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
int type = (m_hasDate?2:0) | (m_hasTime?1:0);
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
if (length == 4 && i == 2 && m_hasDate) {
continue; // skip weekday in between
continue; // skip weekday in between
}
ch = input[baseOffset + offset];
if (hasFlag(BCD) && (hasFlag(REQ) || ch != m_replacement)) {
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) {
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
}
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
}
switch (type) {
case 2: // date only
case 2: // date only
if (!hasFlag(REQ) && ch == m_replacement) {
if (i + 1 != length) {
output << NULL_VALUE << ".";
break;
} else if (last == m_replacement) {
if (length == 2) { // number of days since 01.01.1900
if (length == 2) { // number of days since 01.01.1900
output << NULL_VALUE << ".";
}
output << NULL_VALUE;
break;
}
}
if (length == 2) { // number of days since 01.01.1900
if (length == 2) { // number of days since 01.01.1900
if (i == 0) {
break;
}
int mjd = last + ch*256 + 15020; // 01.01.1900
int mjd = last + ch*256 + 15020; // 01.01.1900
int y = static_cast<int>((mjd-15078.2)/365.25);
int m = static_cast<int>((mjd-14956.1-static_cast<int>(y*365.25))/30.6001);
int d = mjd-14956-static_cast<int>(y*365.25)-static_cast<int>(m*30.6001);
@@ -352,15 +357,15 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
if (i + 1 == length) {
output << (2000 + ch);
} else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12)) {
return RESULT_ERR_OUT_OF_RANGE; // invalid date
return RESULT_ERR_OUT_OF_RANGE; // invalid date
} else {
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch) << ".";
}
break;
case 1: // time only
case 1: // time only
if (!hasFlag(REQ) && ch == m_replacement) {
if (length == 1) { // truncated time
if (length == 1) { // truncated time
output << NULL_VALUE << ":" << NULL_VALUE;
break;
}
@@ -370,37 +375,37 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
output << NULL_VALUE;
break;
}
if (hasFlag(SPE)) { // minutes since midnight
if (hasFlag(SPE)) { // minutes since midnight
if (i == 0) {
last = ch;
continue;
}
int minutes = ch*256 + last;
if (minutes > 24*60) {
return RESULT_ERR_OUT_OF_RANGE; // invalid value
return RESULT_ERR_OUT_OF_RANGE; // invalid value
}
int hour = minutes / 60;
if (hour > 24) {
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
}
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(hour);
ch = (unsigned char)(minutes % 60);
} else if (length == 1) { // truncated time
} else if (length == 1) { // truncated time
if (i == 0) {
ch = (unsigned char)(ch/(60/m_resolution)); // convert to hours
offset -= incr; // repeat for minutes
ch = (unsigned char)(ch/(60/m_resolution)); // convert to hours
offset -= incr; // repeat for minutes
count++;
} else {
ch = (unsigned char)((ch % (60/m_resolution)) * m_resolution); // convert to minutes
ch = (unsigned char)((ch % (60/m_resolution)) * m_resolution); // convert to minutes
}
}
if (i == 0) {
if (ch > 24) {
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
}
hour = ch;
} else if (ch > 59 || (hour == 24 && ch > 0)) {
return RESULT_ERR_OUT_OF_RANGE; // invalid time
return RESULT_ERR_OUT_OF_RANGE; // invalid time
}
if (i > 0) {
output << ":";
@@ -425,7 +430,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
unsigned int value = 0, last = 0, lastLast = 0;
string token;
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -434,7 +439,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
count = 1;
}
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
}
if (usedLength != NULL) {
*usedLength = (unsigned char)count;
@@ -448,12 +453,12 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
for (offset = start; i < count; offset += skip ? 0 : incr, i++) {
skip = false;
switch (type) {
case 2: // date only
case 2: // date only
if (length == 4 && i == 2) {
continue; // skip weekday in between
continue; // skip weekday in between
}
if (input.eof() || !getline(input, token, '.')) {
return RESULT_ERR_EOF; // incomplete
return RESULT_ERR_EOF; // incomplete
}
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) {
value = m_replacement;
@@ -461,9 +466,9 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
}
value = parseInt(token.c_str(), 10, 0, 2099, result);
if (result != RESULT_OK) {
return result; // invalid date part
return result; // invalid date part
}
if (length == 2) { // number of days since 01.01.1900
if (length == 2) { // number of days since 01.01.1900
skip = true;
if (i == 0) {
count++;
@@ -471,7 +476,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
int y = (value < 100 ? value + 2000 : value) - 1900;
int l = last <= 2 ? 1 : 0;
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
value = mjd - 15020; // 01.01.1900
value = mjd - 15020; // 01.01.1900
output[baseOffset + offset] = (unsigned char)(value&0xff);
value >>= 8;
offset += incr;
@@ -485,67 +490,68 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
int y = (value < 100 ? value + 2000 : value) - 1900;
int l = last <= 2 ? 1 : 0;
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
int daysSinceSunday = (mjd+3) % 7; // Sun=0
int daysSinceSunday = (mjd+3) % 7; // Sun=0
if (hasFlag(BCD)) {
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
} else {
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday == 0 ? 7 : daysSinceSunday); // Sun=0x07
// Sun=0x07
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday == 0 ? 7 : daysSinceSunday);
}
}
if (value >= 2000) {
value -= 2000;
}
if (value > 99) {
return RESULT_ERR_OUT_OF_RANGE; // 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_OUT_OF_RANGE; // invalid date part
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
}
break;
case 1: // time only
case 1: // time only
if (input.eof() || !getline(input, token, LENGTH_SEPARATOR)) {
return RESULT_ERR_EOF; // incomplete
return RESULT_ERR_EOF; // incomplete
}
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) {
value = m_replacement;
if (length == 1) { // truncated time
if (length == 1) { // truncated time
if (i == 0) {
skip = true; // repeat for minutes
skip = true; // repeat for minutes
count++;
break;
}
if (last != m_replacement) {
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
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
return result; // invalid time part
}
if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) )) {
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
}
if (hasFlag(SPE)) { // minutes since midnight
if (hasFlag(SPE)) { // minutes since midnight
if (i == 0) {
skip = true; // repeat for minutes
skip = true; // repeat for minutes
break;
}
value += last*60;
output[baseOffset + offset] = (unsigned char)(value&0xff);
value >>= 8;
offset += incr;
} else if (length == 1) { // truncated time
} else if (length == 1) { // truncated time
if (i == 0) {
skip = true; // repeat for minutes
skip = true; // repeat for minutes
count++;
break;
}
value = (last * 60 + value + m_resolution/2)/m_resolution;
if (value > 24 * 6) {
return RESULT_ERR_OUT_OF_RANGE; // invalid time
return RESULT_ERR_OUT_OF_RANGE; // invalid time
}
}
break;
@@ -555,19 +561,19 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (!skip) {
if (hasFlag(BCD) && (hasFlag(REQ) || value != m_replacement)) {
if (value > 99) {
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
}
value = ((value / 10) << 4) | (value % 10);
}
if (value > 0xff) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
output[baseOffset + offset] = (unsigned char)value;
}
}
if (!remainder && i < count) {
return RESULT_ERR_EOF; // input too short
return RESULT_ERR_EOF; // input too short
}
if (usedLength != NULL) {
*usedLength = (unsigned char)((offset-start)*incr);
@@ -667,9 +673,9 @@ result_t NumberDataType::readRawValue(SymbolString& input,
unsigned char ch;
if (baseOffset + length > input.size()) {
return RESULT_ERR_INVALID_POS; // not enough data available
return RESULT_ERR_INVALID_POS; // not enough data available
}
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -685,11 +691,11 @@ result_t NumberDataType::readRawValue(SymbolString& input,
}
if (!hasFlag(HCD)) {
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) {
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
}
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
} else if (ch > 0x63) {
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
}
value += ch * exp;
exp *= 100;
@@ -717,7 +723,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
if (result != RESULT_OK) {
return result;
}
output << setw(0) << dec; // initialize output
output << setw(0) << dec; // initialize output
if (!hasFlag(REQ) && value == m_replacement) {
if (outputFormat & OF_JSON) {
@@ -739,7 +745,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
unsigned char* pval = (unsigned char*)&value;
val = *reinterpret_cast<float*>(pval);
#else
int exp = (value >> 23) & 0xff; // 8 bits, signed
int exp = (value >> 23) & 0xff; // 8 bits, signed
if (exp == 0) {
val = 0.0;
} else {
@@ -777,8 +783,8 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
}
return RESULT_OK;
}
signedValue = static_cast<int>(value); // negative signed value
} else if (negative) { // negative signed value
signedValue = static_cast<int>(value); // negative signed value
} else if (negative) { // negative signed value
signedValue = static_cast<int>(value) - (1 << m_bitCount);
} else {
signedValue = static_cast<int>(value);
@@ -819,7 +825,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
value <<= m_firstBit;
}
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
start = length - 1;
incr = -1;
}
@@ -858,14 +864,14 @@ result_t NumberDataType::writeSymbols(istringstream& input,
const char* str = input.str().c_str();
if (!hasFlag(REQ) && (isIgnored() || strcasecmp(str, NULL_VALUE) == 0)) {
value = m_replacement; // replacement value
value = m_replacement; // replacement value
} else if (str == NULL || *str == 0) {
return RESULT_ERR_EOF; // input too short
} else if (hasFlag(EXP)) { // IEEE 754 binary32
return RESULT_ERR_EOF; // input too short
} else if (hasFlag(EXP)) { // IEEE 754 binary32
char* strEnd = NULL;
double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (m_divisor < 0) {
dvalue /= -m_divisor;
@@ -888,7 +894,7 @@ result_t NumberDataType::writeSymbols(istringstream& input,
}
int exp = ilogb(dvalue);
if (exp < -126 || exp > 127) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
dvalue = scalbln(dvalue, -exp) - 1.0;
unsigned int sig = (unsigned int)(dvalue * exp2(23));
@@ -913,13 +919,13 @@ result_t NumberDataType::writeSymbols(istringstream& input,
value = (unsigned int)strtoul(str, &strEnd, 10);
}
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
} else {
char* strEnd = NULL;
double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (m_divisor < 0) {
dvalue = round(dvalue / -m_divisor);
@@ -928,7 +934,7 @@ result_t NumberDataType::writeSymbols(istringstream& input,
}
if (hasFlag(SIG)) {
if (dvalue < -(1LL << (8 * length)) || dvalue >= (1LL << (8 * length))) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
if (dvalue < 0 && m_bitCount != 32) {
value = static_cast<int>(dvalue + (1 << m_bitCount));
@@ -937,22 +943,22 @@ result_t NumberDataType::writeSymbols(istringstream& input,
}
} else {
if (dvalue < 0.0 || dvalue >= (1LL << (8 * length))) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
value = (unsigned int)dvalue;
}
}
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
}
@@ -968,66 +974,105 @@ bool DataTypeList::s_contrib_initialized = libebus_contrib_register();
DataTypeList::DataTypeList() {
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1)); // unsigned decimal in BCD, 0000 - 9999 (fixed length)
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0)); // >= 1 byte character string filled up with 0x00 (null terminated string)
add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true)); // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0)); // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0)); // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0)); // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63, WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0)); // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0)); // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
add(new DateTimeDataType("BTI", 24, BCD|REV, 0xff, false, true, 0)); // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
add(new DateTimeDataType("HTI", 24, 0, 0xff, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0)); // time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
add(new DateTimeDataType("HTM", 16, 0, 0xff, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0)); // time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10)); // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
add(new DateTimeDataType("TTH", 8, 0, 0, false, true, 30)); // truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
add(new DateTimeDataType("TTQ", 8, 0, 0, false, true, 15)); // truncated time (only multiple of 15 minutes), 00:00 - 24:00 (minutes div 15 + hour * 4 as integer)
add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
add(new NumberDataType("BCD", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999
add(new NumberDataType("BCD", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999
add(new NumberDataType("BCD", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999
add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
add(new NumberDataType("HCD", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99
add(new NumberDataType("HCD", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
add(new NumberDataType("HCD", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2)); // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
add(new NumberDataType("D2B", 16, SIG, 0x8000, 0x8001, 0x7fff, 256)); // signed number (fraction 1/256), -127.99 - +127.99
add(new NumberDataType("D2C", 16, SIG, 0x8000, 0x8001, 0x7fff, 16)); // signed number (fraction 1/16), -2047.9 - +2047.9
add(new NumberDataType("FLT", 16, SIG, 0x8000, 0x8001, 0x7fff, 1000)); // signed number (fraction 1/1000), -32.767 - +32.767, little endian
add(new NumberDataType("FLR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1000)); // signed number (fraction 1/1000), -32.767 - +32.767, big endian
add(new NumberDataType("EXP", 32, SIG|EXP, 0x7f800000, 0x00000000, 0xffffffff, 1)); // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), little endian
add(new NumberDataType("EXR", 32, SIG|EXP|REV, 0x7f800000, 0x00000000, 0xffffffff, 1)); // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), big endian
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1)); // unsigned integer, 0 - 65534, little endian
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1)); // unsigned integer, 0 - 65534, big endian
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1)); // signed integer, -32767 - +32767, little endian
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1)); // signed integer, -32767 - +32767, big endian
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1)); // unsigned 3 bytes int, 0 - 16777214, little endian
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1)); // unsigned 3 bytes int, 0 - 16777214, big endian
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0xffffff, 1)); // signed 3 bytes int, -8388607 - +8388607, little endian
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0xffffff, 1)); // signed 3 bytes int, -8388607 - +8388607, big endian
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1)); // unsigned integer, 0 - 4294967294, little endian
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1)); // unsigned integer, 0 - 4294967294, big endian
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0xffffffff, 1)); // signed integer, -2147483647 - +2147483647, little endian
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0xffffffff, 1)); // signed integer, -2147483647 - +2147483647, big endian
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
add(new NumberDataType("BI3", 5, ADJ|REQ, 0, 3, 1)); // bit 3 (up to 5 bits until bit 7)
add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7)
add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7)
add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7)
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
// unsigned decimal in BCD, 0000 - 9999 (fixed length)
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1));
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
// >= 1 byte character string filled up with 0x00 (null terminated string)
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0));
// >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true));
// date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99,
// WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0));
// date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0));
// date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63,
// WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0));
// date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0));
// date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0));
// time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
add(new DateTimeDataType("BTI", 24, BCD|REV, 0xff, false, true, 0));
// time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
add(new DateTimeDataType("HTI", 24, 0, 0xff, false, true, 0));
// time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0));
// time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0));
// time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
add(new DateTimeDataType("HTM", 16, 0, 0xff, false, true, 0));
// time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0));
// time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0));
// truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10));
// truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
add(new DateTimeDataType("TTH", 8, 0, 0, false, true, 30));
// truncated time (only multiple of 15 minutes), 00:00 - 24:00 (minutes div 15 + hour * 4 as integer)
add(new DateTimeDataType("TTQ", 8, 0, 0, false, true, 15));
add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
add(new NumberDataType("BCD", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999
add(new NumberDataType("BCD", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999
add(new NumberDataType("BCD", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999
add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
add(new NumberDataType("HCD", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99
add(new NumberDataType("HCD", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
add(new NumberDataType("HCD", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
// unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2));
// signed number (fraction 1/256), -127.99 - +127.99
add(new NumberDataType("D2B", 16, SIG, 0x8000, 0x8001, 0x7fff, 256));
// signed number (fraction 1/16), -2047.9 - +2047.9
add(new NumberDataType("D2C", 16, SIG, 0x8000, 0x8001, 0x7fff, 16));
// signed number (fraction 1/1000), -32.767 - +32.767, little endian
add(new NumberDataType("FLT", 16, SIG, 0x8000, 0x8001, 0x7fff, 1000));
// signed number (fraction 1/1000), -32.767 - +32.767, big endian
add(new NumberDataType("FLR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1000));
// signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), little endian
add(new NumberDataType("EXP", 32, SIG|EXP, 0x7f800000, 0x00000000, 0xffffffff, 1));
// signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), big endian
add(new NumberDataType("EXR", 32, SIG|EXP|REV, 0x7f800000, 0x00000000, 0xffffffff, 1));
// unsigned integer, 0 - 65534, little endian
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1));
// unsigned integer, 0 - 65534, big endian
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1));
// signed integer, -32767 - +32767, little endian
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
// signed integer, -32767 - +32767, big endian
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1));
// unsigned 3 bytes int, 0 - 16777214, little endian
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
// unsigned 3 bytes int, 0 - 16777214, big endian
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1));
// signed 3 bytes int, -8388607 - +8388607, little endian
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0xffffff, 1));
// signed 3 bytes int, -8388607 - +8388607, big endian
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0xffffff, 1));
// unsigned integer, 0 - 4294967294, little endian
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
// unsigned integer, 0 - 4294967294, big endian
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
// signed integer, -2147483647 - +2147483647, little endian
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0xffffffff, 1));
// signed integer, -2147483647 - +2147483647, big endian
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0xffffffff, 1));
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
add(new NumberDataType("BI3", 5, ADJ|REQ, 0, 3, 1)); // bit 3 (up to 5 bits until bit 7)
add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7)
add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7)
add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7)
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
}
DataTypeList* DataTypeList::getInstance() {
@@ -1050,15 +1095,15 @@ result_t DataTypeList::add(DataType* dataType) {
str << dataType->getId() << LENGTH_SEPARATOR << static_cast<unsigned>(bitCount >= 8?bitCount/8:bitCount);
map<string, DataType*>::iterator it = m_typesByIdLength.find(str.str());
if (it != m_typesByIdLength.end()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
m_typesByIdLength[str.str()] = dataType;
if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
m_cleanupTypes.push_back(dataType);
return RESULT_OK; // only store first one as default
return RESULT_OK; // only store first one as default
}
} else if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
m_typesById[dataType->getId()] = dataType;
m_cleanupTypes.push_back(dataType);
@@ -1081,4 +1126,4 @@ DataType* DataTypeList::get(const string id, const unsigned char length) {
return dataType;
}
} // namespace ebusd
} // namespace ebusd
+43 -34
View File
@@ -83,7 +83,7 @@ typedef int OutputFormat;
/* the bit flags for @a OutputFormat. */
static const unsigned int OF_NAMES = 0x01; //!< include names.
static const unsigned int OF_UNITS = 0x02; //!< include units.
static const unsigned int OF_COMMENTS = 0x04; //!< include comments.
static const unsigned int OF_COMMENTS = 0x04; //!< include comments.
static const unsigned int OF_NUMERIC = 0x08; //!< numeric format (keep numeric value of value=name pairs).
static const unsigned int OF_JSON = 0x10; //!< JSON format.
@@ -95,19 +95,20 @@ enum PartType {
};
/* flags for @a DataType. */
static const unsigned int ADJ = 0x01; //!< adjustable length, bitCount is maximum length
static const unsigned int BCD = 0x02; //!< binary representation is BCD
static const unsigned int REV = 0x04; //!< reverted binary representation (most significant byte first)
static const unsigned int SIG = 0x08; //!< signed value
static const unsigned int IGN = 0x10; //!< ignore value during read and write
static const unsigned int FIX = 0x20; //!< fixed width formatting
static const unsigned int REQ = 0x40; //!< value may not be NULL
static const unsigned int HCD = 0x80; //!< binary representation is hex converted to decimal and interpreted as 2 digits (also requires #BCD)
static const unsigned int EXP = 0x100; //!< exponential numeric representation
static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days
static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType
static const unsigned int SPE = 0x800; //!< special marker for certain types
static const unsigned int CON = 0x1000; //!< marker for a constant value
static const unsigned int ADJ = 0x01; //!< adjustable length, bitCount is maximum length
static const unsigned int BCD = 0x02; //!< binary representation is BCD
static const unsigned int REV = 0x04; //!< reverted binary representation (most significant byte first)
static const unsigned int SIG = 0x08; //!< signed value
static const unsigned int IGN = 0x10; //!< ignore value during read and write
static const unsigned int FIX = 0x20; //!< fixed width formatting
static const unsigned int REQ = 0x40; //!< value may not be NULL
/** binary representation is hex converted to decimal and interpreted as 2 digits (also requires #BCD). */
static const unsigned int HCD = 0x80;
static const unsigned int EXP = 0x100; //!< exponential numeric representation
static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days
static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType
static const unsigned int SPE = 0x800; //!< special marker for certain types
static const unsigned int CON = 0x1000; //!< marker for a constant value
/**
@@ -120,7 +121,8 @@ static const unsigned int CON = 0x1000; //!< marker for a constant value
* @param length the optional variable in which to store the number of read characters.
* @return the parsed value.
*/
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length = NULL);
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
result_t& result, unsigned int* length = NULL);
/**
* Parse a signed int value.
@@ -132,7 +134,8 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
* @param length the optional variable in which to store the number of read characters.
* @return the parsed value.
*/
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length = NULL);
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
unsigned int* length = NULL);
/**
* Print the error position of the iterator.
@@ -144,20 +147,22 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
* @param lineNo the current line number in the file being read.
* @param result the result code.
*/
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
/**
* Base class for all kinds of data types.
*/
class DataType {
public:
public:
/**
* Constructs a new instance.
* @param id the type identifier.
* @param bitCount the number of bits (maximum length if #ADJ flag is set, must be multiple of 8 with flag #BCD).
* @param flags the combination of flags (like #BCD).
* @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue).
* @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to
* @a NumberDataType#minValue).
*/
DataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement)
: m_id(id), m_bitCount(bitCount), m_flags(flags), m_replacement(replacement) {}
@@ -200,7 +205,8 @@ class DataType {
bool isNumeric() const { return hasFlag(NUM); }
/**
* @return the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue).
* @return the replacement value (fill-up value for @a StringDataType, no replacement if equal to
* @a NumberDataType#minValue).
*/
unsigned int getReplacement() const { return m_replacement; }
@@ -254,7 +260,7 @@ class DataType {
SymbolString& output, const bool isMaster, unsigned char* usedLength) = 0;
protected:
protected:
/** the type identifier. */
const string m_id;
@@ -264,7 +270,8 @@ class DataType {
/** the combination of flags (like #BCD). */
const uint16_t m_flags;
/** the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue). */
/** the replacement value (fill-up value for @a StringDataType, no replacement if equal to
* @a NumberDataType#minValue). */
const unsigned int m_replacement;
};
@@ -273,7 +280,7 @@ class DataType {
* A string based @a DataType.
*/
class StringDataType : public DataType {
public:
public:
/**
* Constructs a new instance.
* @param id the type identifier.
@@ -307,7 +314,7 @@ class StringDataType : public DataType {
SymbolString& output, const bool isMaster, unsigned char* usedLength);
private:
private:
/** true for hex digits instead of characters. */
const bool m_isHex;
};
@@ -317,7 +324,7 @@ class StringDataType : public DataType {
* A date/time based @a DataType.
*/
class DateTimeDataType : public DataType {
public:
public:
/**
* Constructs a new instance.
* @param id the type identifier.
@@ -368,7 +375,7 @@ class DateTimeDataType : public DataType {
SymbolString& output, const bool isMaster, unsigned char* usedLength);
private:
private:
/** true if date part is present. */
const bool m_hasDate;
@@ -384,7 +391,7 @@ class DateTimeDataType : public DataType {
* A number based @a DataType.
*/
class NumberDataType : public DataType {
public:
public:
/**
* Constructs a new instance for multiple of 8 bits.
* @param id the type identifier.
@@ -397,7 +404,8 @@ class NumberDataType : public DataType {
*/
NumberDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement,
const unsigned int minValue, const unsigned int maxValue, const int divisor)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(NULL) {}
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor),
m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(NULL) {}
/**
* Constructs a new instance for less than 8 bits.
@@ -410,7 +418,8 @@ class NumberDataType : public DataType {
*/
NumberDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement,
const int16_t firstBit, const int divisor)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor), m_precision(0), m_firstBit(firstBit), m_baseType(NULL) {}
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor),
m_precision(0), m_firstBit(firstBit), m_baseType(NULL) {}
/**
* Destructor.
@@ -495,7 +504,7 @@ class NumberDataType : public DataType {
SymbolString& output, const bool isMaster, unsigned char* usedLength);
private:
private:
/** the minimum raw value. */
const unsigned int m_minValue;
@@ -520,7 +529,7 @@ class NumberDataType : public DataType {
* A map of base @a DataType instances.
*/
class DataTypeList {
public:
public:
/**
* Constructs a new instance and registers the known base data types.
*/
@@ -568,7 +577,7 @@ class DataTypeList {
DataType* get(const string id, const unsigned char length = 0);
private:
private:
/** the known @a DataType instances by ID only. */
map<string, DataType*> m_typesById;
@@ -588,6 +597,6 @@ class DataTypeList {
#endif
};
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_DATATYPE_H_
#endif // LIB_EBUS_DATATYPE_H_
+9 -9
View File
@@ -54,13 +54,13 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
}
if (portpos == NULL) {
free(in);
return NULL; // invalid protocol or missing port
return NULL; // invalid protocol or missing port
}
result_t result = RESULT_OK;
unsigned int port = parseInt(portpos+1, 10, 1, 65535, result);
if (result != RESULT_OK) {
free(in);
return NULL; // invalid port
return NULL; // invalid port
}
struct sockaddr_in address;
memset(reinterpret_cast<char*>(&address), 0, sizeof(address));
@@ -69,7 +69,7 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
struct hostent* h = gethostbyname(addrpos);
if (h == NULL) {
free(in);
return NULL; // invalid host
return NULL; // invalid host
}
memcpy(&address.sin_addr, h->h_addr_list[0], h->h_length);
}
@@ -142,7 +142,7 @@ result_t Device::recv(const unsigned int timeout, unsigned char& value) {
ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL);
#else
ret = 1; // ignore timeout if neither ppoll nor pselect are available
ret = 1; // ignore timeout if neither ppoll nor pselect are available
#endif
#endif
if (ret == -1) {
@@ -197,8 +197,8 @@ result_t SerialDevice::open() {
memset(&newSettings, '\0', sizeof(newSettings));
newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD);
newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode
newSettings.c_iflag |= IGNPAR; // ignore parity errors
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
@@ -290,7 +290,7 @@ void NetworkDevice::checkDevice() {
unsigned char value;
ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT);
if (c == 0 || (c < 0 && errno != EAGAIN)) {
m_bufLen = 0; // flush read buffer
m_bufLen = 0; // flush read buffer
close();
}
}
@@ -300,7 +300,7 @@ bool NetworkDevice::available() {
}
ssize_t NetworkDevice::write(const unsigned char value) {
m_bufLen = 0; // flush read buffer
m_bufLen = 0; // flush read buffer
return Device::write(value);
}
@@ -324,4 +324,4 @@ ssize_t NetworkDevice::read(unsigned char& value) {
return Device::read(value);
}
} // namespace ebusd
} // namespace ebusd
+17 -16
View File
@@ -42,7 +42,7 @@ namespace ebusd {
* Interface for listening to data received on/sent to a device.
*/
class DeviceListener {
public:
public:
/**
* Destructor.
*/
@@ -53,7 +53,7 @@ class DeviceListener {
* @param byte the data byte received/sent.
* @param received @a true on reception, @a false on sending.
*/
virtual void notifyDeviceData(const unsigned char byte, bool received) = 0; // abstract
virtual void notifyDeviceData(const unsigned char byte, bool received) = 0; // abstract
};
@@ -61,7 +61,7 @@ class DeviceListener {
* The base class for accessing an eBUS.
*/
class Device {
public:
public:
/**
* Construct a new instance.
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
@@ -87,7 +87,8 @@ class Device {
* @return the new @a Device, or NULL on error.
* Note: the caller needs to free the created instance.
*/
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, const bool initialSend = false);
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false,
const bool initialSend = false);
/**
* Get the transfer latency of this device.
@@ -99,7 +100,7 @@ class Device {
* Open the file descriptor.
* @return the @a result_t code.
*/
virtual result_t open() = 0; // abstract
virtual result_t open() = 0; // abstract
/**
* Close the file descriptor if opened.
@@ -146,11 +147,11 @@ class Device {
void setListener(DeviceListener* listener) { m_listener = listener; }
protected:
protected:
/**
* Check if the device is still available and close it if not.
*/
virtual void checkDevice() = 0; // abstract
virtual void checkDevice() = 0; // abstract
/**
* Check whether a byte is available immediately (without waiting).
@@ -188,7 +189,7 @@ class Device {
int m_fd;
private:
private:
/** the @a DeviceListener, or NULL. */
DeviceListener* m_listener;
};
@@ -197,7 +198,7 @@ class Device {
* The @a Device for directly connected serial interfaces (tty).
*/
class SerialDevice : public Device {
public:
public:
/**
* Construct a new instance.
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
@@ -215,12 +216,12 @@ class SerialDevice : public Device {
virtual void close();
protected:
protected:
// @copydoc
virtual void checkDevice();
private:
private:
/** the previous settings of the device for restoring. */
termios m_oldSettings;
};
@@ -229,7 +230,7 @@ class SerialDevice : public Device {
* The @a Device for remote network interfaces.
*/
class NetworkDevice : public Device {
public:
public:
/**
* Construct a new instance.
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
@@ -250,7 +251,7 @@ class NetworkDevice : public Device {
virtual result_t open();
protected:
protected:
// @copydoc
virtual void checkDevice();
@@ -264,7 +265,7 @@ class NetworkDevice : public Device {
virtual ssize_t read(unsigned char& value);
private:
private:
/** the socket address of the device. */
const struct sockaddr_in m_address;
@@ -284,6 +285,6 @@ class NetworkDevice : public Device {
unsigned char m_bufPos;
};
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_DEVICE_H_
#endif // LIB_EBUS_DEVICE_H_
+29 -25
View File
@@ -62,15 +62,17 @@ using std::endl;
/** the separator character used between multiple values (in CSV only). */
#define VALUE_SEPARATOR ';'
extern void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
extern void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
extern unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length);
extern unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
result_t& result, unsigned int* length);
/**
* An abstract class that support reading definitions from a file.
*/
class FileReader {
public:
public:
/**
* Construct a new instance.
*/
@@ -100,13 +102,14 @@ class FileReader {
return RESULT_ERR_NOTFOUND;
}
size_t lastSep = filename.find_last_of('/');
if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
// extract defaultDest, defaultCircuit, defaultSuffix from filename:
// ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv
unsigned char checkDest;
string checkIdent, useCircuit, useSuffix;
unsigned int checkSw, checkHw;
if (extractDefaultsFromFilename(filename.substr(lastSep+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
if (extractDefaultsFromFilename(filename.substr(lastSep+1), checkDest, checkIdent, useCircuit, useSuffix,
checkSw, checkHw)) {
defaultDest = filename.substr(lastSep+1, 2);
if (!useCircuit.empty()) {
defaultCircuit = useCircuit;
@@ -202,8 +205,8 @@ class FileReader {
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo) = 0;
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string& filename, unsigned int lineNo) = 0;
/**
* Left and right trim the string.
@@ -249,7 +252,7 @@ class FileReader {
size_t length = line.length();
if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) {
continue; // skip empty lines and comments
continue; // skip empty lines and comments
}
for (size_t pos = 0; pos < length; pos++) {
char ch = line[pos];
@@ -267,7 +270,7 @@ class FileReader {
}
break;
case TEXT_SEPARATOR:
if (prev == TEXT_SEPARATOR && !quotedText) { // double dquote
if (prev == TEXT_SEPARATOR && !quotedText) { // double dquote
field << ch;
quotedText = true;
} else if (quotedText) {
@@ -282,7 +285,7 @@ class FileReader {
break;
default:
if (prev == TEXT_SEPARATOR && !quotedText && wasQuoted) {
field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text
field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text
quotedText = true;
} else if (quotedText && pos == 0 && field.tellp() > 0 && *(field.str().end()-1) != VALUE_SEPARATOR) {
field << VALUE_SEPARATOR;
@@ -322,48 +325,49 @@ class FileReader {
ident = circuit = suffix = "";
software = hardware = UINT_MAX;
if (name.length() > 4 && name.substr(name.length()-4) == ".csv") {
name = name.substr(0, name.length()-3); // including trailing "."
name = name.substr(0, name.length()-3); // including trailing "."
}
size_t pos = name.find('.');
if (pos != 2) {
return false; // missing "ZZ."
return false; // missing "ZZ."
}
result_t result = RESULT_OK;
dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL);
if (result != RESULT_OK || !isValidAddress(dest)) {
return false; // invalid "ZZ"
return false; // invalid "ZZ"
}
name.erase(0, pos);
if (name.length() > 1) {
pos = name.rfind(".SW"); // check for ".SWxxxx."
pos = name.rfind(".SW"); // check for ".SWxxxx."
if (pos != string::npos && name.find(".", pos+1) == pos+7) {
software = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
if (result != RESULT_OK) {
return false; // invalid "SWxxxx"
return false; // invalid "SWxxxx"
}
name.erase(pos, 7);
}
}
if (name.length() > 1) {
pos = name.rfind(".HW"); // check for ".HWxxxx."
pos = name.rfind(".HW"); // check for ".HWxxxx."
if (pos != string::npos && name.find(".", pos+1) == pos+7) {
hardware = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
if (result != RESULT_OK) {
return false; // invalid "HWxxxx"
return false; // invalid "HWxxxx"
}
name.erase(pos, 7);
}
}
if (name.length() > 1) {
pos = name.find('.', 1); // check for ".IDENT."
if (pos != string::npos && pos >= 1 && pos <= 6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".."
pos = name.find('.', 1); // check for ".IDENT."
if (pos != string::npos && pos >= 1 && pos <= 6) {
// up to 5 chars between two "."s, immediately after "ZZ.", or ".."
ident = circuit = name.substr(1, pos-1);
name.erase(0, pos);
pos = name.find('.', 1); // check for ".CIRCUIT."
pos = name.find('.', 1); // check for ".CIRCUIT."
if (pos != string::npos && (pos>2 || name[1]<'0' || name[1]>'9')) {
circuit = name.substr(1, pos-1);
name.erase(0, pos);
pos = name.find('.', 1); // check for ".SUFFIX."
pos = name.find('.', 1); // check for ".SUFFIX."
}
if (pos != string::npos && pos == 2 && name[1] >= '0' && name[1] <= '9') {
suffix = name.substr(0, 2);
@@ -375,16 +379,16 @@ class FileReader {
}
private:
private:
/** whether this instance supports rows with defaults (starting with a star). */
bool m_supportsDefaults;
protected:
protected:
/** a @a string describing the last error position. */
string m_lastError;
};
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_FILEREADER_H_
#endif // LIB_EBUS_FILEREADER_H_
+148 -125
View File
@@ -83,18 +83,15 @@ Message::Message(const string circuit, const string name,
const bool isWrite, const bool isPassive,
const unsigned char pb, const unsigned char sb,
DataField* data, const bool deleteData)
: m_circuit(circuit), m_name(name), m_isWrite(isWrite),
m_isPassive(isPassive), m_comment(),
m_srcAddress(SYN), m_dstAddress(SYN),
m_data(data), m_deleteData(true),
m_pollPriority(0),
m_usedByCondition(false), m_isScanMessage(false), m_condition(NULL),
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) {
: m_circuit(circuit), m_name(name), m_isWrite(isWrite), m_isPassive(isPassive), m_comment(), m_srcAddress(SYN),
m_dstAddress(SYN), m_data(data), m_deleteData(true), m_pollPriority(0), m_usedByCondition(false),
m_isScanMessage(false), m_condition(NULL), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0),
m_lastPollTime(0) {
m_id.push_back(pb);
m_id.push_back(sb);
uint64_t key = 0;
if (!isPassive) {
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
}
key |= (uint64_t)SYN << (8 * 6);
key |= (uint64_t)pb << (8 * 5);
@@ -116,7 +113,8 @@ Message::Message(const string circuit, const string name,
* empty and @p replaceStar is @p true.
* @return the default if available and value is empty, or the value.
*/
string getDefault(const string value, vector<string>* defaults, size_t pos, bool replaceStar = false, bool required = false) {
string getDefault(const string value, vector<string>* defaults, size_t pos, bool replaceStar = false,
bool required = false) {
if (defaults == NULL || pos >= defaults->size()) {
return value;
}
@@ -139,9 +137,9 @@ uint64_t Message::createKey(const vector<unsigned char> id,
const unsigned char srcAddress, const unsigned char dstAddress) {
uint64_t key = (uint64_t)(id.size()-2) << (8 * 7 + 5);
if (isPassive) {
key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25
key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25
} else {
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
}
key |= (uint64_t)dstAddress << (8 * 6);
int exp = 5;
@@ -166,10 +164,10 @@ uint64_t Message::createKey(SymbolString& master, unsigned char maxIdLength, boo
return INVALID_KEY;
}
uint64_t key = (uint64_t)idLength << (8 * 7 + 5);
key |= (uint64_t)getMasterNumber(master[0]) << (8 * 7); // QQ address for passive message
key |= (uint64_t)(anyDestination ? SYN : master[1]) << (8 * 6); // ZZ address
key |= (uint64_t)master[2] << (8 * 5); // PB
key |= (uint64_t)master[3] << (8 * 4); // SB
key |= (uint64_t)getMasterNumber(master[0]) << (8 * 7); // QQ address for passive message
key |= (uint64_t)(anyDestination ? SYN : master[1]) << (8 * 6); // ZZ address
key |= (uint64_t)master[2] << (8 * 5); // PB
key |= (uint64_t)master[3] << (8 * 4); // SB
int exp = 3;
for (unsigned char i = 0; i < idLength; i++) {
key ^= (uint64_t)master[5 + i] << (8 * exp--);
@@ -186,20 +184,20 @@ result_t Message::parseId(string input, vector<unsigned char>& id) {
while (in.peek() == ' ') {
in.get();
}
if (in.eof()) { // no more digits
if (in.eof()) { // no more digits
break;
}
input.clear();
input.push_back(static_cast<char>(in.get()));
if (in.eof()) {
return RESULT_ERR_INVALID_ARG; // too short hex
return RESULT_ERR_INVALID_ARG; // too short hex
}
input.push_back(static_cast<char>(in.get()));
result_t result;
unsigned char value = (unsigned char)parseInt(input.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK) {
return result; // invalid hex value
return result; // invalid hex value
}
id.push_back(value);
}
@@ -219,28 +217,28 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return RESULT_ERR_EOF;
}
string typeStr = *it++;
const char* str = typeStr.c_str(); // [type]
const char* str = typeStr.c_str(); // [type]
if (it == end) {
return RESULT_ERR_EOF;
}
size_t len = strlen(str);
if (len == 0) { // default: active read
if (len == 0) { // default: active read
defaultName = "r";
} else {
defaultName = str;
char type = str[0];
if (type == 'r' || type == 'R') { // active read
if (type == 'r' || type == 'R') { // active read
char poll = str[1];
if (poll >= '0' && poll <= '9') { // poll priority (=active read)
if (poll >= '0' && poll <= '9') { // poll priority (=active read)
pollPriority = (unsigned char)(poll - '0');
defaultName.erase(1, 1); // cut off priority digit
defaultName.erase(1, 1); // cut off priority digit
}
} else if (type == 'w' || type == 'W') { // active write
} else if (type == 'w' || type == 'W') { // active write
isWrite = true;
} else { // any other: passive read/write
} else { // any other: passive read/write
isPassive = true;
type = str[1];
isWrite = type == 'w' || type == 'W'; // if type continues with "w" it is treated as passive write
isWrite = type == 'w' || type == 'W'; // if type continues with "w" it is treated as passive write
}
}
@@ -255,28 +253,28 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
}
}
string circuit = getDefault(*it++, defaults, defaultPos++, true); // [circuit]
string circuit = getDefault(*it++, defaults, defaultPos++, true); // [circuit]
if (it == end) {
return RESULT_ERR_EOF;
}
string name = getDefault(*it++, defaults, defaultPos++, true, true); // name
string name = getDefault(*it++, defaults, defaultPos++, true, true); // name
if (it == end) {
return RESULT_ERR_EOF;
}
if (name.length() == 0) {
return RESULT_ERR_INVALID_ARG; // empty name
return RESULT_ERR_INVALID_ARG; // empty name
}
string comment = getDefault(*it++, defaults, defaultPos++, true); // [comment]
string comment = getDefault(*it++, defaults, defaultPos++, true); // [comment]
if (it == end) {
return RESULT_ERR_EOF;
}
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [QQ[;QQ]*]
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [QQ[;QQ]*]
if (it == end) {
return RESULT_ERR_EOF;
}
unsigned char srcAddress;
if (*str == 0) {
srcAddress = SYN; // no specific source
srcAddress = SYN; // no specific source
} else {
srcAddress = (unsigned char)parseInt(str, 16, 0, 0xff, result);
if (result != RESULT_OK) {
@@ -287,14 +285,14 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
}
}
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [ZZ]
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [ZZ]
if (it == end) {
return RESULT_ERR_EOF;
}
vector<unsigned char> dstAddresses;
bool isBroadcastOrMasterDestination = false;
if (*str == 0) {
dstAddresses.push_back(SYN); // no specific destination
dstAddresses.push_back(SYN); // no specific destination
} else {
istringstream stream(str);
string token;
@@ -320,7 +318,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
}
vector<unsigned char> id;
string token = *it++; // [PBSB]
string token = *it++; // [PBSB]
bool useDefaults = token.empty();
if (useDefaults) {
token = getDefault(token, defaults, defaultPos);
@@ -331,12 +329,12 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return result;
}
if (id.size() != 2) {
return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB
return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB
}
if (it == end) {
token = "";
} else {
token = *it++;// [ID] (optional master data)
token = *it++; // [ID] (optional master data)
}
string defaultIdPrefix;
if (useDefaults) {
@@ -406,7 +404,8 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
}
vector<string>::iterator realEnd = end;
vector<string> newTypes;
if (defaults != NULL && defaults->size() > defaultPos + 2) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
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) {
@@ -430,12 +429,14 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
vector<SingleDataField*> fields;
data = new DataFieldSet("", "", fields);
} else {
result = DataField::create(it, realEnd, templates, data, isWrite, false, isBroadcastOrMasterDestination, (unsigned char)maxLength);
result = DataField::create(it, realEnd, templates, data, isWrite, false, isBroadcastOrMasterDestination,
(unsigned char)maxLength);
if (result != RESULT_OK) {
return result;
}
}
if (id.size() + data->getLength(pt_masterData, (unsigned char)maxLength) > 2 + maxLength || data->getLength(pt_slaveData, (unsigned char)maxLength) > maxLength) {
if (id.size() + data->getLength(pt_masterData, (unsigned char)maxLength) > 2 + maxLength
|| data->getLength(pt_slaveData, (unsigned char)maxLength) > maxLength) {
// max NN exceeded
delete data;
return RESULT_ERR_INVALID_POS;
@@ -452,9 +453,11 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
}
Message* message;
if (chainIds.size() > 1) {
message = new ChainedMessage(useCircuit, name, isWrite, comment, srcAddress, dstAddress, id, chainIds, chainLengths, data, index == 0, pollPriority, condition);
message = new ChainedMessage(useCircuit, name, isWrite, comment, srcAddress, dstAddress, id, chainIds,
chainLengths, data, index == 0, pollPriority, condition);
} else {
message = new Message(useCircuit, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data, index == 0, pollPriority, condition);
message = new Message(useCircuit, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data,
index == 0, pollPriority, condition);
}
messages.push_back(message);
}
@@ -500,7 +503,7 @@ bool Message::checkIdPrefix(vector<unsigned char>& id) {
bool Message::checkId(SymbolString& master, unsigned char* index) {
unsigned char idLen = getIdLength();
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
return false;
}
for (unsigned char pos = 0; pos < idLen; pos++) {
@@ -516,7 +519,7 @@ bool Message::checkId(SymbolString& master, unsigned char* index) {
bool Message::checkId(Message& other) {
unsigned char idLen = getIdLength();
if (idLen != other.getIdLength() || getCount() > 1) { // only equal for non-chained messages
if (idLen != other.getIdLength() || getCount() > 1) { // only equal for non-chained messages
return false;
}
return other.checkIdPrefix(m_id);
@@ -560,7 +563,7 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma
istringstream& input, char separator,
const unsigned char dstAddress, unsigned char index) {
if (m_isPassive) {
return RESULT_ERR_INVALID_ARG; // prepare not possible
return RESULT_ERR_INVALID_ARG; // prepare not possible
}
SymbolString master(false);
result_t result = master.push_back(srcAddress, false, false);
@@ -604,7 +607,7 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
return RESULT_ERR_NOTFOUND;
}
unsigned char pos = master.size();
result_t result = master.push_back(0, false, false); // length, will be set later
result_t result = master.push_back(0, false, false); // length, will be set later
if (result != RESULT_OK) {
return result;
}
@@ -624,10 +627,10 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) {
if (m_isWrite) {
return RESULT_ERR_INVALID_ARG; // prepare not possible
return RESULT_ERR_INVALID_ARG; // prepare not possible
}
SymbolString slave(false);
result_t result = slave.push_back(0, false, false); // length, will be set later
result_t result = slave.push_back(0, false, false); // length, will be set later
if (result != RESULT_OK) {
return result;
}
@@ -661,11 +664,11 @@ result_t Message::storeLastData(const PartType partType, SymbolString& data, uns
}
if (partType == pt_masterData) {
switch (data.compareMaster(m_lastMasterData)) {
case 1: // completely different
case 1: // completely different
m_lastChangeTime = m_lastUpdateTime;
m_lastMasterData = data;
break;
case 2: // only master address is different
case 2: // only master address is different
m_lastMasterData = data;
break;
}
@@ -687,7 +690,8 @@ result_t Message::decodeLastData(const PartType partType,
} else {
offset = 0;
}
result_t result = m_data->read(partType, partType == pt_masterData ? m_lastMasterData : m_lastSlaveData, offset, output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
result_t result = m_data->read(partType, partType == pt_masterData ? m_lastMasterData : m_lastSlaveData, offset,
output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
if (result < RESULT_OK) {
return result;
}
@@ -700,18 +704,20 @@ result_t Message::decodeLastData(const PartType partType,
result_t Message::decodeLastData(ostringstream& output, OutputFormat outputFormat,
bool leadingSeparator, const char* fieldName, signed char fieldIndex) {
size_t startPos = output.str().length();
result_t result = m_data->read(pt_masterData, m_lastMasterData, getIdLength(), output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
result_t result = m_data->read(pt_masterData, m_lastMasterData, getIdLength(), output, outputFormat, -1,
leadingSeparator, fieldName, fieldIndex);
if (result < RESULT_OK) {
return result;
}
bool empty = result == RESULT_EMPTY;
leadingSeparator |= output.str().length() > startPos;
result = m_data->read(pt_slaveData, m_lastSlaveData, 0, output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
result = m_data->read(pt_slaveData, m_lastSlaveData, 0, output, outputFormat, -1, leadingSeparator, fieldName,
fieldIndex);
if (result < RESULT_OK) {
return result;
}
if (result == RESULT_EMPTY && !empty) {
result = RESULT_OK; // OK if at least one part was non-empty
result = RESULT_OK; // OK if at least one part was non-empty
} else if (result == RESULT_EMPTY && fieldName != NULL) {
return RESULT_ERR_NOTFOUND;
}
@@ -774,7 +780,7 @@ void Message::dump(ostream& output, vector<size_t>* columns, bool withConditions
void Message::dumpColumn(ostream& output, size_t column, bool withConditions) {
switch (column) {
case COLUMN_TYPE: // type
case COLUMN_TYPE: // type
if (withConditions && m_condition != NULL) {
m_condition->dump(output);
}
@@ -792,36 +798,36 @@ void Message::dumpColumn(ostream& output, size_t column, bool withConditions) {
}
}
break;
case COLUMN_CIRCUIT: // circuit
case COLUMN_CIRCUIT: // circuit
DataField::dumpString(output, m_circuit, false);
break;
case COLUMN_NAME: // name
case COLUMN_NAME: // name
DataField::dumpString(output, m_name, false);
break;
case COLUMN_COMMENT: // comment
case COLUMN_COMMENT: // comment
DataField::dumpString(output, m_comment, false);
break;
case COLUMN_QQ: // QQ
case COLUMN_QQ: // QQ
if (m_srcAddress != SYN) {
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_srcAddress);
}
break;
case COLUMN_ZZ: // ZZ
case COLUMN_ZZ: // ZZ
if (m_dstAddress != SYN) {
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress);
}
break;
case COLUMN_PBSB: // PBSB
case COLUMN_PBSB: // PBSB
for (vector<unsigned char>::const_iterator it = m_id.begin(); it < m_id.begin()+2 && it < m_id.end(); it++) {
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(*it);
}
break;
case COLUMN_ID: // ID
case COLUMN_ID: // ID
for (vector<unsigned char>::const_iterator it = m_id.begin()+2; it < m_id.end(); it++) {
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(*it);
}
break;
case COLUMN_FIELDS: // fields
case COLUMN_FIELDS: // fields
m_data->dump(output);
break;
}
@@ -840,7 +846,7 @@ ChainedMessage::ChainedMessage(const string circuit, const string name,
srcAddress, dstAddress, id,
data, deleteData, pollPriority, condition),
m_ids(ids), m_lengths(lengths),
m_maxTimeDiff(m_ids.size()*15) { // 15 seconds per message
m_maxTimeDiff(m_ids.size()*15) { // 15 seconds per message
size_t cnt = ids.size();
m_lastMasterDatas = reinterpret_cast<SymbolString**>(calloc(cnt, sizeof(SymbolString*)));
m_lastSlaveDatas = reinterpret_cast<SymbolString**>(calloc(cnt, sizeof(SymbolString*)));
@@ -879,16 +885,16 @@ Message* ChainedMessage::derive(const unsigned char dstAddress, const unsigned c
bool ChainedMessage::checkId(SymbolString& master, unsigned char* index) {
unsigned char idLen = getIdLength();
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
return false;
}
unsigned char chainPrefixLength = Message::getIdLength();
for (unsigned char pos = 0; pos < chainPrefixLength; pos++) {
if (m_id[2+pos] != master[5+pos]) {
return false; // chain prefix mismatch
return false; // chain prefix mismatch
}
}
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
vector<unsigned char> id = m_ids[checkIndex];
bool found = false;
for (unsigned char pos = chainPrefixLength; pos < idLen; pos++) {
@@ -910,15 +916,15 @@ bool ChainedMessage::checkId(SymbolString& master, unsigned char* index) {
bool ChainedMessage::checkId(Message& other) {
unsigned char idLen = getIdLength();
if (idLen != other.getIdLength() || other.getCount() == 1) { // only equal for chained messages
if (idLen != other.getIdLength() || other.getCount() == 1) { // only equal for chained messages
return false;
}
if (!other.checkIdPrefix(m_id)) {
return false; // chain prefix mismatch
return false; // chain prefix mismatch
}
vector< vector<unsigned char> > otherIds = ((ChainedMessage&)other).m_ids;
unsigned char chainPrefixLength = Message::getIdLength();
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
vector<unsigned char> id = m_ids[checkIndex];
for (unsigned char otherIndex = 0; otherIndex < otherIds.size(); otherIndex++) {
vector<unsigned char> otherId = otherIds[otherIndex];
@@ -938,7 +944,8 @@ bool ChainedMessage::checkId(Message& other) {
return false;
}
result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index) {
result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream& input, char separator,
unsigned char index) {
size_t cnt = getCount();
if (index >= cnt) {
return RESULT_ERR_NOTFOUND;
@@ -960,7 +967,7 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
return RESULT_ERR_INVALID_POS;
}
vector<unsigned char> id = m_ids[index];
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN
if (result != RESULT_OK) {
return result;
}
@@ -1003,10 +1010,10 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
}
if (partType == pt_masterData) {
switch (data.compareMaster(*m_lastMasterDatas[index])) {
case 1: // completely different
case 1: // completely different
*m_lastMasterDatas[index] = data;
break;
case 2: // only master address is different
case 2: // only master address is different
*m_lastMasterDatas[index] = data;
break;
}
@@ -1043,7 +1050,7 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
// everything was completely retrieved in short time
SymbolString master(false);
SymbolString slave(false);
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
for (index = 0; index < m_ids.size(); index++) {
SymbolString* add = m_lastMasterDatas[index];
size_t end = 5+(*add)[4];
@@ -1166,7 +1173,8 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
valueRanges.push_back(0);
}
bool inclusive = str[1] == '=';
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1, inclusive?UINT_MAX:(UINT_MAX-1), result);
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1,
inclusive?UINT_MAX:(UINT_MAX-1), result);
if (result != RESULT_OK) {
return result;
}
@@ -1176,14 +1184,14 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
}
} else {
size_t pos = str.find('-');
if (pos != string::npos && pos > 0) { // range
if (pos != string::npos && pos > 0) { // range
unsigned int val = parseInt(str.substr(0, pos).c_str(), 10, 0, UINT_MAX, result);
if (result != RESULT_OK) {
return result;
}
valueRanges.push_back(val);
pos++;
} else { // single value
} else { // single value
pos = 0;
}
unsigned int val = parseInt(str.substr(pos).c_str(), 10, 0, UINT_MAX, result);
@@ -1192,22 +1200,23 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
}
valueRanges.push_back(val);
if (pos == 0) {
valueRanges.push_back(val); // single value
valueRanges.push_back(val); // single value
}
}
}
return RESULT_OK;
}
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue) {
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end,
string defaultDest, string defaultCircuit, SimpleCondition*& returnValue) {
// name,circuit,messagename,[comment],[fieldname],[ZZ],values (name already skipped by caller)
string circuit = it == end ? "" : *(it++); // circuit
string name = it == end ? "" : *(it++); // messagename
string circuit = it == end ? "" : *(it++); // circuit
string name = it == end ? "" : *(it++); // messagename
if (it < end) {
it++; // comment
it++; // comment
}
string field = it == end ? "" : *(it++); // fieldname
string zz = it == end ? "" : *(it++); // ZZ
string field = it == end ? "" : *(it++); // fieldname
string zz = it == end ? "" : *(it++); // ZZ
unsigned char dstAddress = SYN;
result_t result = RESULT_OK;
if (zz.length() == 0) {
@@ -1304,12 +1313,14 @@ CombinedCondition* SimpleCondition::combineAnd(Condition* other) {
return ret->combineAnd(this)->combineAnd(other);
}
result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)) {
result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage,
void (*readMessageFunc)(Message* message)) {
if (m_message == NULL) {
Message* message;
if (m_name.length() == 0) {
message = messages->getScanMessage(m_dstAddress);
errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(m_dstAddress);
errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(m_dstAddress);
} else {
message = messages->find(m_circuit, m_name, false);
if (!message) {
@@ -1339,7 +1350,8 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess
} else {
Message* first = getFirstAvailable(*derived, message);
if (first == NULL) {
errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName() << " for " << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress) << " not found";
errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName()
<< " for " << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress) << " not found";
return RESULT_ERR_INVALID_ARG;
}
message = first;
@@ -1369,7 +1381,7 @@ bool SimpleCondition::isTrue() {
return false;
}
if (m_message->getLastChangeTime() > m_lastCheckTime) {
bool isTrue = !m_hasValues; // for message seen check
bool isTrue = !m_hasValues; // for message seen check
if (!isTrue) {
isTrue = checkValue(m_message, m_field);
}
@@ -1420,7 +1432,8 @@ void CombinedCondition::dump(ostream& output, bool matched) {
}
}
result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)) {
result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage,
void (*readMessageFunc)(Message* message)) {
for (vector<Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
Condition* condition = *it;
ostringstream dummy;
@@ -1443,8 +1456,9 @@ bool CombinedCondition::isTrue() {
}
result_t Instruction::create(const string contextPath, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue) {
result_t Instruction::create(const string contextPath, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, Condition* condition, const string type, vector<string>::iterator& it,
const vector<string>::iterator end, Instruction*& returnValue) {
// type[,argument]* (type already skipped by caller)
bool singleton = false;
if ((singleton=(type == "load")) || type == "include") {
@@ -1494,7 +1508,8 @@ result_t LoadInstruction::execute(MessageMap* messages, ostringstream& log, Cond
log << ", ";
}
if (result != RESULT_OK) {
log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \"" << getDestination() << "\": " << getResultCode(result);
log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \""
<< getDestination() << "\": " << getResultCode(result);
return result;
}
log << (isSingleton() ? "loaded \"" : "included \"") << m_filename << "\" for \"" << getDestination() << "\"";
@@ -1532,10 +1547,10 @@ result_t MessageMap::add(Message* message, bool storeByName) {
Message* other = getFirstAvailable(keyIt->second, message);
if (other != NULL) {
if (!conditional) {
return RESULT_ERR_DUPLICATE; // duplicate key
return RESULT_ERR_DUPLICATE; // duplicate key
}
if (!other->isConditional()) {
return RESULT_ERR_DUPLICATE; // duplicate key
return RESULT_ERR_DUPLICATE; // duplicate key
}
}
}
@@ -1553,23 +1568,26 @@ result_t MessageMap::add(Message* message, bool storeByName) {
if (nameIt != m_messagesByName.end()) {
vector<Message*>* messages = &nameIt->second;
if (!message->isConditional() || !messages->front()->isConditional()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
}
}
m_messagesByName[nameKey].push_back(message);
nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit
nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
if (nameIt == m_messagesByName.end()) {
m_messagesByName[nameKey].push_back(message); // always store first message without circuit (in order of circuit name)
// always store first message without circuit (in order of circuit name)
m_messagesByName[nameKey].push_back(message);
} else {
vector<Message*>* messages = &nameIt->second;
Message* first = messages->front();
if (circuit < first->getCircuit()) {
m_messagesByName[nameKey].at(0) = message; // always store first message without circuit (in order of circuit name)
// always store first message without circuit (in order of circuit name)
m_messagesByName[nameKey].at(0) = message;
} else if (m_addAll || (conditional && first->isConditional())) {
m_messagesByName[nameKey].push_back(message); // store further messages only if both are conditional or if storing everything
// store further messages only if both are conditional or if storing everything
m_messagesByName[nameKey].push_back(message);
}
}
m_messageCount++;
@@ -1618,22 +1636,26 @@ result_t MessageMap::addDefaultFromFile(vector< vector<string> >& defaults, vect
}
if (row.size() > 1 && defaultCircuit.length() > 0) {
if (row[1].length() == 0) {
row[1] = defaultCircuit+defaultSuffix; // set default circuit and suffix: "circuit[.suffix]"
row[1] = defaultCircuit+defaultSuffix; // set default circuit and suffix: "circuit[.suffix]"
} else if (row[1][0] == '#') {
row[1] = defaultCircuit+defaultSuffix+row[1]; // move security suffix behind default circuit and suffix: "circuit[.suffix]#security"
} else if (defaultSuffix.length() > 0 && row[1].find_last_of('.') == string::npos) { // circuit suffix not yet present
// move security suffix behind default circuit and suffix: "circuit[.suffix]#security"
row[1] = defaultCircuit+defaultSuffix+row[1];
} else if (defaultSuffix.length() > 0 && row[1].find_last_of('.') == string::npos) {
// circuit suffix not yet present
size_t pos = row[1].find_first_of('#');
if (pos == string::npos) {
row[1] += defaultSuffix; // append default suffix: "circuit.suffix"
row[1] += defaultSuffix; // append default suffix: "circuit.suffix"
} else {
row[1] = row[1].substr(0, pos)+defaultSuffix+row[1].substr(pos); // insert default suffix: "circuit.suffix#security"
// insert default suffix: "circuit.suffix#security"
row[1] = row[1].substr(0, pos)+defaultSuffix+row[1].substr(pos);
}
}
}
if (row.size() > 5 && defaultDest.length() > 0 && row[5].length() == 0) {
row[5] = defaultDest; // set default destination
row[5] = defaultDest; // set default destination
}
return FileReader::addDefaultFromFile(defaults, row, begin, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
return FileReader::addDefaultFromFile(defaults, row, begin, defaultDest, defaultCircuit, defaultSuffix, filename,
lineNo);
}
result_t MessageMap::readConditions(string& types, const string& filename, Condition*& condition) {
@@ -1665,7 +1687,7 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
m_lastError = "derive condition with values "+key.substr(pos)+" failed";
return RESULT_ERR_INVALID_ARG;
}
m_conditions[key] = add; // store derived condition
m_conditions[key] = add; // store derived condition
}
}
if (add == NULL) {
@@ -1688,7 +1710,7 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
}
}
if (store) {
m_conditions[combinedkey] = condition; // store combined condition
m_conditions[combinedkey] = condition; // store combined condition
}
}
}
@@ -1696,8 +1718,8 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
}
result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo) {
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string& filename, unsigned int lineNo) {
vector<string>::iterator restart = begin;
string types = *restart;
Condition* condition = NULL;
@@ -1709,7 +1731,8 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
// instruction
types = types.substr(1);
Instruction* instruction = NULL;
result_t result = Instruction::create(filename, defaultDest, defaultCircuit, defaultSuffix, condition, types, ++begin, end, instruction);
result_t result = Instruction::create(filename, defaultDest, defaultCircuit, defaultSuffix, condition, types,
++begin, end, instruction);
if (instruction == NULL || result != RESULT_OK) {
m_lastError = "invalid instruction";
return result;
@@ -1745,13 +1768,13 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
if (result == RESULT_OK) {
result = add(message);
if (result == RESULT_ERR_DUPLICATE_NAME) {
begin = restart+3; // mark name as invalid
begin = restart+3; // mark name as invalid
} else if (result == RESULT_ERR_DUPLICATE) {
begin = restart+8; // mark ID as invalid
begin = restart+8; // mark ID as invalid
}
}
if (result != RESULT_OK) {
delete message; // delete all remaining messages on error
delete message; // delete all remaining messages on error
}
}
if (result != RESULT_OK) {
@@ -1906,9 +1929,9 @@ Message* MessageMap::find(const string& circuit, const string& name, const bool
if (i == 0) {
key = string(isPassive ? "P" : (isWrite ? "W" : "R")) + lcircuit + FIELD_SEPARATOR + lname;
} else if (lcircuit.length() == 0) {
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit
} else {
continue; // not allowed without circuit
continue; // not allowed without circuit
}
map<string, vector<Message*> >::iterator it = m_messagesByName.find(key);
if (it != m_messagesByName.end()) {
@@ -1940,7 +1963,7 @@ deque<Message*> MessageMap::findAll(const string& circuit, const string& name, c
}
}
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
if (it->first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-"
if (it->first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-"
continue;
}
for (vector<Message*>::iterator msgIt = it->second.begin(); msgIt != it->second.end(); msgIt++) {
@@ -2032,7 +2055,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
}
if ((key & ID_SOURCE_MASK) != 0) {
key &= ~ID_SOURCE_MASK;
it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master
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);
if (message) {
@@ -2044,7 +2067,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
key &= ~ID_SOURCE_MASK;
}
if (withRead) {
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read
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);
if (message) {
@@ -2053,7 +2076,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
}
}
if (withWrite) {
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write
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);
if (message) {
@@ -2102,7 +2125,7 @@ void MessageMap::clear() {
// free message instances by name
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
vector<Message*> nameMessages = it->second;
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
for (vector<Message*>::iterator nit = nameMessages.begin(); nit != nameMessages.end(); nit++) {
Message* message = *nit;
map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey());
@@ -2163,14 +2186,14 @@ Message* MessageMap::getNextPoll() {
m_pollMessages.pop();
ret->m_pollCount++;
time(&(ret->m_lastPollTime));
m_pollMessages.push(ret); // re-insert at new position
m_pollMessages.push(ret); // re-insert at new position
return ret;
}
void MessageMap::dump(ostream& output, bool withConditions) {
bool first = true;
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
if (it->first[0] == '-') { // skip instances stored multiple times (key starting with "-")
if (it->first[0] == '-') { // skip instances stored multiple times (key starting with "-")
continue;
}
if (m_addAll) {
@@ -2204,4 +2227,4 @@ void MessageMap::dump(ostream& output, bool withConditions) {
}
}
} // namespace ebusd
} // namespace ebusd
+91 -64
View File
@@ -100,7 +100,7 @@ class MessageMap;
*/
class Message {
friend class MessageMap;
public:
public:
/**
* Construct a new instance.
* @param circuit the optional circuit name.
@@ -126,7 +126,7 @@ class Message {
Condition* condition = NULL);
private:
private:
/**
* Construct a new scan @a Message instance.
* @param circuit the circuit name, or empty for not storing by name.
@@ -145,7 +145,7 @@ class Message {
DataField* data, const bool deleteData);
public:
public:
/**
* Destructor.
*/
@@ -229,7 +229,8 @@ class Message {
* @param circuit the new circuit name, or empty to use the current circuit name.
* @return the derived @a Message instance.
*/
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN,
const string circuit = "");
/**
* Derive a new @a Message from this message.
@@ -400,7 +401,7 @@ class Message {
const unsigned char dstAddress = SYN, unsigned char index = 0);
protected:
protected:
/**
* Prepare a part of the master data @a SymbolString for sending (everything including NN).
* @param master the master data @a SymbolString for writing symbols to.
@@ -412,7 +413,7 @@ class Message {
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
public:
public:
/**
* Prepare the slave @a SymbolString for sending an answer to the bus.
* @param input the @a istringstream to parse the formatted value(s) from.
@@ -527,7 +528,7 @@ class Message {
virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
protected:
protected:
/** the optional circuit name. */
const string m_circuit;
@@ -618,7 +619,7 @@ class Message {
* A chained @a Message that needs more than one read/write on the bus to collect/send the data.
*/
class ChainedMessage : public Message {
public:
public:
/**
* Construct a new instance.
* @param circuit the optional circuit name.
@@ -647,7 +648,8 @@ class ChainedMessage : public Message {
virtual ~ChainedMessage();
// @copydoc
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN,
const string circuit = "");
// @copydoc
virtual unsigned char getIdLength() const { return (unsigned char)(m_ids[0].size() - 2); }
@@ -662,12 +664,12 @@ class ChainedMessage : public Message {
virtual unsigned char getCount() { return (unsigned char)m_ids.size(); }
protected:
protected:
// @copydoc
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
public:
public:
// @copydoc
virtual result_t storeLastData(SymbolString& master, SymbolString& slave);
@@ -675,12 +677,12 @@ class ChainedMessage : public Message {
virtual result_t storeLastData(const PartType partType, SymbolString& data, unsigned char index);
protected:
protected:
// @copydoc
virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
private:
private:
/** the primary, secondary, and optional further ID bytes for each part of the chain. */
const vector< vector<unsigned char> > m_ids;
@@ -723,7 +725,7 @@ struct compareMessagePriority : binary_function<Message*, Message*, bool> {
*/
class MessagePriorityQueue
: public priority_queue<Message*, vector<Message*>, compareMessagePriority> {
public:
public:
/**
* Add data to the queue and ensure it is contained only once.
* @param __x the element to add.
@@ -744,7 +746,7 @@ class MessagePriorityQueue
* An abstract condition based on the value of one or more @a Message instances.
*/
class Condition {
public:
public:
/**
* Construct a new instance.
*/
@@ -766,7 +768,8 @@ class Condition {
* @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code.
*/
static result_t create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue);
static result_t create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end,
string defaultDest, string defaultCircuit, SimpleCondition*& returnValue);
/**
* Derive a new @a SimpleCondition from this condition.
@@ -796,7 +799,8 @@ class Condition {
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL) = 0;
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
void (*readMessageFunc)(Message* message) = NULL) = 0;
/**
* Check and return whether this condition is fulfilled.
@@ -805,7 +809,7 @@ class Condition {
virtual bool isTrue() = 0;
protected:
protected:
/** the system time when the condition was last checked, 0 for never. */
time_t m_lastCheckTime;
@@ -818,20 +822,23 @@ class Condition {
* A simple @a Condition based on the value of one @a Message.
*/
class SimpleCondition : public Condition {
public:
public:
/**
* Construct a new instance.
* @param condName the name of the condition.
* @param refName the reference name for dumping.
* @param circuit the circuit name.
* @param name the message name, or empty for scan message.
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message).
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination
* as well as scan message).
* @param field the field name.
* @param hasValues whether a value has to be checked against.
*/
SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues = false)
SimpleCondition(const string condName, const string refName, const string circuit, const string name,
const unsigned char dstAddress, const string field, const bool hasValues = false)
: Condition(),
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress),
m_field(field), m_hasValues(hasValues), m_message(NULL) { }
/**
* Destructor.
@@ -848,7 +855,8 @@ class SimpleCondition : public Condition {
virtual CombinedCondition* combineAnd(Condition* other);
// @copydoc
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
void (*readMessageFunc)(Message* message) = NULL);
// @copydoc
virtual bool isTrue();
@@ -860,7 +868,7 @@ class SimpleCondition : public Condition {
virtual bool isNumeric() { return true; }
protected:
protected:
/**
* Check the values against the field in the @a Message.
* @param message the @a Message to check against.
@@ -873,7 +881,7 @@ class SimpleCondition : public Condition {
string m_matchedValue;
private:
private:
/** the condition name. */
const string m_condName;
@@ -886,7 +894,8 @@ class SimpleCondition : public Condition {
/** the message name, or empty for scan message. */
const string m_name;
/** the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message). */
/** the override destination address, or @a SYN (only for @a Message without specific destination as well as scan
* message). */
const unsigned char m_dstAddress;
/** the field name, or empty for first field. */
@@ -904,7 +913,7 @@ class SimpleCondition : public Condition {
* A simple @a Condition based on the numeric value of one @a Message.
*/
class SimpleNumericCondition : public SimpleCondition {
public:
public:
/**
* Construct a new instance.
* @param condName the name of the condition.
@@ -915,7 +924,8 @@ class SimpleNumericCondition : public SimpleCondition {
* @param field the field name.
* @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check.
*/
SimpleNumericCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
SimpleNumericCondition(const string condName, const string refName, const string circuit, const string name,
const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
: SimpleCondition(condName, refName, circuit, name, dstAddress, field, true),
m_valueRanges(valueRanges) { }
@@ -925,12 +935,12 @@ class SimpleNumericCondition : public SimpleCondition {
virtual ~SimpleNumericCondition() {}
protected:
protected:
// @copydoc
virtual bool checkValue(Message* message, const string field);
private:
private:
/** the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */
const vector<unsigned int> m_valueRanges;
};
@@ -940,7 +950,7 @@ class SimpleNumericCondition : public SimpleCondition {
* A simple @a Condition based on the string value of one @a Message.
*/
class SimpleStringCondition : public SimpleCondition {
public:
public:
/**
* Construct a new instance.
* @param condName the name of the condition.
@@ -951,7 +961,8 @@ class SimpleStringCondition : public SimpleCondition {
* @param field the field name.
* @param values the valid values.
*/
SimpleStringCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<string> values)
SimpleStringCondition(const string condName, const string refName, const string circuit, const string name,
const unsigned char dstAddress, const string field, const vector<string> values)
: SimpleCondition(condName, refName, circuit, name, dstAddress, field, true),
m_values(values) { }
@@ -964,12 +975,12 @@ class SimpleStringCondition : public SimpleCondition {
virtual bool isNumeric() { return false; }
protected:
protected:
// @copydoc
virtual bool checkValue(Message* message, const string field);
private:
private:
/** the valid values. */
const vector<string> m_values;
};
@@ -979,7 +990,7 @@ class SimpleStringCondition : public SimpleCondition {
* A @a Condition combining two or more @a SimpleCondition instances with a logical and.
*/
class CombinedCondition : public Condition {
public:
public:
/**
* Construct a new instance.
*/
@@ -998,13 +1009,14 @@ class CombinedCondition : public Condition {
virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; }
// @copydoc
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
void (*readMessageFunc)(Message* message) = NULL);
// @copydoc
virtual bool isTrue();
private:
private:
/** the @a Condition instances used. */
vector<Condition*> m_conditions;
};
@@ -1014,17 +1026,20 @@ class CombinedCondition : public Condition {
* An abstract instruction based on the value of one or more @a Message instances.
*/
class Instruction {
public:
public:
/**
* Construct a new instance.
* @param condition the @a Condition this instruction requires, or null.
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be
* executed for the same source file.
* @param defaultDest the default destination address, or empty.
* @param defaultCircuit the default circuit name, or empty.
* @param defaultSuffix the default circuit name suffix (starting with a "."), or empty.
*/
Instruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix)
: m_condition(condition), m_singleton(singleton), m_defaultDest(defaultDest), m_defaultCircuit(defaultCircuit), m_defaultSuffix(defaultSuffix) { }
Instruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix)
: m_condition(condition), m_singleton(singleton), m_defaultDest(defaultDest), m_defaultCircuit(defaultCircuit),
m_defaultSuffix(defaultSuffix) { }
/**
* Destructor.
@@ -1044,8 +1059,9 @@ class Instruction {
* @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code.
*/
static result_t create(const string contextPath, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue);
static result_t create(const string contextPath, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, Condition* condition, const string type, vector<string>::iterator& it,
const vector<string>::iterator end, Instruction*& returnValue);
/**
* Return the @a Condition this instruction requires.
@@ -1054,8 +1070,10 @@ class Instruction {
Condition* getCondition() { return m_condition; }
/**
* Return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
* @return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
* Return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed
* for the same source file.
* @return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed
* for the same source file.
*/
bool isSingleton() { return m_singleton; }
@@ -1075,15 +1093,16 @@ class Instruction {
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition) = 0;
private:
private:
/** the @a Condition this instruction requires, or null. */
Condition* m_condition;
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file. */
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the
* same source file. */
bool m_singleton;
protected:
protected:
/** the default destination address, or empty. */
const string m_defaultDest;
@@ -1099,17 +1118,20 @@ class Instruction {
* An @a Instruction allowing to load another file.
*/
class LoadInstruction : public Instruction {
public:
public:
/**
* Construct a new instance.
* @param condition the @a Condition this instruction requires, or null.
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be
* executed for the same source file.
* @param defaultDest the default destination address (may be overwritten by file name), or empty.
* @param defaultCircuit the default circuit name (may be overwritten by file name), or empty.
* @param defaultSuffix the default circuit name suffix (starting with a ".", may be overwritten by file name), or empty.
* @param defaultSuffix the default circuit name suffix (starting with a ".", may be overwritten by file name), or
* empty.
* @param filename the name of the file to load.
*/
LoadInstruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix, const string filename)
LoadInstruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string filename)
: Instruction(condition, singleton, defaultDest, defaultCircuit, defaultSuffix), m_filename(filename) { }
/**
@@ -1121,7 +1143,7 @@ class LoadInstruction : public Instruction {
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition);
private:
private:
/** the name of the file to load. */
const string m_filename;
};
@@ -1131,7 +1153,7 @@ class LoadInstruction : public Instruction {
* Holds a map of all known @a Message instances.
*/
class MessageMap : public FileReader {
public:
public:
/**
* Construct a new instance.
* @param addAll whether to add all messages, even if duplicate.
@@ -1174,8 +1196,8 @@ class MessageMap : public FileReader {
// @copydoc
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo);
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
const string& defaultSuffix, const string& filename, unsigned int lineNo);
/**
* Get the scan @a Message instance for the specified address.
@@ -1219,7 +1241,8 @@ class MessageMap : public FileReader {
/**
* Get the loaded files for a participant.
* @param address the slave address.
* @return the name of the file(s) loaded for the participant (separated by comma and enclosed in double quotes), or empty.
* @return the name of the file(s) loaded for the participant (separated by comma and enclosed in double quotes),
* or empty.
*/
string getLoadedFiles(unsigned char address);
@@ -1246,15 +1269,19 @@ class MessageMap : public FileReader {
* Find all active get @a Message instances for the specified circuit and name.
* @param circuit the circuit name, or empty for any.
* @param name the message name, or empty for any.
* @param completeMatch false to also include messages where the circuit and name matches only a part of the given circuit and name (default true).
* @param completeMatch false to also include messages where the circuit and name matches only a part of the given
* circuit and name (default true).
* @param withRead true to include read messages (default true).
* @param withWrite true to include write messages (default false).
* @param withPassive true to include passive messages (default false).
* @return the found @a Message instances.
* @param completeMatchIgnoreCircuitSuffix ignore different circuit suffixes (after "#") for completeMatch.
* @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).
* @param since the start time from which to add updates (inclusive, also removes messages with unset destination 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.
* @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).
* @param since the start time from which to add updates (inclusive, also removes messages with unset destination
* 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.
* Note: the caller may not free the returned instances.
*/
deque<Message*> findAll(const string& circuit, const string& name, const bool completeMatch = true,
@@ -1344,7 +1371,7 @@ class MessageMap : public FileReader {
void dump(ostream& output, bool withConditions = false);
private:
private:
/** whether to add all messages, even if duplicate. */
const bool m_addAll;
@@ -1382,6 +1409,6 @@ class MessageMap : public FileReader {
map<string, vector<Instruction*> > m_instructions;
};
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_MESSAGE_H_
#endif // LIB_EBUS_MESSAGE_H_
+1 -1
View File
@@ -58,4 +58,4 @@ const char* getResultCode(result_t resultCode) {
}
}
} // namespace ebusd
} // namespace ebusd
+8 -8
View File
@@ -46,14 +46,14 @@ enum result_t {
RESULT_ERR_EOF = -7, //!< end of input reached
RESULT_ERR_INVALID_ARG = -8, //!< invalid argument
RESULT_ERR_INVALID_NUM = -9, //!< invalid numeric argument
RESULT_ERR_INVALID_ADDR = -10, //!< invalid address
RESULT_ERR_INVALID_ADDR = -10, //!< invalid address
RESULT_ERR_INVALID_POS = -11, //!< invalid position
RESULT_ERR_OUT_OF_RANGE = -12, //!< argument value out of valid range
RESULT_ERR_INVALID_PART = -13, //!< invalid part type value
RESULT_ERR_MISSING_TYPE = -14, //!< missing data type
RESULT_ERR_INVALID_LIST = -15, //!< invalid value list
RESULT_ERR_OUT_OF_RANGE = -12, //!< argument value out of valid range
RESULT_ERR_INVALID_PART = -13, //!< invalid part type value
RESULT_ERR_MISSING_TYPE = -14, //!< missing data type
RESULT_ERR_INVALID_LIST = -15, //!< invalid value list
RESULT_ERR_DUPLICATE = -16, //!< duplicate entry
RESULT_ERR_DUPLICATE_NAME = -17, //!< duplicate entry (name)
RESULT_ERR_DUPLICATE_NAME = -17, //!< duplicate entry (name)
RESULT_ERR_BUS_LOST = -18, //!< arbitration lost
RESULT_ERR_CRC = -19, //!< CRC error
@@ -72,6 +72,6 @@ enum result_t {
*/
const char* getResultCode(result_t resultCode);
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_RESULT_H_
#endif // LIB_EBUS_RESULT_H_
+11 -11
View File
@@ -66,7 +66,7 @@ void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol) {
push_back(data[i], isEscaped, addCrc);
}
if (addCrc) {
push_back(m_crc, false, false); // add CRC
push_back(m_crc, false, false); // add CRC
}
}
@@ -78,12 +78,12 @@ result_t SymbolString::parseHex(const string& str, const bool isEscaped) {
unsigned long value = strtoul(strBegin, &strEnd, 16);
if (strEnd == NULL || strEnd != strBegin+2 || value > 0xff) {
return RESULT_ERR_INVALID_NUM; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
push_back((unsigned char)value, isEscaped, addCrc);
}
if (addCrc) {
push_back(m_crc, false, false); // add CRC
push_back(m_crc, false, false); // add CRC
}
return RESULT_OK;
}
@@ -97,16 +97,16 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
if (m_unescapeState == 0 && unescape && previousEscape) {
if (!skipLastSymbol || i+1 < m_data.size()) {
if (value == 0x00) {
sstr << "a9"; // ESC
sstr << "a9"; // ESC
} else if (value == 0x01) {
sstr << "aa"; // SYN
sstr << "aa"; // SYN
} else {
sstr << "XX"; // invalid escape sequence
sstr << "XX"; // invalid escape sequence
}
}
previousEscape = false;
} else if (m_unescapeState == 0 && unescape && value == ESC) {
previousEscape = true; // escape sequence not yet finished
previousEscape = true; // escape sequence not yet finished
} else if (!skipLastSymbol || i+1 < m_data.size()) {
sstr << nouppercase << setw(2) << hex
<< setfill('0') << static_cast<unsigned>(value);
@@ -116,7 +116,7 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
}
result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) {
if (m_unescapeState == 0) { // store escaped data
if (m_unescapeState == 0) { // store escaped data
if (!isEscaped && value == ESC) {
m_data.push_back(ESC);
m_data.push_back(0x00);
@@ -141,7 +141,7 @@ result_t SymbolString::push_back(const unsigned char value, const bool isEscaped
}
if (!isEscaped) {
if (m_unescapeState != 1) {
return RESULT_ERR_ESC; // invalid unescape state
return RESULT_ERR_ESC; // invalid unescape state
}
m_data.push_back(value);
if (updateCRC) {
@@ -171,7 +171,7 @@ result_t SymbolString::push_back(const unsigned char value, const bool isEscaped
m_unescapeState = 1;
return RESULT_OK;
}
return RESULT_ERR_ESC; // invalid escape sequence
return RESULT_ERR_ESC; // invalid escape sequence
}
if (value == ESC) {
if (updateCRC) {
@@ -261,4 +261,4 @@ bool isValidAddress(unsigned char addr, bool allowBroadcast) {
return addr != SYN && addr != ESC && (allowBroadcast || addr != BROADCAST);
}
} // namespace ebusd
} // namespace ebusd
+29 -15
View File
@@ -68,18 +68,19 @@ namespace ebusd {
using std::string;
using std::vector;
static const unsigned char ESC = 0xA9; //!< escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA
/** escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA. */
static const unsigned char ESC = 0xA9;
static const unsigned char SYN = 0xAA; //!< synchronization symbol
static const unsigned char ACK = 0x00; //!< positive acknowledge
static const unsigned char NAK = 0xFF; //!< negative acknowledge
static const unsigned char BROADCAST = 0xFE; //!< the broadcast destination address
static const unsigned char BROADCAST = 0xFE; //!< the broadcast destination address
/**
* A string of escaped or unescaped bus symbols.
*/
class SymbolString {
public:
public:
/**
* Creates a new empty escaped or unescaped instance.
* @param escaped whether to create an escaped instance.
@@ -114,24 +115,35 @@ class SymbolString {
* @param index the index of the symbol to return.
* @return the reference to the symbol at the specified index.
*/
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) { m_data.resize(index+1, 0); } return m_data[index]; }
unsigned char& operator[](const size_t index) {
if (index >= m_data.size()) {
m_data.resize(index+1, 0);
}
return m_data[index];
}
/**
* Return whether this instance is equal to the other instance.
* @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).
* @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;
}
/**
* Return whether this instance is different from the other instance.
* @param other the other instance.
* @return true if this instance is different from the other instance.
*/
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;
}
/**
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master address and ending with the CRC).
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master
* address and ending with the CRC).
* @param other the other instance.
* @return 0 if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols),
* 1 if this instance is completely different to the other instance,
@@ -159,8 +171,8 @@ class SymbolString {
* @param isEscaped whether the symbol is escaped.
* @param updateCRC whether to update the calculated CRC in @a m_crc.
* @return RESULT_OK if another symbol was appended,
* 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_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 = true, const bool updateCRC = true);
@@ -188,7 +200,7 @@ class SymbolString {
void clear(const bool escape) { m_data.clear(); m_unescapeState = escape ? 0 : 1; m_crc = 0; }
private:
private:
/**
* Hidden copy constructor.
* @param str the @a SymbolString to copy from.
@@ -234,14 +246,16 @@ bool isSlaveMaster(unsigned char addr);
/**
* Return the slave address associated with the specified address (master or slave).
* @param addr the address to check.
* @return the slave address, or SYN if the specified address is neither a master address nor a slave address of a master.
* @return the slave address, or SYN if the specified address is neither a master address nor a slave address of a
* master.
*/
unsigned char getSlaveAddress(unsigned char addr);
/**
* Return the master address associated with the specified address (master or slave).
* @param addr the address to check.
* @return the master address, or SYN if the specified address is neither a master address nor a slave address of a master.
* @return the master address, or SYN if the specified address is neither a master address nor a slave address of a
* master.
*/
unsigned char getMasterAddress(unsigned char addr);
@@ -260,6 +274,6 @@ unsigned char getMasterNumber(unsigned char addr);
*/
bool isValidAddress(unsigned char addr, bool allowBroadcast = true);
} // namespace ebusd
} // namespace ebusd
#endif // LIB_EBUS_SYMBOL_H_
#endif // LIB_EBUS_SYMBOL_H_
+53 -37
View File
@@ -59,7 +59,8 @@ int main() {
{"x,,str:10", " ", "10fe07000a20202020202020202020", "00", ""},
{"x,,str:10", "", "10fe07000a20202020202020202020", "00", "R"},
{"x,,str:11", "", "10fe07000a20202020202020202020", "00", "rW"},
{"x,,str:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778", "00", ""},
{"x,,str:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778",
"00", ""},
{"x,,str:*", "abcde", "10fe0700056162636465", "00", ""},
{"x,,str,2", "", "", "", "c"},
{"x,,str:10,=dummy", "", "10fe07000a48616c6c6f2044752120", "00", "W"},
@@ -73,7 +74,8 @@ int main() {
{"x,,nts:10", "", "10fe07000a00000000000000000000", "00", ""},
{"x,,nts:10", "abc", "10fe07000a6162630065666768696a", "00", "W"},
{"x,,nts:11", "", "10fe07000a20202020202020202020", "00", "rW"},
{"x,,nts:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778", "00", ""},
{"x,,nts:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778",
"00", ""},
{"x,,nts:*", "abcde", "10fe0700056162636465", "00", "W"},
{"x,,nts:*", "abcde", "10fe070006616263646500", "00", ""},
{"x,,nts,2", "", "", "", "c"},
@@ -86,9 +88,9 @@ int main() {
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"},
{"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
{"x,,bda", "26.10.2014", "10fe07000426100614", "00", ""}, // Sunday
{"x,,bda", "01.01.2000", "10fe07000401010500", "00", ""}, // Saturday
{"x,,bda", "31.12.2099", "10fe07000431120399", "00", ""}, // Thursday
{"x,,bda", "26.10.2014", "10fe07000426100614", "00", ""}, // Sunday
{"x,,bda", "01.01.2000", "10fe07000401010500", "00", ""}, // Saturday
{"x,,bda", "31.12.2099", "10fe07000431120399", "00", ""}, // Thursday
{"x,,bda", "-.-.-", "10fe070004ffff00ff", "00", ""},
{"x,,bda", "", "10fe07000432100014", "00", "rw"},
{"x,,bda:3", "26.10.2014", "10fe070003261014", "00", ""},
@@ -97,9 +99,9 @@ int main() {
{"x,,bda:3", "-.-.-", "10fe070003ffffff", "00", ""},
{"x,,bda:3", "", "10fe070003321299", "00", "rw"},
{"x,,bda,2", "", "", "", "c"},
{"x,,hda", "26.10.2014", "10fe0700041a0a070e", "00", ""}, // Sunday
{"x,,hda", "01.01.2000", "10fe07000401010600", "00", ""}, // Saturday
{"x,,hda", "31.12.2099", "10fe0700041f0c0463", "00", ""}, // Thursday
{"x,,hda", "26.10.2014", "10fe0700041a0a070e", "00", ""}, // Sunday
{"x,,hda", "01.01.2000", "10fe07000401010600", "00", ""}, // Saturday
{"x,,hda", "31.12.2099", "10fe0700041f0c0463", "00", ""}, // Thursday
{"x,,hda", "-.-.-", "10fe070004ffff00ff", "00", ""},
{"x,,hda", "", "10fe070004200c0463", "00", "rw"},
{"x,,hda:3", "26.10.2014", "10fe0700031a0a0e", "00", ""},
@@ -301,7 +303,7 @@ int main() {
{"uin10,uin,-10", "", "", "", "t"}, // template
{"x,,uin10", "380", "10feffff022600", "00", ""}, // template reference
{"x,,uin10,-10", "3800", "10feffff022600", "00", ""}, // template reference, valid divider product
{"x,,uin10,10", "", "", "", "c"}, // template reference, invalid divider product
{"x,,uin10,10", "", "", "", "c"}, // template reference, invalid divider product
{"x,,sin", "-90", "10feffff02a6ff", "00", ""},
{"x,,sin", "0", "10feffff020000", "00", ""},
{"x,,sin", "-1", "10feffff02ffff", "00", ""},
@@ -427,35 +429,43 @@ int main() {
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvv"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvvn"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "vj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "vj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "j"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108",
"00", "vj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108",
"00", "j"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert",
"\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108",
"00", "vvvj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1}", "10feffff0108", "00", "vnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00", "nj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert",
"\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00",
"vvvnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00",
"nj"},
{"x,,uch,1=test;2=high;3=off;0x10=on", "on", "10feffff0110", "00", ""},
{"x,s,uch", "3", "1050ffff00", "0103", ""},
{"x,,d2b,,°C,Aussentemperatur", "x=18.004 °C [Aussentemperatur]", "10fe0700090112", "00", "vvv"},
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun", "10fe0700085804212610061406", "00", ""}, // combination
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "0;1", "10feffff0120", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "0;0", "10feffff0100", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9", "10feffff020009", "00", ""}, // bit combination
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9", "10feffff03800109", "00", ""}, // bit combination
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0", "ff75b50900", "0104", ""}, // bits
{"temp,d2b,,°C,Aussentemperatur", "", "", "", "t"}, // template with relative pos
{"x,,temp", "18.004", "10fe0700020112", "00", ""}, // reference to template
{"x,,temp,10", "1.8004", "10fe0700020112", "00", ""}, // reference to template, valid divider product
{"x,,temp,-10", "", "", "", "c"}, // reference to template, invalid divider product
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun", "10fe0700085804212610061406", "00", ""}, // combination
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "0;1", "10feffff0120", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "0;0", "10feffff0100", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9", "10feffff020009", "00", ""}, // bit combination
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9", "10feffff03800109", "00", ""}, // bit combination
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0", "ff75b50900", "0104", ""}, // bits
{"temp,d2b,,°C,Aussentemperatur", "", "", "", "t"}, // template with relative pos
{"x,,temp", "18.004", "10fe0700020112", "00", ""}, // reference to template
{"x,,temp,10", "1.8004", "10fe0700020112", "00", ""}, // reference to template, valid divider product
{"x,,temp,-10", "", "", "", "c"}, // reference to template, invalid divider product
{"relrel,d2b,,,,y,d1c", "", "", "", "t"}, // template struct with relative pos
{"x,,relrel", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template struct
{"x,,relrel", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template struct
{"trelrel,temp;temp", "", "", "", "t"}, // template struct with relative pos and ref to templates
{"x,,trelrel", "18.004;19.008", "10fe07000401120213", "00", ""}, // reference to template struct
{"x,,temp,,,,y,,d1c", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template, normal def
{"x,,temp;HEX:2", "18.004;13 14", "10fe07000401121314", "00", ""}, // reference to template and base type
{"x,,temp;HEX:2", "temp=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
{"x,,temp:degrees;HEX:2", "degrees=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
{"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
{"x,,temp;HEX:2", "18.004;13 14", "10fe07000401121314", "00", ""}, // reference to template and base type
{"x,,temp;HEX:2", "temp=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
// reference to template and base type
{"x,,temp:degrees;HEX:2", "degrees=18.004;=13 14", "10fe07000401121314", "00", "v"},
};
DataFieldTemplates* templates = new DataFieldTemplates();
DataField* fields = NULL;
@@ -510,7 +520,8 @@ int main() {
fields = NULL;
}
vector<string>::iterator it = entries.begin();
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate,
!isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
if (failedCreate) {
if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
@@ -555,18 +566,21 @@ int main() {
SymbolString writeMstr(false);
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
if (result != RESULT_OK) {
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) << endl;
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result)
<< endl;
error = true;
}
SymbolString writeSstr(false);
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
if (result != RESULT_OK) {
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) << endl;
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result)
<< endl;
error = true;
}
result = fields->read(pt_masterData, mstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, false);
if (result >= RESULT_OK) {
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, !output.str().empty());
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1,
!output.str().empty());
}
if (failedRead) {
if (result >= RESULT_OK) {
@@ -607,7 +621,9 @@ int main() {
error = true;
} else {
bool match = mstr == writeMstr && sstr == writeSstr;
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " + sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " "
+ writeSstr.getDataStr(true, false));
}
}
delete fields;
+76 -36
View File
@@ -47,7 +47,7 @@ DataFieldTemplates* templates = NULL;
namespace ebusd {
DataFieldTemplates* getTemplates(const string filename) {
if (filename == "") { // avoid compiler warning
if (filename == "") { // avoid compiler warning
return templates;
}
return templates;
@@ -73,13 +73,23 @@ int main() {
{"pumpstate,UCH,0=off;1=on;2=overrun,,Pumpenstatus", "", "", "", "template"},
{"tempsensor,temp;sensor,,Temperatursensor", "", "", "", "template"},
{"tempsensorc,temp;sensorc,,Temperatursensor", "", "", "", "template"},
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate", "28.0;24.0;4.938;35.0;41.0;4", "ff08b5110101", "093830f00446520400ff", "d"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor", "temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00},\n \"sensor\": {\"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00, \"unit\": \"field unit\", \"comment\": \"field comment\"},\n \"sensor\": {\"value\": \"ok\", \"comment\": \"Fühlerstatus\"}", "ff25b509030d2800", "0320ff00", "mJ"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,D2C,,°C,Temperatur,,,sensor", "\n \"0\": {\"name\": \"\", \"value\": -14.00},\n \"1\": {\"name\": \"sensor\", \"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"},
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate",
"28.0;24.0;4.938;35.0;41.0;4", "ff08b5110101", "093830f00446520400ff", "d"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor",
"temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
"temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
"\n \"temp\": {\"value\": -14.00},\n \"sensor\": {\"value\": \"ok\"}", "ff25b509030d2800", "0320ff00",
"mj"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
"\n \"temp\": {\"value\": -14.00, \"unit\": \"field unit\", \"comment\": \"field comment\"},\n"
" \"sensor\": {\"value\": \"ok\", \"comment\": \"Fühlerstatus\"}", "ff25b509030d2800", "0320ff00", "mJ"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor",
"temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,D2C,,°C,Temperatur,,,sensor",
"\n \"0\": {\"name\": \"\", \"value\": -14.00},\n \"1\": {\"name\": \"sensor\", \"value\": \"ok\"}",
"ff25b509030d2800", "0320ff00", "mj"},
{"r,,name,,,25,B509,0d2800,,,tempsensorc", "-14.00", "ff25b509030d2800", "0320ff55", "m"},
{"r,,name,,,25,B509,0d28,,m,sensorc,,,,,,temp", "-14.00", "ff25b509030d2855", "0220ff", "m"},
{"u,,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"},
@@ -92,20 +102,27 @@ int main() {
{"r,ehp,time,,,08;10,b509,0d2800,,,time", "", "", "", "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"},
{"r,700,date,,,15,b524,020000003400,,,IGN:4,,,,,,date", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"},
{"r,700,time,,,15,b524,030000003500,,,IGN:4,,,,,,HTI", "12:29:06", "ff15b52406030000003500", "07030035000c1d06", "d"},
{"r,700,date,,,15,b524,020000003400,,,IGN:4,,,,,,date", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f",
"d"},
{"r,700,time,,,15,b524,030000003500,,,IGN:4,,,,,,HTI", "12:29:06", "ff15b52406030000003500", "07030035000c1d06",
"d"},
{"", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"},
{"", "12:29:06", "ff15b52406030000003500", "07030035000c1d06", "d"},
{"w,700,date,,,15,b524,020000003400,,,date", "23.11.2015", "ff15b52409020000003400170b0f", "00", "m"},
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "3;15:00:17", "ff08b509040d280003", "0311000f", "mdi"},
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f", "mD"},
{"u,ehp,ActualEnvironmentPower,Energiebezug,,08,B509,29BA00,,s,IGN:2,,,,,s,power", "8", "1008b5090329ba00", "03ba0008", "pm"},
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f",
"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"},
{"u,ehp,hwTankTemp,Speichertemperatur IST,,25,B509,290000,,,IGN:2,,,,,,tempsensor", "", "", "", "M"},
{"", "55.50;ok", "1025b50903290000", "050000780300", "d"},
{"r,ehp,datetime,Datum Uhrzeit,,50,B504,00,,,dcfstate,,,,time,,BTI,,,,date,,BDA,,,,temp,,temp2", "valid;08:24:51;31.12.2014;-0.875", "1050b5040100", "0a035124083112031420ff", "md" },
{"r,ehp,bad,invalid pos,,50,B5ff,000102,,m,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
{"r,ehp,bad,invalid pos,,50,B5ff,,,s,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
{"r,ehp,datetime,Datum Uhrzeit,,50,B504,00,,,dcfstate,,,,time,,BTI,,,,date,,BDA,,,,temp,,temp2",
"valid;08:24:51;31.12.2014;-0.875", "1050b5040100", "0a035124083112031420ff", "md" },
{"r,ehp,bad,invalid pos,,50,B5ff,000102,,m,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "",
"", "", "c" },
{"r,ehp,bad,invalid pos,,50,B5ff,,,s,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,",
"", "", "", "c" },
{"r,ehp,ApplianceCode,,,08,b509,0d4301,,,UCH,", "9", "ff08b509030d4301", "0109", "d" },
{"r,ehp,,,,08,b509,0d", "", "", "", "defaults" },
{"w,ehp,,,,08,b509,0e", "", "", "", "defaults" },
@@ -113,22 +130,39 @@ int main() {
{"[airtowater]r,ehp,notavailable,,,,,0100,,,uch", "1", "", "", "c" },
{"[brinetowater]r,ehp,available,,,,,0100,,,uch", "1", "ff08b509030d0100", "0101", "d" },
{"r,,x,,,,,\"6800\",,,UCH,,,bit0=\"comment, continued comment", "", "", "", "c" },
{"r,,x,,,,,\"6800\",,,UCH,,\"\",\"bit0=\"comment, continued comment\"", "=1 [bit0=\"comment, continued comment]", "ff08b509030d6800", "0101", "mD" },
{"r,ehp,multi,,,,,0001:5;0002;0003,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509030d0001;ff08b509030d0003;ff08b509030d0002", "054142434445;054b4c4d4e4f;05464748494a", "mdC" },
{"r,ehp,multi,,,,,01;02;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509020d01;ff08b509020d03;ff08b509020d02", "084142434445464748;054b4c4d4e4f;02494a", "mdC" },
{"w,ehp,multi,,,,,01:8;02:2;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "mdC" },
{"w,ehp,multi,,,,,01:8;02:2;0304,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "cC" },
{"r,ehp,scan,chained scan,,08,B509,24:9;25;26;27,,,IGN,,,,id4,,STR:28", "21074500100027790000000000N8", "ff08b5090124;ff08b5090125;ff08b5090126;ff08b5090127", "09003231303734353030;09313030303237373930;09303030303030303030;024E38", "mdC" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509030d6900", "03138040", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509030d6900", "0313ffbf", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509030d6900", "03137fff", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509030d6900", "03137fbf", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71", "ff08b509030d6900", "0213ff", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71", "ff08b509030d6900", "0213bf", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70", "ff08b509030d6900", "02137f", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70", "ff08b509030d6900", "02133f", "md" },
{"r,,x,,,,,\"6800\",,,UCH,,\"\",\"bit0=\"comment, continued comment\"", "=1 [bit0=\"comment, continued comment]",
"ff08b509030d6800", "0101", "mD" },
{"r,ehp,multi,,,,,0001:5;0002;0003,longname,,STR:15", "ABCDEFGHIJKLMNO",
"ff08b509030d0001;ff08b509030d0003;ff08b509030d0002", "054142434445;054b4c4d4e4f;05464748494a", "mdC" },
{"r,ehp,multi,,,,,01;02;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509020d01;ff08b509020d03;ff08b509020d02",
"084142434445464748;054b4c4d4e4f;02494a", "mdC" },
{"w,ehp,multi,,,,,01:8;02:2;03,longname,,STR:15", "ABCDEFGHIJKLMNO",
"ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "mdC" },
{"w,ehp,multi,,,,,01:8;02:2;0304,longname,,STR:15", "ABCDEFGHIJKLMNO",
"ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "cC" },
{"r,ehp,scan,chained scan,,08,B509,24:9;25;26;27,,,IGN,,,,id4,,STR:28", "21074500100027790000000000N8",
"ff08b5090124;ff08b5090125;ff08b5090126;ff08b5090127",
"09003231303734353030;09313030303237373930;09303030303030303030;024E38", "mdC" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61",
"ff08b509030d6900", "03138040", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60",
"ff08b509030d6900", "0313ffbf", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61",
"ff08b509030d6900", "03137fff", "md" },
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60",
"ff08b509030d6900", "03137fbf", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71",
"ff08b509030d6900", "0213ff", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71",
"ff08b509030d6900", "0213bf", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70",
"ff08b509030d6900", "02137f", "md" },
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70",
"ff08b509030d6900", "02133f", "md" },
{"r,cir*cuit#level,na*me,com*ment,ff,75,b509,0d", "", "", "", "defaults" },
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH", "r,cirCIRCUITcuit#level,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42", "ff08b509030d0100", "012a", "mDN"},
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH",
"r,cirCIRCUITcuit#level,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42",
"ff08b509030d0100", "012a", "mDN"},
};
templates = new DataFieldTemplates();
MessageMap* messages = new MessageMap();
@@ -174,7 +208,8 @@ int main() {
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": template fields create error: " << getResultCode(result) << endl;
} else if (it != entries.end()) {
cout << "\"" << check[0] << "\": template fields create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
cout << "\"" << check[0] << "\": template fields create error: trailing input "
<< static_cast<unsigned>(entries.end()-it) << endl;
} else {
cout << "\"" << check[0] << "\": create template OK" << endl;
result = templates->add(fields, "", true);
@@ -195,7 +230,8 @@ int main() {
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": defaults read error: " << getResultCode(result) << endl;
} else if (it != entries.end()) {
cout << "\"" << check[0] << "\": defaults read error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
cout << "\"" << check[0] << "\": defaults read error: trailing input "
<< static_cast<unsigned>(entries.end()-it) << endl;
} else {
cout << "\"" << check[0] << "\": read defaults OK" << endl;
if (isCondition) {
@@ -204,7 +240,8 @@ int main() {
} else {
result = messages->resolveConditions();
if (result != RESULT_OK) {
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError() << endl;
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError()
<< endl;
} else {
cout << " resolve conditions OK" << endl;
}
@@ -314,7 +351,8 @@ int main() {
continue;
}
if (it != entries.end()) {
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it)
<< endl;
continue;
}
if (multi && deleteMessages.size() == 1) {
@@ -368,7 +406,8 @@ int main() {
message->dump(output, NULL, true);
output << ": ";
}
result = message->decodeLastData(output, (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false);
result = message->decodeLastData(output,
(decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false);
if (result != RESULT_OK) {
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: "
<< getResultCode(result) << endl;
@@ -399,7 +438,8 @@ int main() {
cout << " \"" << inputStr << "\": prepare OK" << endl;
bool match = writeMstr == *mstrs[0];
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false), writeMstr.getDataStr(true, false));
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false),
writeMstr.getDataStr(true, false));
}
}
+1 -1
View File
@@ -29,4 +29,4 @@
*/
void clockGettime(struct timespec* t);
#endif // LIB_UTILS_CLOCK_H_
#endif // LIB_UTILS_CLOCK_H_
+1 -2
View File
@@ -71,7 +71,6 @@ bool setLogFacilities(const char* facilities) {
newFacilites |= 1 << val;
}
}
//s_lastFacilities = newFacilites;
s_logFacilites = newFacilites;
free(input);
return true;
@@ -81,7 +80,7 @@ bool getLogFacilities(char* buffer) {
if (s_logFacilites == LF_ALL) {
return snprintf(buffer, 48, "%s", facilityNames[lf_COUNT]) != 0;
}
*buffer = 0; // for strcat to work
*buffer = 0; // for strcat to work
bool found = false;
size_t len = 0;
for (int val = 0; val < lf_COUNT; val++) {
+11 -7
View File
@@ -36,12 +36,12 @@ enum LogFacility {
/** the available log levels. */
enum LogLevel {
ll_none = 0, //!< no level at all
ll_none = 0, //!< no level at all
ll_error, //!< error message
ll_notice, //!< important message
ll_info, //!< informational message
ll_debug, //!< debugging message (normally suppressed)
ll_COUNT = 5 //!< number of available log levels
ll_COUNT = 5 //!< number of available log levels
};
/**
@@ -125,15 +125,19 @@ void logWrite(const char* facility, const LogLevel level, const char* message, .
#define logDebug(facility, ...) (needsLog(facility, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
/** A macro for an error message that calls the logging function only if needed. */
#define logOtherError(facility, ...) (needsLog(lf_other, ll_error) ? logWrite(facility, ll_error, __VA_ARGS__) : void(0))
#define logOtherError(facility, ...) \
(needsLog(lf_other, ll_error) ? logWrite(facility, ll_error, __VA_ARGS__) : void(0))
/** A macro for a notice message that calls the logging function only if needed. */
#define logOtherNotice(facility, ...) (needsLog(lf_other, ll_notice) ? logWrite(facility, ll_notice, __VA_ARGS__) : void(0))
#define logOtherNotice(facility, ...) \
(needsLog(lf_other, ll_notice) ? logWrite(facility, ll_notice, __VA_ARGS__) : void(0))
/** A macro for an info message that calls the logging function only if needed. */
#define logOtherInfo(facility, ...) (needsLog(lf_other, ll_info) ? logWrite(facility, ll_info, __VA_ARGS__) : void(0))
#define logOtherInfo(facility, ...) \
(needsLog(lf_other, ll_info) ? logWrite(facility, ll_info, __VA_ARGS__) : void(0))
/** A macro for a debug message that calls the logging function only if needed. */
#define logOtherDebug(facility, ...) (needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
#define logOtherDebug(facility, ...) \
(needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
#endif // LIB_UTILS_LOG_H_
#endif // LIB_UTILS_LOG_H_
+3 -3
View File
@@ -28,7 +28,7 @@
* class to notify other thread per pipe.
*/
class Notify {
public:
public:
/**
* constructs a new instance and do notifying.
*/
@@ -61,7 +61,7 @@ class Notify {
*/
int notify() const { return write(m_sendfd, "1", 1); }
private:
private:
/** file descriptor to watch */
int m_recvfd;
@@ -69,6 +69,6 @@ class Notify {
int m_sendfd;
};
#endif // LIB_UTILS_NOTIFY_H_
#endif // LIB_UTILS_NOTIFY_H_
+5 -5
View File
@@ -34,7 +34,7 @@ using std::list;
*/
template <typename T>
class Queue {
public:
public:
/**
* Constructor.
*/
@@ -52,7 +52,7 @@ class Queue {
}
private:
private:
/**
* Hidden copy constructor.
* @param src the object to copy from.
@@ -60,7 +60,7 @@ class Queue {
Queue(const Queue& src);
public:
public:
/**
* Add an item to the end of queue.
* @param item the item to add.
@@ -141,7 +141,7 @@ class Queue {
}
private:
private:
/** the queue itself */
list<T> m_queue;
@@ -152,4 +152,4 @@ class Queue {
pthread_cond_t m_cond;
};
#endif // LIB_UTILS_QUEUE_H_
#endif // LIB_UTILS_QUEUE_H_
+3 -3
View File
@@ -35,7 +35,7 @@ using std::string;
* Helper class for writing to a rotating file with maximum size.
*/
class RotateFile {
public:
public:
/**
* Construct a new instance.
* @param fileName the name of the file write to.
@@ -72,7 +72,7 @@ class RotateFile {
void write(unsigned char* value, unsigned int size, bool received = true);
private:
private:
/** whether writing to the file is enabled. */
bool m_enabled;
@@ -92,5 +92,5 @@ class RotateFile {
uint64_t m_fileSize;
};
#endif // LIB_UTILS_ROTATEFILE_H_
#endif // LIB_UTILS_ROTATEFILE_H_
+6 -6
View File
@@ -38,7 +38,7 @@ using std::string;
* class for low level tcp socket operations. (open, close, send, receive).
*/
class TCPSocket {
public:
public:
/** grant access for friend class TCPClient */
friend class TCPClient;
@@ -91,7 +91,7 @@ class TCPSocket {
bool isValid();
private:
private:
/** file descriptor from tcp socket */
int m_sfd;
@@ -113,7 +113,7 @@ class TCPSocket {
* class to initiate a tcp socket connection to a listening server.
*/
class TCPClient {
public:
public:
/**
* initiate a tcp socket connection to a listening server.
* @param server the server name or ip address to connect.
@@ -127,7 +127,7 @@ class TCPClient {
* class for a tcp based network server.
*/
class TCPServer {
public:
public:
/**
* creates a new instance of a listening tcp server.
* @param port the tcp port.
@@ -160,7 +160,7 @@ class TCPServer {
int getFD() const { return m_lfd; }
private:
private:
/** file descriptor from listening tcp socket */
int m_lfd;
@@ -174,5 +174,5 @@ class TCPServer {
bool m_listening;
};
#endif // LIB_UTILS_TCPSOCKET_H_
#endif // LIB_UTILS_TCPSOCKET_H_
+6 -6
View File
@@ -27,7 +27,7 @@
* wrapper class for pthread.
*/
class Thread {
public:
public:
/**
* constructor.
*/
@@ -76,14 +76,14 @@ class Thread {
pthread_t self() { return m_threadid; }
protected:
protected:
/**
* Thread entry method to be overridden by derived class.
*/
virtual void run() = 0;
private:
private:
/**
* Enter the Thread loop by calling run().
*/
@@ -107,7 +107,7 @@ class Thread {
* A @a Thread that can be waited on.
*/
class WaitThread : public Thread {
public:
public:
/**
* Constructor.
*/
@@ -132,7 +132,7 @@ class WaitThread : public Thread {
bool Wait(int seconds);
private:
private:
/** the mutex for waiting. */
pthread_mutex_t m_mutex;
@@ -140,4 +140,4 @@ class WaitThread : public Thread {
pthread_cond_t m_cond;
};
#endif // LIB_UTILS_THREAD_H_
#endif // LIB_UTILS_THREAD_H_
+11 -11
View File
@@ -39,20 +39,20 @@ using std::endl;
/** A structure holding all program options. */
struct options {
const char* server; //!< ebusd server host (name or ip) [localhost]
uint16_t port; //!< ebusd server port [8888]
const char* server; //!< ebusd server host (name or ip) [localhost]
uint16_t port; //!< ebusd server port [8888]
char* const *args; //!< arguments to pass to ebusd
unsigned int argCount; //!< number of arguments to pass to ebusd
char* const *args; //!< arguments to pass to ebusd
unsigned int argCount; //!< number of arguments to pass to ebusd
};
/** the program options. */
static struct options opt = {
"localhost", // server
8888, // port
"localhost", // server
8888, // port
NULL, // args
0 // argCount
NULL, // args
0 // argCount
};
/** the version string of the program. */
@@ -92,14 +92,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
unsigned int port;
switch (key) {
// Device settings:
case 's': // --server=localhost
case 's': // --server=localhost
if (arg == NULL || arg[0] == 0) {
argp_error(state, "invalid server");
return EINVAL;
}
opt->server = arg;
break;
case 'p': // --port=8888
case 'p': // --port=8888
port = strtoul(arg, &strEnd, 10);
if (strEnd == NULL || strEnd == arg || *strEnd != 0 || port < 1 || port > 65535) {
argp_error(state, "invalid port");
@@ -156,7 +156,7 @@ string fetchData(TCPSocket* socket, bool& listening) {
#endif
#endif
while(true) {
while (true) {
#ifdef HAVE_PPOLL
// wait for new fd event
ret = ppoll(fds, nfds, &tdiff, NULL);
+8 -8
View File
@@ -42,18 +42,18 @@ using ebusd::Device;
/** A structure holding all program options. */
struct options {
const char* device; //!< device to write to [/dev/ttyUSB60]
unsigned int time; //!< delay between bytes in us [10000]
const char* device; //!< device to write to [/dev/ttyUSB60]
unsigned int time; //!< delay between bytes in us [10000]
const char* dumpFile; //!< dump file to read
const char* dumpFile; //!< dump file to read
};
/** the program options. */
static struct options opt = {
"/dev/ttyUSB60", // device
10000, // time
"/dev/ttyUSB60", // device
10000, // time
"/tmp/ebus_dump.bin", // dumpFile
"/tmp/ebus_dump.bin", // dumpFile
};
/** the version string of the program. */
@@ -98,14 +98,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
char* strEnd = NULL;
switch (key) {
// Device settings:
case 'd': // --device=/dev/ttyUSB60
case 'd': // --device=/dev/ttyUSB60
if (arg == NULL || arg[0] == 0) {
argp_error(state, "invalid device");
return EINVAL;
}
opt->device = arg;
break;
case 't': // --time=10000
case 't': // --time=10000
opt->time = (unsigned int)strtoul(arg, &strEnd, 10);
if (strEnd == NULL || strEnd == arg || *strEnd != 0 || opt->time < 1000 || opt->time > 100000000) {
argp_error(state, "invalid time");