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