code style
This commit is contained in:
+76
-61
@@ -89,12 +89,14 @@ bool PollRequest::notify(result_t result, SymbolString& slave) {
|
||||
}
|
||||
ostringstream output;
|
||||
if (result == RESULT_OK) {
|
||||
result = m_message->decodeLastData(output); // decode data
|
||||
result = m_message->decodeLastData(output); // decode data
|
||||
}
|
||||
if (result < RESULT_OK) {
|
||||
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), getResultCode(result));
|
||||
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(),
|
||||
getResultCode(result));
|
||||
} else {
|
||||
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), output.str().c_str());
|
||||
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(),
|
||||
output.str().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -105,11 +107,12 @@ result_t ScanRequest::prepare(unsigned char ownMasterAddress) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
unsigned char dstAddress = m_slaves.front();
|
||||
if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
|
||||
if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
|
||||
m_busHandler->setScanResult(dstAddress, "");
|
||||
}
|
||||
istringstream input;
|
||||
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index);
|
||||
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress,
|
||||
m_index);
|
||||
if (result >= RESULT_OK) {
|
||||
logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getDataStr().c_str());
|
||||
}
|
||||
@@ -123,12 +126,12 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
|
||||
Message* message = m_messageMap->getScanMessage(dstAddress);
|
||||
if (message != NULL) {
|
||||
m_message = message;
|
||||
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
|
||||
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
|
||||
}
|
||||
} else if (m_message->getDstAddress() == SYN) {
|
||||
m_message = m_message->derive(dstAddress, true);
|
||||
m_messageMap->add(m_message);
|
||||
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
|
||||
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
|
||||
}
|
||||
result = m_message->storeLastData(pt_slaveData, slave, m_index);
|
||||
if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
|
||||
@@ -139,7 +142,7 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
|
||||
}
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
|
||||
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
|
||||
}
|
||||
}
|
||||
if (result < RESULT_OK) {
|
||||
@@ -151,14 +154,14 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
|
||||
} else {
|
||||
logError(lf_bus, "scan %2.2x failed (%d slaves left): %s", dstAddress, m_slaves.size(), getResultCode(result));
|
||||
}
|
||||
m_messages.clear(); // skip remaining secondary messages
|
||||
m_messages.clear(); // skip remaining secondary messages
|
||||
} else if (m_messages.empty()) {
|
||||
if (!m_slaves.empty()) {
|
||||
m_slaves.pop_front();
|
||||
}
|
||||
logNotice(lf_bus, "scan %2.2x completed (%d slaves left)", dstAddress, m_slaves.size());
|
||||
}
|
||||
if (m_messages.empty()) { // last message for this address
|
||||
if (m_messages.empty()) { // last message for this address
|
||||
m_busHandler->setScanResult(dstAddress, m_scanResult.str());
|
||||
}
|
||||
if (m_slaves.empty()) {
|
||||
@@ -176,7 +179,7 @@ bool ScanRequest::notify(result_t result, SymbolString& slave) {
|
||||
m_messages.pop_front();
|
||||
if (prepare(m_master[0]) < RESULT_OK) {
|
||||
m_busHandler->setScanFinished();
|
||||
return false; // give up
|
||||
return false; // give up
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -337,10 +340,10 @@ result_t BusHandler::handleSymbol() {
|
||||
|
||||
case bs_ready:
|
||||
if (m_currentRequest != NULL) {
|
||||
setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up
|
||||
setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up
|
||||
} else if (m_remainLockCount == 0) {
|
||||
startRequest = m_nextRequests.peek();
|
||||
if (startRequest == NULL && m_pollInterval > 0) { // check for poll/scan
|
||||
if (startRequest == NULL && m_pollInterval > 0) { // check for poll/scan
|
||||
time_t now;
|
||||
time(&now);
|
||||
if (m_lastPoll == 0 || difftime(now, m_lastPoll) > m_pollInterval) {
|
||||
@@ -359,7 +362,7 @@ result_t BusHandler::handleSymbol() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (startRequest != NULL) { // initiate arbitration
|
||||
if (startRequest != NULL) { // initiate arbitration
|
||||
sendSymbol = m_ownMasterAddress;
|
||||
sending = true;
|
||||
}
|
||||
@@ -385,7 +388,7 @@ result_t BusHandler::handleSymbol() {
|
||||
|
||||
case bs_sendCmd:
|
||||
if (m_currentRequest != NULL) {
|
||||
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command
|
||||
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
@@ -406,7 +409,7 @@ result_t BusHandler::handleSymbol() {
|
||||
|
||||
case bs_sendRes:
|
||||
if (m_answer) {
|
||||
sendSymbol = m_response[m_nextSendPos]; // escaped response
|
||||
sendSymbol = m_response[m_nextSendPos]; // escaped response
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
@@ -431,7 +434,7 @@ result_t BusHandler::handleSymbol() {
|
||||
sending = false;
|
||||
timeout = SYN_TIMEOUT;
|
||||
if (startRequest != NULL && m_nextRequests.remove(startRequest)) {
|
||||
m_currentRequest = startRequest; // force the failed request to be notified
|
||||
m_currentRequest = startRequest; // force the failed request to be notified
|
||||
}
|
||||
setState(bs_skip, result);
|
||||
}
|
||||
@@ -471,9 +474,10 @@ result_t BusHandler::handleSymbol() {
|
||||
time(&now);
|
||||
if (result != RESULT_OK) {
|
||||
if (sending && startRequest != NULL && m_nextRequests.remove(startRequest)) {
|
||||
m_currentRequest = startRequest; // force the failed request to be notified
|
||||
m_currentRequest = startRequest; // force the failed request to be notified
|
||||
}
|
||||
if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1) // at least one full second has passed since last received symbol
|
||||
if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1)
|
||||
// at least one full second has passed since last received symbol
|
||||
|| m_state == bs_noSignal) {
|
||||
return setState(bs_noSignal, result);
|
||||
}
|
||||
@@ -485,7 +489,7 @@ result_t BusHandler::handleSymbol() {
|
||||
if (!sending && m_remainLockCount > 0 && m_command.size() != 1) {
|
||||
m_remainLockCount--;
|
||||
} else if (!sending && m_remainLockCount == 0 && m_command.size() == 1) {
|
||||
m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority)
|
||||
m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority)
|
||||
}
|
||||
return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN);
|
||||
}
|
||||
@@ -507,20 +511,20 @@ result_t BusHandler::handleSymbol() {
|
||||
}
|
||||
m_currentRequest = startRequest;
|
||||
// check arbitration
|
||||
if (recvSymbol == sendSymbol) { // arbitration successful
|
||||
if (recvSymbol == sendSymbol) { // arbitration successful
|
||||
m_nextSendPos = 1;
|
||||
m_repeat = false;
|
||||
return setState(bs_sendCmd, RESULT_OK);
|
||||
}
|
||||
// arbitration lost. if same priority class found, try again after next AUTO-SYN
|
||||
m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try
|
||||
m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try
|
||||
if ((recvSymbol & 0x0f) != (sendSymbol & 0x0f) && m_lockCount > m_remainLockCount) {
|
||||
// if different priority class found, try again after N AUTO-SYN symbols (at least next AUTO-SYN)
|
||||
m_remainLockCount = m_lockCount;
|
||||
}
|
||||
setState(m_state, RESULT_ERR_BUS_LOST); // try again later
|
||||
setState(m_state, RESULT_ERR_BUS_LOST); // try again later
|
||||
}
|
||||
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
|
||||
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
@@ -529,14 +533,16 @@ result_t BusHandler::handleSymbol() {
|
||||
|
||||
case bs_recvCmd:
|
||||
headerLen = 4;
|
||||
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; // header symbols are never escaped
|
||||
// header symbols are never escaped
|
||||
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff;
|
||||
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
|
||||
unsigned char dstAddress = m_command[1];
|
||||
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); // header symbols are never escaped
|
||||
// header symbols are never escaped
|
||||
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC();
|
||||
if (m_commandCrcValid) {
|
||||
if (dstAddress == BROADCAST) {
|
||||
receiveCompleted();
|
||||
@@ -570,7 +576,7 @@ result_t BusHandler::handleSymbol() {
|
||||
if (isMaster(m_currentRequest->m_master[1])) {
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
}
|
||||
} else if (isMaster(m_command[1])) { // header symbols are never escaped
|
||||
} else if (isMaster(m_command[1])) { // header symbols are never escaped
|
||||
receiveCompleted();
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
@@ -599,7 +605,7 @@ result_t BusHandler::handleSymbol() {
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
|
||||
m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC();
|
||||
if (m_responseCrcValid) {
|
||||
if (m_currentRequest != NULL) {
|
||||
@@ -681,14 +687,14 @@ result_t BusHandler::handleSymbol() {
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
}
|
||||
if (isMaster(m_command[1])) {
|
||||
receiveCompleted(); // decode command and store value
|
||||
receiveCompleted(); // decode command and store value
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
|
||||
m_nextSendPos = 0;
|
||||
m_repeat = false;
|
||||
Message* message;
|
||||
istringstream input; // TODO create input from database of internal variables
|
||||
istringstream input; // TODO create input from database of internal variables
|
||||
message = m_messages->find(m_command);
|
||||
if (message == NULL) {
|
||||
message = m_messages->find(m_command, true);
|
||||
@@ -697,13 +703,14 @@ result_t BusHandler::handleSymbol() {
|
||||
}
|
||||
}
|
||||
if (message == NULL || message->isWrite()) {
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG); // don't know this request or definition has wrong direction, deny
|
||||
// don't know this request or definition has wrong direction, deny
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
}
|
||||
if (message == m_messages->getScanMessage(m_ownSlaveAddress)) {
|
||||
input.str(SCAN_ANSWER);
|
||||
}
|
||||
// build response and store in m_response for sending back to requesting master
|
||||
m_response.clear(true); // escape while sending response
|
||||
m_response.clear(true); // escape while sending response
|
||||
result = message->prepareSlave(input, m_response);
|
||||
if (result != RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
@@ -739,7 +746,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
if (result == RESULT_ERR_BUS_LOST && m_currentRequest->m_busLostRetries < m_busLostRetries) {
|
||||
logDebug(lf_bus, "%s during %s, retry", getResultCode(result), getStateCode(m_state));
|
||||
m_currentRequest->m_busLostRetries++;
|
||||
m_nextRequests.push(m_currentRequest); // repeat
|
||||
m_nextRequests.push(m_currentRequest); // repeat
|
||||
m_currentRequest = NULL;
|
||||
} else if (state == bs_sendSyn || (result != RESULT_OK && !firstRepetition)) {
|
||||
logDebug(lf_bus, "notify request: %s", getResultCode(result));
|
||||
@@ -748,7 +755,8 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
addSeenAddress(dstAddress);
|
||||
}
|
||||
bool restart = m_currentRequest->notify(
|
||||
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes) ? RESULT_ERR_TIMEOUT : result, m_response);
|
||||
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes)
|
||||
? RESULT_ERR_TIMEOUT : result, m_response);
|
||||
if (restart) {
|
||||
m_currentRequest->m_busLostRetries = 0;
|
||||
m_nextRequests.push(m_currentRequest);
|
||||
@@ -761,11 +769,11 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
}
|
||||
}
|
||||
|
||||
if (state == bs_noSignal) { // notify all requests
|
||||
m_response.clear(false); // notify with empty response
|
||||
if (state == bs_noSignal) { // notify all requests
|
||||
m_response.clear(false); // notify with empty response
|
||||
while ((m_currentRequest = m_nextRequests.pop()) != NULL) {
|
||||
bool restart = m_currentRequest->notify(RESULT_ERR_NO_SIGNAL, m_response);
|
||||
if (restart) { // should not occur with no signal
|
||||
if (restart) { // should not occur with no signal
|
||||
m_currentRequest->m_busLostRetries = 0;
|
||||
m_nextRequests.push(m_currentRequest);
|
||||
} else if (m_currentRequest->m_deleteOnFinish) {
|
||||
@@ -780,7 +788,8 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
return result;
|
||||
}
|
||||
if (result < RESULT_OK || (result != RESULT_OK && state == bs_skip)) {
|
||||
logDebug(lf_bus, "%s during %s, switching to %s", getResultCode(result), getStateCode(m_state), getStateCode(state));
|
||||
logDebug(lf_bus, "%s during %s, switching to %s", getResultCode(result), getStateCode(m_state),
|
||||
getStateCode(state));
|
||||
} else if (m_currentRequest != NULL || state == bs_sendCmd || state == bs_sendResAck || state == bs_sendSyn) {
|
||||
logDebug(lf_bus, "switching from %s to %s", getStateCode(m_state), getStateCode(state));
|
||||
}
|
||||
@@ -794,7 +803,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
if (state == bs_ready || state == bs_skip) {
|
||||
m_command.clear();
|
||||
m_commandCrcValid = false;
|
||||
m_response.clear(false); // unescape while receiving response
|
||||
m_response.clear(false); // unescape while receiving response
|
||||
m_responseCrcValid = false;
|
||||
m_nextSendPos = 0;
|
||||
}
|
||||
@@ -883,7 +892,7 @@ void BusHandler::receiveCompleted() {
|
||||
if (message) {
|
||||
key = message->getKey();
|
||||
} else {
|
||||
key = Message::createKey(m_command, 4); // up to 4 DD bytes
|
||||
key = Message::createKey(m_command, 4); // up to 4 DD bytes
|
||||
}
|
||||
m_grabbedMessages[key].setLastData(m_command, m_response);
|
||||
}
|
||||
@@ -893,7 +902,8 @@ void BusHandler::receiveCompleted() {
|
||||
} else if (master) {
|
||||
logNotice(lf_update, "unknown MM cmd: %s", m_command.getDataStr().c_str());
|
||||
} else {
|
||||
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getDataStr().c_str(), m_response.getDataStr().c_str());
|
||||
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getDataStr().c_str(),
|
||||
m_response.getDataStr().c_str());
|
||||
}
|
||||
} else {
|
||||
m_messages->invalidateCache(message);
|
||||
@@ -905,18 +915,21 @@ void BusHandler::receiveCompleted() {
|
||||
result = message->decodeLastData(output);
|
||||
}
|
||||
if (result < RESULT_OK) {
|
||||
logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(), m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result));
|
||||
logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(),
|
||||
m_command.getDataStr().c_str(), m_response.getDataStr().c_str(), getResultCode(result));
|
||||
} else {
|
||||
string data = output.str();
|
||||
if (m_answer && dstAddress == (master ? m_ownMasterAddress : m_ownSlaveAddress)) {
|
||||
logNotice(lf_update, "self-update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, data.c_str()); // TODO store in database of internal variables
|
||||
} else if (message->getDstAddress() == SYN) { // any destination
|
||||
if (message->getSrcAddress() == SYN) { // any destination and any source
|
||||
logNotice(lf_update, "update %s %s QQ=%2.2x ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, dstAddress, data.c_str());
|
||||
logNotice(lf_update, "self-update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress,
|
||||
data.c_str()); // TODO store in database of internal variables
|
||||
} else if (message->getDstAddress() == SYN) { // any destination
|
||||
if (message->getSrcAddress() == SYN) { // any destination and any source
|
||||
logNotice(lf_update, "update %s %s QQ=%2.2x ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress,
|
||||
dstAddress, data.c_str());
|
||||
} else {
|
||||
logNotice(lf_update, "update %s %s ZZ=%2.2x: %s", circuit.c_str(), name.c_str(), dstAddress, data.c_str());
|
||||
}
|
||||
} else if (message->getSrcAddress() == SYN) { // any source
|
||||
} else if (message->getSrcAddress() == SYN) { // any source
|
||||
logNotice(lf_update, "update %s %s QQ=%2.2x: %s", circuit.c_str(), name.c_str(), srcAddress, data.c_str());
|
||||
} else {
|
||||
logNotice(lf_update, "update %s %s: %s", circuit.c_str(), name.c_str(), data.c_str());
|
||||
@@ -930,7 +943,7 @@ result_t BusHandler::startScan(bool full) {
|
||||
for (deque<Message*>::iterator it = messages.begin(); it < messages.end(); it++) {
|
||||
Message* message = *it;
|
||||
if (message->getPrimaryCommand() == 0x07 && message->getSecondaryCommand() == 0x04) {
|
||||
messages.erase(it--); // query pb 0x07 / sb 0x04 only once
|
||||
messages.erase(it--); // query pb 0x07 / sb 0x04 only once
|
||||
}
|
||||
}
|
||||
|
||||
@@ -941,12 +954,12 @@ result_t BusHandler::startScan(bool full) {
|
||||
m_scanResults.clear();
|
||||
|
||||
deque<unsigned char> slaves;
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
if (!isValidAddress(slave, false) || isMaster(slave)) {
|
||||
continue;
|
||||
}
|
||||
if (!full && (m_seenAddresses[slave]&SEEN) == 0) {
|
||||
unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already
|
||||
unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already
|
||||
if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -985,7 +998,7 @@ void BusHandler::formatScanResult(ostringstream& output) {
|
||||
output << static_cast<unsigned>(m_runningScans) << " scan(s) still running" << endl;
|
||||
}
|
||||
bool first = true;
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
map<unsigned char, string>::iterator it = m_scanResults.find(slave);
|
||||
if (it != m_scanResults.end()) {
|
||||
if (first) {
|
||||
@@ -998,7 +1011,7 @@ void BusHandler::formatScanResult(ostringstream& output) {
|
||||
}
|
||||
if (first) {
|
||||
// fallback to autoscan results
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
if (isValidAddress(slave, false) && !isMaster(slave) && (m_seenAddresses[slave]&SCAN_DONE) != 0) {
|
||||
Message* message = m_messages->getScanMessage(slave);
|
||||
if (message != NULL && message->getLastUpdateTime() > 0) {
|
||||
@@ -1018,8 +1031,8 @@ void BusHandler::formatScanResult(ostringstream& output) {
|
||||
void BusHandler::formatSeenInfo(ostringstream& output) {
|
||||
unsigned char address = 0;
|
||||
for (int index = 0; index < 256; index++, address++) {
|
||||
if (isValidAddress(address, false)
|
||||
&& ((m_seenAddresses[address]&SEEN) != 0 || (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)))) {
|
||||
if (isValidAddress(address, false) && ((m_seenAddresses[address]&SEEN) != 0
|
||||
|| (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)))) {
|
||||
output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address);
|
||||
unsigned char master;
|
||||
if (isMaster(address)) {
|
||||
@@ -1081,17 +1094,18 @@ result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
|
||||
Message* message = m_messages->getScanMessage(dstAddress);
|
||||
if (message != NULL && message != scanMessage) {
|
||||
scanMessage = message;
|
||||
scanMessage->storeLastData(pt_masterData, master, 0); // update the cache, expected to work since this is a clone
|
||||
// update the cache, expected to work since this is a clone
|
||||
scanMessage->storeLastData(pt_masterData, master, 0);
|
||||
}
|
||||
}
|
||||
if (result != RESULT_ERR_NO_SIGNAL) {
|
||||
m_seenAddresses[dstAddress] |= SCAN_DONE;
|
||||
}
|
||||
}
|
||||
if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
|
||||
if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
|
||||
return result;
|
||||
}
|
||||
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
|
||||
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
|
||||
}
|
||||
|
||||
bool BusHandler::enableGrab(bool enable) {
|
||||
@@ -1110,7 +1124,8 @@ void BusHandler::formatGrabResult(const bool unknown, ostringstream& output) {
|
||||
output << "grab disabled";
|
||||
} else {
|
||||
bool first = true;
|
||||
for (map<uint64_t, GrabbedMessage>::iterator it = m_grabbedMessages.begin(); it != m_grabbedMessages.end(); it++) {
|
||||
for (map<uint64_t, GrabbedMessage>::iterator it = m_grabbedMessages.begin(); it != m_grabbedMessages.end();
|
||||
it++) {
|
||||
if (it->second.dump(unknown, m_messages, first, output)) {
|
||||
first = false;
|
||||
}
|
||||
@@ -1122,7 +1137,7 @@ unsigned char BusHandler::getNextScanAddress(unsigned char lastAddress, bool& sc
|
||||
if (lastAddress == SYN) {
|
||||
return SYN;
|
||||
}
|
||||
while (++lastAddress != 0) { // 0 is known to be a master
|
||||
while (++lastAddress != 0) { // 0 is known to be a master
|
||||
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) {
|
||||
continue;
|
||||
}
|
||||
@@ -1147,4 +1162,4 @@ void BusHandler::setScanConfigLoaded(unsigned char address, string file) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+18
-16
@@ -99,7 +99,7 @@ class BusHandler;
|
||||
class BusRequest {
|
||||
friend class BusHandler;
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param master the escaped master data @a SymbolString to send.
|
||||
@@ -123,7 +123,7 @@ class BusRequest {
|
||||
virtual bool notify(result_t result, SymbolString& slave) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the escaped master data @a SymbolString to send. */
|
||||
SymbolString& m_master;
|
||||
|
||||
@@ -141,7 +141,7 @@ class BusRequest {
|
||||
class PollRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param message the associated @a Message.
|
||||
@@ -165,7 +165,7 @@ class PollRequest : public BusRequest {
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the escaped master data @a SymbolString. */
|
||||
SymbolString m_master;
|
||||
|
||||
@@ -183,7 +183,7 @@ class PollRequest : public BusRequest {
|
||||
class ScanRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param messageMap the @a MessageMap instance.
|
||||
@@ -192,7 +192,8 @@ class ScanRequest : public BusRequest {
|
||||
* @param busHandler the @a BusHandler instance to notify of final scan result.
|
||||
*/
|
||||
ScanRequest(MessageMap* messageMap, deque<Message*> messages, deque<unsigned char> slaves, BusHandler* busHandler)
|
||||
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages), m_slaves(slaves), m_busHandler(busHandler) {
|
||||
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages),
|
||||
m_slaves(slaves), m_busHandler(busHandler) {
|
||||
m_message = m_messages.front();
|
||||
m_messages.pop_front();
|
||||
}
|
||||
@@ -213,7 +214,7 @@ class ScanRequest : public BusRequest {
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the @a MessageMap instance. */
|
||||
MessageMap* m_messageMap;
|
||||
|
||||
@@ -249,7 +250,7 @@ class ScanRequest : public BusRequest {
|
||||
class ActiveBusRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param master the escaped master data @a SymbolString to send.
|
||||
@@ -267,7 +268,7 @@ class ActiveBusRequest : public BusRequest {
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the result of handling the request. */
|
||||
result_t m_result;
|
||||
|
||||
@@ -280,7 +281,7 @@ class ActiveBusRequest : public BusRequest {
|
||||
* Helper class for keeping track of grabbed messages.
|
||||
*/
|
||||
class GrabbedMessage {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -313,7 +314,7 @@ class GrabbedMessage {
|
||||
bool dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the last master @a SymbolString. */
|
||||
SymbolString m_lastMaster;
|
||||
|
||||
@@ -329,7 +330,7 @@ class GrabbedMessage {
|
||||
* Handles input from and output to the bus with respect to the eBUS protocol.
|
||||
*/
|
||||
class BusHandler : public WaitThread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param device the @a Device instance for accessing the bus.
|
||||
@@ -356,7 +357,8 @@ class BusHandler : public WaitThread {
|
||||
m_answer(answer), m_addressConflict(false),
|
||||
m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries),
|
||||
m_transferLatency(transferLatency), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout),
|
||||
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0), m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
|
||||
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0),
|
||||
m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
|
||||
m_generateSynInterval(generateSyn ? SYN_TIMEOUT*getMasterNumber(ownAddress)+SYMBOL_DURATION : 0),
|
||||
m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0),
|
||||
m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0),
|
||||
@@ -513,7 +515,7 @@ class BusHandler : public WaitThread {
|
||||
void setScanConfigLoaded(unsigned char address, string file);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Handle the next symbol on the bus.
|
||||
* @return RESULT_OK on success, or an error code.
|
||||
@@ -653,6 +655,6 @@ class BusHandler : public WaitThread {
|
||||
map<uint64_t, GrabbedMessage> m_grabbedMessages;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_BUSHANDLER_H_
|
||||
#endif // EBUSD_BUSHANDLER_H_
|
||||
|
||||
@@ -71,4 +71,4 @@ void DataSink::notifyUpdate(Message* message) {
|
||||
m_updatedMessages[message]++;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -58,7 +58,7 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
|
||||
* Base class for all kinds of data handlers.
|
||||
*/
|
||||
class DataHandler {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -92,7 +92,7 @@ class DataHandler {
|
||||
* Base class for listening to data updates.
|
||||
*/
|
||||
class DataSink : virtual public DataHandler {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -113,7 +113,7 @@ class DataSink : virtual public DataHandler {
|
||||
virtual bool isDataSink() { return true; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** a map of updated @p Message instances. */
|
||||
map<Message*, int> m_updatedMessages;
|
||||
};
|
||||
@@ -123,7 +123,7 @@ class DataSink : virtual public DataHandler {
|
||||
* Base class providing data to be sent on the bus.
|
||||
*/
|
||||
class DataSource : virtual public DataHandler {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param busHandler the @a BusHandler instance.
|
||||
@@ -140,11 +140,11 @@ class DataSource : virtual public DataHandler {
|
||||
virtual bool isDataSource() { return true; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_DATAHANDLER_H_
|
||||
#endif // EBUSD_DATAHANDLER_H_
|
||||
|
||||
+126
-103
@@ -75,38 +75,38 @@ static bool isDaemon = false;
|
||||
|
||||
/** the program options. */
|
||||
static struct options opt = {
|
||||
"/dev/ttyUSB0", // device
|
||||
false, // noDeviceCheck
|
||||
false, // readOnly
|
||||
false, // initialSend
|
||||
-1, // latency
|
||||
CONFIG_PATH, // configPath
|
||||
false, // scanConfig
|
||||
BROADCAST, // initialScan
|
||||
0, // checkConfig
|
||||
5, // pollInterval
|
||||
0x31, // address
|
||||
false, // answer
|
||||
9400, // acquireTimeout
|
||||
3, // acquireRetries
|
||||
2, // sendRetries
|
||||
SLAVE_RECV_TIMEOUT*5/3, // receiveTimeout
|
||||
0, // masterCount
|
||||
false, // generateSyn
|
||||
false, // foreground
|
||||
false, // enableHex
|
||||
PID_FILE_NAME, // pidFile
|
||||
8888, // port
|
||||
false, // localOnly
|
||||
0, // httpPort
|
||||
"/var/" PACKAGE "/html", // htmlPath
|
||||
PACKAGE_LOGFILE, // logFile
|
||||
false, // logRaw
|
||||
PACKAGE_LOGFILE, // logRawFile
|
||||
100, // logRawSize
|
||||
false, // dump
|
||||
"/tmp/" PACKAGE "_dump.bin", // dumpFile
|
||||
100, // dumpSize
|
||||
"/dev/ttyUSB0", // device
|
||||
false, // noDeviceCheck
|
||||
false, // readOnly
|
||||
false, // initialSend
|
||||
-1, // latency
|
||||
CONFIG_PATH, // configPath
|
||||
false, // scanConfig
|
||||
BROADCAST, // initialScan
|
||||
0, // checkConfig
|
||||
5, // pollInterval
|
||||
0x31, // address
|
||||
false, // answer
|
||||
9400, // acquireTimeout
|
||||
3, // acquireRetries
|
||||
2, // sendRetries
|
||||
SLAVE_RECV_TIMEOUT*5/3, // receiveTimeout
|
||||
0, // masterCount
|
||||
false, // generateSyn
|
||||
false, // foreground
|
||||
false, // enableHex
|
||||
PID_FILE_NAME, // pidFile
|
||||
8888, // port
|
||||
false, // localOnly
|
||||
0, // httpPort
|
||||
"/var/" PACKAGE "/html", // htmlPath
|
||||
PACKAGE_LOGFILE, // logFile
|
||||
false, // logRaw
|
||||
PACKAGE_LOGFILE, // logRawFile
|
||||
100, // logRawSize
|
||||
false, // dump
|
||||
"/tmp/" PACKAGE "_dump.bin", // dumpFile
|
||||
100, // dumpSize
|
||||
};
|
||||
|
||||
/** the @a MessageMap instance, or NULL. */
|
||||
@@ -161,7 +161,10 @@ static const struct argp_option argpoptions[] = {
|
||||
|
||||
{NULL, 0, NULL, 0, "Message configuration options:", 2 },
|
||||
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 },
|
||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR=\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, default is broadcast ident message). If combined with --checkconfig, you can add scan message data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
|
||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
|
||||
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
|
||||
"default is broadcast ident message). If combined with --checkconfig, you can add scan message data as "
|
||||
"arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
|
||||
{"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 },
|
||||
{"dumpconfig", O_DMPCFG, NULL, 0, "Check and dump CSV config files, then stop", 0 },
|
||||
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
||||
@@ -187,8 +190,10 @@ static const struct argp_option argpoptions[] = {
|
||||
|
||||
{NULL, 0, NULL, 0, "Log options:", 5 },
|
||||
{"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon) [" PACKAGE_LOGFILE "]", 0 },
|
||||
{"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main,network,bus,update,all [all]", 0 },
|
||||
{"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error/notice/info/debug [notice]", 0 },
|
||||
{"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main,network,bus,update,all "
|
||||
"[all]", 0 },
|
||||
{"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error/notice/info/debug "
|
||||
"[notice]", 0 },
|
||||
|
||||
{NULL, 0, NULL, 0, "Raw logging options:", 6 },
|
||||
{"lograwdata", O_RAW, NULL, 0, "Log each received/sent byte on the bus", 0 },
|
||||
@@ -224,27 +229,27 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
||||
switch (key) {
|
||||
// Device options:
|
||||
case 'd': // --device=/dev/ttyUSB0
|
||||
case 'd': // --device=/dev/ttyUSB0
|
||||
if (arg == NULL || arg[0] == 0) {
|
||||
argp_error(state, "invalid device");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->device = arg;
|
||||
break;
|
||||
case 'n': // --nodevicecheck
|
||||
case 'n': // --nodevicecheck
|
||||
opt->noDeviceCheck = true;
|
||||
break;
|
||||
case 'r': // --readonly
|
||||
case 'r': // --readonly
|
||||
opt->readOnly = true;
|
||||
if (opt->scanConfig || opt->answer || opt->generateSyn) {
|
||||
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_INISND: // --initsend
|
||||
case O_INISND: // --initsend
|
||||
opt->initialSend = true;
|
||||
break;
|
||||
case O_DEVLAT: // --latency=10000
|
||||
case O_DEVLAT: // --latency=10000
|
||||
opt->latency = parseInt(arg, 10, 0, 200000, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid latency");
|
||||
@@ -253,14 +258,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
|
||||
// Message configuration options:
|
||||
case 'c': // --configpath=/etc/ebusd
|
||||
case 'c': // --configpath=/etc/ebusd
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid configpath");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->configPath = arg;
|
||||
break;
|
||||
case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>)
|
||||
case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>)
|
||||
opt->scanConfig = true;
|
||||
if (opt->readOnly) {
|
||||
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
|
||||
@@ -287,15 +292,15 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case O_CHKCFG: // --checkconfig
|
||||
case O_CHKCFG: // --checkconfig
|
||||
if (opt->checkConfig == 0) {
|
||||
opt->checkConfig = 1;
|
||||
}
|
||||
break;
|
||||
case O_DMPCFG: // --dumpconfig
|
||||
case O_DMPCFG: // --dumpconfig
|
||||
opt->checkConfig = 2;
|
||||
break;
|
||||
case O_POLINT: // --pollinterval=5
|
||||
case O_POLINT: // --pollinterval=5
|
||||
opt->pollInterval = parseInt(arg, 10, 0, 3600, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid pollinterval");
|
||||
@@ -308,56 +313,56 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
|
||||
// eBUS options:
|
||||
case 'a': // --address=31
|
||||
case 'a': // --address=31
|
||||
opt->address = (unsigned char)parseInt(arg, 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK || !isMaster(opt->address)) {
|
||||
argp_error(state, "invalid address");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_ANSWER: // --answer
|
||||
case O_ANSWER: // --answer
|
||||
opt->answer = true;
|
||||
if (opt->readOnly) {
|
||||
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_ACQTIM: // --acquiretimeout=9400
|
||||
case O_ACQTIM: // --acquiretimeout=9400
|
||||
opt->acquireTimeout = parseInt(arg, 10, 1000, 100000, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid acquiretimeout");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_ACQRET: // --acquireretries=3
|
||||
case O_ACQRET: // --acquireretries=3
|
||||
opt->acquireRetries = parseInt(arg, 10, 0, 10, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid acquireretries");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_SNDRET: // --sendretries=2
|
||||
case O_SNDRET: // --sendretries=2
|
||||
opt->sendRetries = parseInt(arg, 10, 0, 10, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid sendretries");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_RCVTIM: // --receivetimeout=25000
|
||||
case O_RCVTIM: // --receivetimeout=25000
|
||||
opt->receiveTimeout = parseInt(arg, 10, 1000, 100000, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid receivetimeout");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_MASCNT: // --numbermasters=0
|
||||
case O_MASCNT: // --numbermasters=0
|
||||
opt->masterCount = parseInt(arg, 10, 0, 25, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid numbermasters");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_GENSYN: // --generatesyn
|
||||
case O_GENSYN: // --generatesyn
|
||||
opt->generateSyn = true;
|
||||
if (opt->readOnly) {
|
||||
argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn");
|
||||
@@ -366,37 +371,37 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
|
||||
// Daemon options:
|
||||
case 'f': // --foreground
|
||||
case 'f': // --foreground
|
||||
opt->foreground = true;
|
||||
break;
|
||||
case O_HEXCMD: // --enablehex
|
||||
case O_HEXCMD: // --enablehex
|
||||
opt->enableHex = true;
|
||||
break;
|
||||
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
|
||||
case O_PIDFIL: // --pidfile=/var/run/ebusd.pid
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid pidfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->pidFile = arg;
|
||||
break;
|
||||
case 'p': // --port=8888
|
||||
case 'p': // --port=8888
|
||||
opt->port = (uint16_t)parseInt(arg, 10, 1, 65535, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid port");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_LOCAL: // --localhost
|
||||
case O_LOCAL: // --localhost
|
||||
opt->localOnly = true;
|
||||
break;
|
||||
case O_HTTPPT: // --httpport=0
|
||||
case O_HTTPPT: // --httpport=0
|
||||
opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid httpport");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_HTMLPA: // --htmlpath=/var/ebusd/html
|
||||
case O_HTMLPA: // --htmlpath=/var/ebusd/html
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid htmlpath");
|
||||
return EINVAL;
|
||||
@@ -405,20 +410,20 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
break;
|
||||
|
||||
// Log options:
|
||||
case 'l': // --logfile=/var/log/ebusd.log
|
||||
case 'l': // --logfile=/var/log/ebusd.log
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid logfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logFile = arg;
|
||||
break;
|
||||
case O_LOGARE: // --logareas=all
|
||||
case O_LOGARE: // --logareas=all
|
||||
if (!setLogFacilities(arg)) {
|
||||
argp_error(state, "invalid logareas");
|
||||
return EINVAL;
|
||||
}
|
||||
break;
|
||||
case O_LOGLEV: // --loglevel=notice
|
||||
case O_LOGLEV: // --loglevel=notice
|
||||
if (!setLogLevel(arg)) {
|
||||
argp_error(state, "invalid loglevel");
|
||||
return EINVAL;
|
||||
@@ -429,14 +434,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case O_RAW: // --lograwdata
|
||||
opt->logRaw = true;
|
||||
break;
|
||||
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
|
||||
case O_RAWFIL: // --lograwdatafile=/var/log/ebusd.log
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid lograwdatafile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->logRawFile = arg;
|
||||
break;
|
||||
case O_RAWSIZ: // --lograwdatasize=100
|
||||
case O_RAWSIZ: // --lograwdatasize=100
|
||||
opt->logRawSize = (unsigned int)parseInt(arg, 10, 1, 1000000, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid lograwdatasize");
|
||||
@@ -449,14 +454,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
case 'D': // --dump
|
||||
opt->dump = true;
|
||||
break;
|
||||
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
|
||||
case O_DMPFIL: // --dumpfile=/tmp/ebusd_dump.bin
|
||||
if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) {
|
||||
argp_error(state, "invalid dumpfile");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpFile = arg;
|
||||
break;
|
||||
case O_DMPSIZ: // --dumpsize=100
|
||||
case O_DMPSIZ: // --dumpsize=100
|
||||
opt->dumpSize = (unsigned int)parseInt(arg, 10, 1, 1000000, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid dumpsize");
|
||||
@@ -514,10 +519,10 @@ void daemonize() {
|
||||
// create pid file and try to lock it
|
||||
pidFile = fopen(opt.pidFile, "w+");
|
||||
|
||||
umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750
|
||||
umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750
|
||||
|
||||
if (pidFile != NULL) {
|
||||
setbuf(pidFile, NULL); // disable buffering
|
||||
setbuf(pidFile, NULL); // disable buffering
|
||||
if (lockf(fileno(pidFile), F_TLOCK, 0) < 0
|
||||
|| fprintf(pidFile, "%d\n", getpid()) <= 0) {
|
||||
fclose(pidFile);
|
||||
@@ -640,7 +645,8 @@ static result_t collectConfigFiles(const string path, const string prefix, const
|
||||
if (hasTemplates) {
|
||||
*hasTemplates = true;
|
||||
}
|
||||
} else if (prefix.length() == 0 || (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
|
||||
} else if (prefix.length() == 0
|
||||
|| (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
|
||||
files.push_back(p);
|
||||
}
|
||||
}
|
||||
@@ -692,7 +698,8 @@ static bool readTemplates(const string path, const string extension, bool availa
|
||||
if (result == RESULT_OK) {
|
||||
logInfo(lf_main, "read templates in %s", path.c_str());
|
||||
} else {
|
||||
logError(lf_main, "error reading templates in %s: %s, last error: %s", path.c_str(), getResultCode(result), templates->getLastError().c_str());
|
||||
logError(lf_main, "error reading templates in %s: %s, last error: %s", path.c_str(), getResultCode(result),
|
||||
templates->getLastError().c_str());
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
@@ -706,7 +713,8 @@ static bool readTemplates(const string path, const string extension, bool availa
|
||||
* @param verbose whether to verbosely log problems.
|
||||
* @return the result code.
|
||||
*/
|
||||
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose) {
|
||||
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive,
|
||||
bool verbose) {
|
||||
vector<string> files, dirs;
|
||||
bool hasTemplates = false;
|
||||
result_t result = collectConfigFiles(path, "", extension, files, &dirs, &hasTemplates);
|
||||
@@ -746,7 +754,8 @@ void readMessage(Message* message) {
|
||||
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||
result_t result = busHandler->readFromBus(message, "");
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "error reading message %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result));
|
||||
logError(lf_main, "error reading message %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,23 +767,27 @@ void readMessage(Message* message) {
|
||||
void executeInstructions(MessageMap* messages, bool verbose) {
|
||||
result_t result = messages->resolveConditions(verbose);
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), messages->getLastError().c_str());
|
||||
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result),
|
||||
messages->getLastError().c_str());
|
||||
}
|
||||
ostringstream log;
|
||||
result = messages->executeInstructions(log, readMessage);
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "error executing instructions: %s, last error: %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
|
||||
logError(lf_main, "error executing instructions: %s, last error: %s, %s", getResultCode(result),
|
||||
messages->getLastError().c_str(), log.str().c_str());
|
||||
} else if (verbose && log.tellp() > 0) {
|
||||
logInfo(lf_main, log.str().c_str());
|
||||
}
|
||||
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
||||
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(),
|
||||
messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
||||
}
|
||||
|
||||
result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) {
|
||||
logInfo(lf_main, "loading configuration files from %s", opt.configPath);
|
||||
messages->clear();
|
||||
s_globalTemplates.clear();
|
||||
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) {
|
||||
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end();
|
||||
it++) {
|
||||
if (it->second != &s_globalTemplates) {
|
||||
delete it->second;
|
||||
}
|
||||
@@ -782,41 +795,44 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
|
||||
}
|
||||
s_templatesByPath.clear();
|
||||
|
||||
result_t result = readConfigFiles(string(opt.configPath), ".csv", messages, (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose);
|
||||
result_t result = readConfigFiles(string(opt.configPath), ".csv", messages,
|
||||
(!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose);
|
||||
if (result == RESULT_OK) {
|
||||
logInfo(lf_main, "read config files");
|
||||
} else {
|
||||
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result), messages->getLastError().c_str());
|
||||
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result),
|
||||
messages->getLastError().c_str());
|
||||
}
|
||||
executeInstructions(messages, verbose);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose) {
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile,
|
||||
bool verbose) {
|
||||
PartType partType;
|
||||
if (isMaster(address)) {
|
||||
address = (unsigned char)(data[0]+5); // slave address of sending master
|
||||
address = (unsigned char)(data[0]+5); // slave address of sending master
|
||||
partType = pt_masterData;
|
||||
if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
|
||||
if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
|
||||
logError(lf_main, "unable to load scan config %2.2x: master part too short", address);
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
} else {
|
||||
partType = pt_slaveData;
|
||||
if (data.size() < 1+1+5+2+2) { // skip NN
|
||||
if (data.size() < 1+1+5+2+2) { // skip NN
|
||||
logError(lf_main, "unable to load scan config %2.2x: slave part too short", address);
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
}
|
||||
DataFieldSet* identFields = DataFieldSet::getIdentFields();
|
||||
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
|
||||
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
|
||||
unsigned int sw, hw;
|
||||
ostringstream out;
|
||||
unsigned char offset = 0;
|
||||
size_t field = 0;
|
||||
result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
|
||||
result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
|
||||
if (result == RESULT_ERR_NOTFOUND) {
|
||||
result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
|
||||
result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
path = out.str();
|
||||
@@ -828,17 +844,17 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
out.str("");
|
||||
out.clear();
|
||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
|
||||
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
ident = out.str();
|
||||
out.str("");
|
||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
|
||||
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
|
||||
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result));
|
||||
@@ -849,14 +865,17 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
|
||||
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), getResultCode(result));
|
||||
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(),
|
||||
getResultCode(result));
|
||||
return result;
|
||||
}
|
||||
if (files.empty()) {
|
||||
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(), prefix.c_str());
|
||||
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(),
|
||||
prefix.c_str());
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
|
||||
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(),
|
||||
prefix.c_str(), getResultCode(result));
|
||||
for (string::iterator it = ident.begin(); it != ident.end(); it++) {
|
||||
if (::isspace(*it)) {
|
||||
ident.erase(it--);
|
||||
@@ -872,7 +891,8 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
unsigned char checkDest;
|
||||
string checkIdent, useCircuit, useSuffix;
|
||||
unsigned int checkSw, checkHw;
|
||||
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
|
||||
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit,
|
||||
useSuffix, checkSw, checkHw)) {
|
||||
continue;
|
||||
}
|
||||
if (address != checkDest || (checkSw != UINT_MAX && sw != checkSw) || (checkHw != UINT_MAX && hw != checkHw)) {
|
||||
@@ -890,10 +910,10 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
if (remain[remain.length()-1] < '0' || remain[remain.length()-1] > '9') {
|
||||
break;
|
||||
}
|
||||
remain.erase(remain.length()-1); // remove trailing digit
|
||||
remain.erase(remain.length()-1); // remove trailing digit
|
||||
}
|
||||
if (!matches) {
|
||||
continue; // IDENT mismatch
|
||||
continue; // IDENT mismatch
|
||||
}
|
||||
match += remain.length();
|
||||
}
|
||||
@@ -905,7 +925,9 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
}
|
||||
|
||||
if (best.empty()) {
|
||||
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d", address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw);
|
||||
logError(lf_main,
|
||||
"unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d",
|
||||
address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw);
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
@@ -916,11 +938,11 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
if (result == RESULT_OK && !files.empty()) {
|
||||
for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
|
||||
string name = *it;
|
||||
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
|
||||
if (name == "_templates.") { // skip templates
|
||||
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
|
||||
if (name == "_templates.") { // skip templates
|
||||
continue;
|
||||
}
|
||||
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
|
||||
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
|
||||
name = *it;
|
||||
result = messages->readFromFile(name, opt.checkConfig);
|
||||
if (result == RESULT_OK) {
|
||||
@@ -934,7 +956,8 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
}
|
||||
result = messages->readFromFile(best, opt.checkConfig, "", ident);
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), ident.c_str(), sw, hw, getResultCode(result));
|
||||
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(),
|
||||
ident.c_str(), sw, hw, getResultCode(result));
|
||||
return result;
|
||||
}
|
||||
logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d", best.c_str(), ident.c_str(), sw, hw);
|
||||
@@ -943,7 +966,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
using namespace ebusd;
|
||||
|
||||
@@ -985,7 +1008,7 @@ int main(int argc, char* argv[]) {
|
||||
logError(lf_main, "invalid scan message %s: %s", arg.c_str(), getResultCode(res));
|
||||
continue;
|
||||
}
|
||||
if (master.size() < 5) { // skip QQ ZZ PB SB NN
|
||||
if (master.size() < 5) { // skip QQ ZZ PB SB NN
|
||||
logError(lf_main, "invalid scan message %s: master part too short", arg.c_str());
|
||||
continue;
|
||||
}
|
||||
@@ -1020,7 +1043,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
if (!opt.foreground) {
|
||||
setLogFile(opt.logFile);
|
||||
daemonize(); // make me daemon
|
||||
daemonize(); // make me daemon
|
||||
}
|
||||
|
||||
// trap signals that we expect to receive
|
||||
|
||||
+40
-36
@@ -31,44 +31,46 @@ namespace ebusd {
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options {
|
||||
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
|
||||
bool noDeviceCheck; //!< skip serial eBUS device test
|
||||
bool readOnly; //!< read-only access to the device
|
||||
bool initialSend; //!< send an initial escape symbol after connecting device
|
||||
int latency; //!< transfer latency in us [0 for USB, 10000 for IP]
|
||||
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
|
||||
bool noDeviceCheck; //!< skip serial eBUS device test
|
||||
bool readOnly; //!< read-only access to the device
|
||||
bool initialSend; //!< send an initial escape symbol after connecting device
|
||||
int latency; //!< transfer latency in us [0 for USB, 10000 for IP]
|
||||
|
||||
const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
|
||||
bool scanConfig; //!< pick configuration files matching initial scan
|
||||
unsigned char initialScan; //!< the initial address to scan for scanconfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address)
|
||||
int checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
|
||||
int pollInterval; //!< poll interval in seconds, 0 to disable [5]
|
||||
const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
|
||||
bool scanConfig; //!< pick configuration files matching initial scan
|
||||
/** the initial address to scan for scanconfig
|
||||
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
||||
unsigned char initialScan;
|
||||
int checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
|
||||
int pollInterval; //!< poll interval in seconds, 0 to disable [5]
|
||||
|
||||
unsigned char address; //!< own bus address [31]
|
||||
bool answer; //!< answer to requests from other masters
|
||||
int acquireTimeout; //!< bus acquisition timeout in us [9400]
|
||||
int acquireRetries; //!< number of retries for bus acquisition [3]
|
||||
int sendRetries; //!< number of retries for failed sends [2]
|
||||
int receiveTimeout; //!< timeout for receiving answer from slave in us [25000]
|
||||
int masterCount; //!< expected number of masters for arbitration [0]
|
||||
bool generateSyn; //!< enable AUTO-SYN symbol generation
|
||||
unsigned char address; //!< own bus address [31]
|
||||
bool answer; //!< answer to requests from other masters
|
||||
int acquireTimeout; //!< bus acquisition timeout in us [9400]
|
||||
int acquireRetries; //!< number of retries for bus acquisition [3]
|
||||
int sendRetries; //!< number of retries for failed sends [2]
|
||||
int receiveTimeout; //!< timeout for receiving answer from slave in us [25000]
|
||||
int masterCount; //!< expected number of masters for arbitration [0]
|
||||
bool generateSyn; //!< enable AUTO-SYN symbol generation
|
||||
|
||||
bool foreground; //!< run in foreground
|
||||
bool enableHex; //!< enable hex command
|
||||
const char* pidFile; //!< PID file name [/var/run/ebusd.pid]
|
||||
uint16_t port; //!< port to listen for command line connections [8888]
|
||||
bool localOnly; //!< listen on 127.0.0.1 interface only
|
||||
uint16_t httpPort; //!< optional port to listen for HTTP connections, 0 to disable [0]
|
||||
const char* htmlPath; //!< path for HTML files served by the HTTP port [/var/ebusd/html]
|
||||
bool foreground; //!< run in foreground
|
||||
bool enableHex; //!< enable hex command
|
||||
const char* pidFile; //!< PID file name [/var/run/ebusd.pid]
|
||||
uint16_t port; //!< port to listen for command line connections [8888]
|
||||
bool localOnly; //!< listen on 127.0.0.1 interface only
|
||||
uint16_t httpPort; //!< optional port to listen for HTTP connections, 0 to disable [0]
|
||||
const char* htmlPath; //!< path for HTML files served by the HTTP port [/var/ebusd/html]
|
||||
|
||||
const char* logFile; //!< log file name [/var/log/ebusd.log]
|
||||
const char* logFile; //!< log file name [/var/log/ebusd.log]
|
||||
|
||||
bool logRaw; //!< raw log each received/sent byte on the bus
|
||||
const char* logRawFile; //!< name of raw log file [/var/log/ebusd.log]
|
||||
unsigned int logRawSize; //!< maximum size of raw log file in kB [100]
|
||||
bool logRaw; //!< raw log each received/sent byte on the bus
|
||||
const char* logRawFile; //!< name of raw log file [/var/log/ebusd.log]
|
||||
unsigned int logRawSize; //!< maximum size of raw log file in kB [100]
|
||||
|
||||
bool dump; //!< binary dump received bytes
|
||||
const char* dumpFile; //!< name of dump file [/tmp/ebusd_dump.bin]
|
||||
unsigned int dumpSize; //!< maximum size of dump file in kB [100]
|
||||
bool dump; //!< binary dump received bytes
|
||||
const char* dumpFile; //!< name of dump file [/tmp/ebusd_dump.bin]
|
||||
unsigned int dumpSize; //!< maximum size of dump file in kB [100]
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -90,14 +92,16 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose = false, bool denyRe
|
||||
/**
|
||||
* Load the message definitions from a configuration file matching the scan result.
|
||||
* @param messages the @a MessageMap to load the messages into.
|
||||
* @param address the address of the scan participant (either master for broadcast master data or slave for read slave data).
|
||||
* @param address the address of the scan participant
|
||||
* (either master for broadcast master data or slave for read slave data).
|
||||
* @param data the scan @a SymbolString for which to load the configuration file.
|
||||
* @param relativeFile the string in which the name of the configuration file is stored on success.
|
||||
* @param verbose whether to verbosely log problems.
|
||||
* @return the result code.
|
||||
*/
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose = false);
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile,
|
||||
bool verbose = false);
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_MAIN_H_
|
||||
#endif // EBUSD_MAIN_H_
|
||||
|
||||
+129
-102
@@ -150,7 +150,7 @@ void MainLoop::run() {
|
||||
bool reload = true;
|
||||
time_t lastTaskRun, now, lastSignal = 0, since, sinkSince = 1;
|
||||
int taskDelay = 5;
|
||||
unsigned char lastScanAddress = 0; // 0 is known to be a master
|
||||
unsigned char lastScanAddress = 0; // 0 is known to be a master
|
||||
time(&now);
|
||||
lastTaskRun = now;
|
||||
ostringstream updates;
|
||||
@@ -196,7 +196,7 @@ void MainLoop::run() {
|
||||
Message* message = m_messages->getScanMessage(m_initialScan);
|
||||
if (result == RESULT_OK && message != NULL) {
|
||||
ostringstream ret;
|
||||
result = message->decodeLastData(ret, 0, true); // decode data
|
||||
result = message->decodeLastData(ret, 0, true); // decode data
|
||||
if (result == RESULT_OK) {
|
||||
logNotice(lf_main, "initial scan result: %2.2x%s", m_initialScan, ret.str().c_str());
|
||||
}
|
||||
@@ -277,7 +277,7 @@ void MainLoop::run() {
|
||||
logDebug(lf_main, "<<< %s", result.c_str());
|
||||
}
|
||||
if (result.length() == 0) {
|
||||
result = "\n"; // only for HTTP
|
||||
result = "\n"; // only for HTTP
|
||||
} else if (!netMessage->isHttp()) {
|
||||
result += "\n\n";
|
||||
}
|
||||
@@ -331,7 +331,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
|
||||
escaped = false;
|
||||
}
|
||||
token = previous + " " + token;
|
||||
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
|
||||
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
|
||||
continue;
|
||||
} else if (token[0] == '"') {
|
||||
token.erase(0, 1);
|
||||
@@ -364,11 +364,13 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
|
||||
const char* str = args[0].c_str();
|
||||
if (args.size() == 2) {
|
||||
// check for "CMD -h"
|
||||
if (strcasecmp(args[1].c_str(), "-h") == 0 || strcasecmp(args[1].c_str(), "-?") == 0 || strcasecmp(args[1].c_str(), "--help") == 0) {
|
||||
args.clear(); // empty args is used as command help indicator
|
||||
} else if (strcasecmp(args[0].c_str(), "H") == 0 || strcasecmp(args[0].c_str(), "HELP") == 0) { // check for "HELP CMD"
|
||||
if (strcasecmp(args[1].c_str(), "-h") == 0 || strcasecmp(args[1].c_str(), "-?") == 0 ||
|
||||
strcasecmp(args[1].c_str(), "--help") == 0) {
|
||||
args.clear(); // empty args is used as command help indicator
|
||||
} else if (strcasecmp(args[0].c_str(), "H") == 0 || strcasecmp(args[0].c_str(), "HELP") == 0) {
|
||||
// check for "HELP CMD"
|
||||
str = args[1].c_str();
|
||||
args.clear(); // empty args is used as command help indicator
|
||||
args.clear(); // empty args is used as command help indicator
|
||||
}
|
||||
}
|
||||
if (strcasecmp(str, "R") == 0 || strcasecmp(str, "READ") == 0) {
|
||||
@@ -431,7 +433,7 @@ result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, SymbolStr
|
||||
}
|
||||
msg << args[argPos++];
|
||||
}
|
||||
if (msg.str().size() < 4*2) { // at least ZZ, PB, SB, NN
|
||||
if (msg.str().size() < 4*2) { // at least ZZ, PB, SB, NN
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
result_t ret;
|
||||
@@ -485,24 +487,24 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
result_t result;
|
||||
maxAge = parseInt(args[argPos].c_str(), 10, 0, 24*60*60, result);
|
||||
if (result != RESULT_OK) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else if (args[argPos] == "-c") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
circuit = args[argPos];
|
||||
} else if (args[argPos] == "-d") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
result_t ret;
|
||||
@@ -513,7 +515,7 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
} else if (args[argPos] == "-p") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
result_t ret;
|
||||
@@ -524,18 +526,19 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
} else if (args[argPos] == "-i") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
params = args[argPos];
|
||||
} else {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
argPos++;
|
||||
}
|
||||
if (hex && (dstAddress != SYN || !circuit.empty() || verbosity != 0 || numeric || pollPriority > 0 || args.size() < argPos + 1)) {
|
||||
argPos = 0; // print usage
|
||||
if (hex && (dstAddress != SYN || !circuit.empty() || verbosity != 0 || numeric || pollPriority > 0
|
||||
|| args.size() < argPos + 1)) {
|
||||
argPos = 0; // print usage
|
||||
}
|
||||
|
||||
time_t now;
|
||||
@@ -562,7 +565,7 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG);
|
||||
}
|
||||
if (circuit.length() > 0 && circuit != message->getCircuit()) {
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
|
||||
}
|
||||
if (message->getLastUpdateTime() + maxAge > now || (message->isPassive() && message->getLastUpdateTime() != 0)) {
|
||||
SymbolString& slave = message->getLastSlaveData();
|
||||
@@ -583,36 +586,40 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
ret = message->decodeLastData(result);
|
||||
}
|
||||
if (ret >= RESULT_OK) {
|
||||
logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
|
||||
logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
result.str().c_str());
|
||||
} else {
|
||||
logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
}
|
||||
return slave.getDataStr(true, false);
|
||||
}
|
||||
logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
return getResultCode(ret);
|
||||
}
|
||||
if (argPos == 0 || args.size() < argPos + 1 || args.size() > argPos + 2) {
|
||||
return "usage: read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
|
||||
" or: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" Read value(s) or hex message.\n"
|
||||
" -f force reading from the bus (same as '-m 0')\n"
|
||||
" -m SECONDS only return cached value if age is less than SECONDS [300]\n"
|
||||
" -c CIRCUIT limit to messages of CIRCUIT\n"
|
||||
" -d ZZ override destination address ZZ\n"
|
||||
" -p PRIO set the message poll priority (1-9)\n"
|
||||
" -v increase verbosity (include names/units/comments)\n"
|
||||
" -V be very verbose (include names, units, and comments)\n"
|
||||
" -n use numeric value of value=name pairs\n"
|
||||
" -i VALUE read additional message parameters from VALUE\n"
|
||||
" NAME NAME of the message to send\n"
|
||||
" FIELD only retrieve the field named FIELD\n"
|
||||
" N only retrieve the N'th field named FIELD (0-based)\n"
|
||||
" -h send hex read message (or answer from cache):\n"
|
||||
" ZZ destination address\n"
|
||||
" PB SB primary/secondary command byte\n"
|
||||
" NN number of following data bytes\n"
|
||||
" Dx data byte(s) to send";
|
||||
return "usage: read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME "
|
||||
"[FIELD[.N]]\n"
|
||||
" or: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" Read value(s) or hex message.\n"
|
||||
" -f force reading from the bus (same as '-m 0')\n"
|
||||
" -m SECONDS only return cached value if age is less than SECONDS [300]\n"
|
||||
" -c CIRCUIT limit to messages of CIRCUIT\n"
|
||||
" -d ZZ override destination address ZZ\n"
|
||||
" -p PRIO set the message poll priority (1-9)\n"
|
||||
" -v increase verbosity (include names/units/comments)\n"
|
||||
" -V be very verbose (include names, units, and comments)\n"
|
||||
" -n use numeric value of value=name pairs\n"
|
||||
" -i VALUE read additional message parameters from VALUE\n"
|
||||
" NAME NAME of the message to send\n"
|
||||
" FIELD only retrieve the field named FIELD\n"
|
||||
" N only retrieve the N'th field named FIELD (0-based)\n"
|
||||
" -h send hex read message (or answer from cache):\n"
|
||||
" ZZ destination address\n"
|
||||
" PB SB primary/secondary command byte\n"
|
||||
" NN number of following data bytes\n"
|
||||
" Dx data byte(s) to send";
|
||||
}
|
||||
string fieldName;
|
||||
char fieldIndex = -2;
|
||||
@@ -641,26 +648,31 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
Message* cacheMessage = m_messages->find(circuit, args[argPos], false, true);
|
||||
bool hasCache = cacheMessage != NULL;
|
||||
if (!hasCache || (message != NULL && message->getLastUpdateTime() > cacheMessage->getLastUpdateTime())) {
|
||||
cacheMessage = message; // message is newer/better
|
||||
cacheMessage = message; // message is newer/better
|
||||
}
|
||||
if (cacheMessage != NULL && (cacheMessage->getLastUpdateTime() + maxAge > now || (cacheMessage->isPassive() && cacheMessage->getLastUpdateTime() != 0))) {
|
||||
if (cacheMessage != NULL
|
||||
&& (cacheMessage->getLastUpdateTime() + maxAge > now
|
||||
|| (cacheMessage->isPassive() && cacheMessage->getLastUpdateTime() != 0))) {
|
||||
if (verbosity & OF_NAMES) {
|
||||
result << cacheMessage->getCircuit() << " " << cacheMessage->getName() << " ";
|
||||
}
|
||||
result_t ret = cacheMessage->decodeLastData(result, verbosity|(numeric?OF_NUMERIC:0), false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
|
||||
result_t ret = cacheMessage->decodeLastData(result, verbosity|(numeric?OF_NUMERIC:0), false,
|
||||
fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
|
||||
if (ret != RESULT_OK) {
|
||||
if (ret < RESULT_OK) {
|
||||
logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(),
|
||||
cacheMessage->getName().c_str(), getResultCode(ret));
|
||||
}
|
||||
return getResultCode(ret);
|
||||
}
|
||||
logInfo(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(), result.str().c_str());
|
||||
logInfo(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), cacheMessage->getName().c_str(),
|
||||
result.str().c_str());
|
||||
return result.str();
|
||||
}
|
||||
|
||||
if (message == NULL && hasCache) {
|
||||
return "ERR: no data stored";
|
||||
} // else: read directly from bus
|
||||
} // else: read directly from bus
|
||||
}
|
||||
|
||||
if (message == NULL) {
|
||||
@@ -677,9 +689,11 @@ string MainLoop::executeRead(vector<string> &args) {
|
||||
if (verbosity & OF_NAMES) {
|
||||
result << message->getCircuit() << " " << message->getName() << " ";
|
||||
}
|
||||
ret = message->decodeLastData(pt_slaveData, result, verbosity|(numeric?OF_NUMERIC:0), false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
|
||||
ret = message->decodeLastData(pt_slaveData, result, verbosity|(numeric?OF_NUMERIC:0), false,
|
||||
fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex);
|
||||
if (ret < RESULT_OK) {
|
||||
logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
result.str("");
|
||||
result << getResultCode(ret) << " in decode";
|
||||
return result.str();
|
||||
@@ -702,7 +716,7 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
} else if (args[argPos] == "-d") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
result_t ret;
|
||||
@@ -713,19 +727,19 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
} else if (args[argPos] == "-c") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
circuit = args[argPos];
|
||||
} else {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
argPos++;
|
||||
}
|
||||
|
||||
if (hex && (dstAddress != SYN || !circuit.empty() || args.size() < argPos + 1)) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
}
|
||||
|
||||
if (hex && argPos > 0) {
|
||||
@@ -746,7 +760,7 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG);
|
||||
}
|
||||
if (circuit.length() > 0 && circuit != message->getCircuit()) {
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
|
||||
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
|
||||
}
|
||||
// send message
|
||||
SymbolString master(true);
|
||||
@@ -762,9 +776,11 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
ret = message->decodeLastData(result);
|
||||
}
|
||||
if (ret >= RESULT_OK) {
|
||||
logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
|
||||
logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(),
|
||||
message->getName().c_str(), result.str().c_str());
|
||||
} else {
|
||||
logError(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(),
|
||||
message->getName().c_str(), getResultCode(ret));
|
||||
}
|
||||
if (master[1] == BROADCAST) {
|
||||
return "done broadcast";
|
||||
@@ -774,7 +790,8 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
}
|
||||
return slave.getDataStr(true, false);
|
||||
}
|
||||
logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
return getResultCode(ret);
|
||||
}
|
||||
|
||||
@@ -800,40 +817,46 @@ string MainLoop::executeWrite(vector<string> &args) {
|
||||
if (message->getDstAddress() == SYN && dstAddress == SYN) {
|
||||
return getResultCode(RESULT_ERR_INVALID_ADDR);
|
||||
}
|
||||
result_t ret = m_busHandler->readFromBus(message, args.size() == argPos + 1 ? "" : args[argPos + 1], dstAddress); // allow missing values
|
||||
// allow missing values
|
||||
result_t ret = m_busHandler->readFromBus(message, args.size() == argPos + 1 ? "" : args[argPos + 1], dstAddress);
|
||||
if (ret != RESULT_OK) {
|
||||
logError(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
return getResultCode(ret);
|
||||
}
|
||||
dstAddress = message->getLastMasterData()[1];
|
||||
ostringstream result;
|
||||
if (dstAddress == BROADCAST || isMaster(dstAddress)) {
|
||||
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
if (dstAddress == BROADCAST) {
|
||||
return "done broadcast";
|
||||
}
|
||||
return getResultCode(RESULT_OK);
|
||||
}
|
||||
|
||||
ret = message->decodeLastData(pt_slaveData, result); // decode data
|
||||
ret = message->decodeLastData(pt_slaveData, result); // decode data
|
||||
if (ret >= RESULT_OK && result.str().empty()) {
|
||||
logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
return getResultCode(RESULT_OK);
|
||||
}
|
||||
if (ret != RESULT_OK) {
|
||||
logError(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret));
|
||||
logError(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(ret));
|
||||
result.str("");
|
||||
result << getResultCode(ret) << " in decode";
|
||||
return result.str();
|
||||
}
|
||||
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str());
|
||||
logNotice(lf_main, "write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
result.str().c_str());
|
||||
return result.str();
|
||||
}
|
||||
|
||||
string MainLoop::executeHex(vector<string> &args) {
|
||||
size_t argPos = 1;
|
||||
if (args.size() < argPos + 1 || (args.size() > argPos && args[argPos][0] == '-')) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
}
|
||||
|
||||
if (argPos > 0) {
|
||||
@@ -873,7 +896,8 @@ string MainLoop::executeHex(vector<string> &args) {
|
||||
|
||||
string MainLoop::executeFind(vector<string> &args) {
|
||||
size_t argPos = 1;
|
||||
bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true, onlyWithData = false, hexFormat = false;
|
||||
bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true,
|
||||
onlyWithData = false, hexFormat = false;
|
||||
OutputFormat verbosity = 0;
|
||||
vector<size_t> columns;
|
||||
string circuit;
|
||||
@@ -898,13 +922,13 @@ string MainLoop::executeFind(vector<string> &args) {
|
||||
} else if (args[argPos] == "-f") {
|
||||
configFormat = true;
|
||||
if (hexFormat) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else if (args[argPos] == "-F") {
|
||||
argPos++;
|
||||
if (hexFormat || (argPos >= args.size())) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
istringstream input(args[argPos]);
|
||||
@@ -918,13 +942,13 @@ string MainLoop::executeFind(vector<string> &args) {
|
||||
}
|
||||
}
|
||||
if (idx == columnCount) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
columns.push_back(columnIds[idx]);
|
||||
}
|
||||
if (columns.empty()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else if (args[argPos] == "-e") {
|
||||
@@ -952,13 +976,13 @@ string MainLoop::executeFind(vector<string> &args) {
|
||||
} else if (args[argPos] == "-h") {
|
||||
hexFormat = true;
|
||||
if (configFormat) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else if (args[argPos] == "-i") {
|
||||
argPos++;
|
||||
if (argPos >= args.size() || !id.empty()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
result_t result = Message::parseId(args[argPos], id);
|
||||
@@ -966,18 +990,18 @@ string MainLoop::executeFind(vector<string> &args) {
|
||||
return getResultCode(result);
|
||||
}
|
||||
if (id.empty()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
} else if (args[argPos] == "-c") {
|
||||
argPos++;
|
||||
if (argPos >= args.size()) {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
circuit = args[argPos];
|
||||
} else {
|
||||
argPos = 0; // print usage
|
||||
argPos = 0; // print usage
|
||||
break;
|
||||
}
|
||||
argPos++;
|
||||
@@ -1171,10 +1195,11 @@ string MainLoop::executeScan(vector<string> &args) {
|
||||
if (result != RESULT_OK) {
|
||||
return getResultCode(result);
|
||||
}
|
||||
Message* message = m_messages->getScanMessage(dstAddress); // never NULL due to scanAndWait() == RESULT_OK && dstAddress != BROADCAST
|
||||
Message* message = m_messages->getScanMessage(dstAddress);
|
||||
// never NULL due to scanAndWait() == RESULT_OK && dstAddress != BROADCAST
|
||||
ostringstream ret;
|
||||
ret << hex << setw(2) << setfill('0') << static_cast<unsigned>(dstAddress);
|
||||
result = message->decodeLastData(ret, 0, true); // decode data
|
||||
result = message->decodeLastData(ret, 0, true); // decode data
|
||||
if (result != RESULT_OK) {
|
||||
return getResultCode(result);
|
||||
}
|
||||
@@ -1291,27 +1316,29 @@ string MainLoop::executeQuit(vector<string> &args, bool& connected) {
|
||||
|
||||
string MainLoop::executeHelp() {
|
||||
return "usage:\n"
|
||||
" read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n] [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
|
||||
" Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" write|w Write value(s): write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n"
|
||||
" Write hex message: write [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" hex Send hex data: hex ZZPBSBNNDx\n"
|
||||
" find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e] [-c CIRCUIT] [NAME]\n"
|
||||
" listen|l Listen for updates: listen [stop]\n"
|
||||
" state|s Report bus state\n"
|
||||
" info|i Report information about the daemon, the configuration, and seen devices.\n"
|
||||
" grab|g Grab messages: grab [stop]\n"
|
||||
" Report the messages: grab result [all]\n"
|
||||
" scan Scan slaves: scan [full|ZZ]\n"
|
||||
" Report scan result: scan result\n"
|
||||
" log Set log area/level: log [AREA[,AREA]*] [LEVEL]\n"
|
||||
" AREA: main|network|bus|update|all\n"
|
||||
" LEVEL: error|notice|info|debug\n"
|
||||
" raw Toggle logging of each byte\n"
|
||||
" dump Toggle binary dump of received bytes\n"
|
||||
" reload Reload CSV config files\n"
|
||||
" quit|q Close connection\n"
|
||||
" help|h Print help help [COMMAND]";
|
||||
" read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v|-V] [-n]"
|
||||
" [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n"
|
||||
" Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" write|w Write value(s): write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n"
|
||||
" Write hex message: write [-c CIRCUIT] -h ZZPBSBNNDx\n"
|
||||
" hex Send hex data: hex ZZPBSBNNDx\n"
|
||||
" find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]"
|
||||
" [-c CIRCUIT] [NAME]\n"
|
||||
" listen|l Listen for updates: listen [stop]\n"
|
||||
" state|s Report bus state\n"
|
||||
" info|i Report information about the daemon, the configuration, and seen devices.\n"
|
||||
" grab|g Grab messages: grab [stop]\n"
|
||||
" Report the messages: grab result [all]\n"
|
||||
" scan Scan slaves: scan [full|ZZ]\n"
|
||||
" Report scan result: scan result\n"
|
||||
" log Set log area/level: log [AREA[,AREA]*] [LEVEL]\n"
|
||||
" AREA: main|network|bus|update|all\n"
|
||||
" LEVEL: error|notice|info|debug\n"
|
||||
" raw Toggle logging of each byte\n"
|
||||
" dump Toggle binary dump of received bytes\n"
|
||||
" reload Reload CSV config files\n"
|
||||
" quit|q Close connection\n"
|
||||
" help|h Print help help [COMMAND]";
|
||||
}
|
||||
|
||||
string MainLoop::executeGet(vector<string> &args, bool& connected) {
|
||||
@@ -1391,7 +1418,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
|
||||
if (lastup == 0 && required) {
|
||||
// read directly from bus
|
||||
if (message->isPassive()) {
|
||||
continue; // not possible to actively read this message
|
||||
continue; // not possible to actively read this message
|
||||
}
|
||||
if (m_busHandler->readFromBus(message, "") != RESULT_OK) {
|
||||
continue;
|
||||
@@ -1430,7 +1457,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
|
||||
} else {
|
||||
string prefix = result.str().substr(0, pos);
|
||||
result.str("");
|
||||
result.clear(); // remove written fields
|
||||
result.clear(); // remove written fields
|
||||
result << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\"";
|
||||
}
|
||||
}
|
||||
@@ -1542,4 +1569,4 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
|
||||
return result.str();
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace ebusd {
|
||||
* The main loop handling requests from connected clients.
|
||||
*/
|
||||
class MainLoop : public Thread, DeviceListener {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct the main loop and create network and bus handling components.
|
||||
* @param opt the program options.
|
||||
@@ -66,12 +66,12 @@ class MainLoop : public Thread, DeviceListener {
|
||||
virtual void notifyDeviceData(const unsigned char byte, bool received);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void run();
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Decode and execute client message.
|
||||
* @param data the data string to decode (may be empty).
|
||||
@@ -230,7 +230,8 @@ class MainLoop : public Thread, DeviceListener {
|
||||
/** whether to pick configuration files matching initial scan. */
|
||||
const bool m_scanConfig;
|
||||
|
||||
/** the initial address to scan for @a m_scanConfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
||||
/** the initial address to scan for @a m_scanConfig
|
||||
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
||||
const unsigned char m_initialScan;
|
||||
|
||||
/** whether to enable the hex command. */
|
||||
@@ -252,6 +253,6 @@ class MainLoop : public Thread, DeviceListener {
|
||||
list<DataHandler*> m_dataHandlers;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_MAINLOOP_H_
|
||||
#endif // EBUSD_MAINLOOP_H_
|
||||
|
||||
+19
-16
@@ -37,9 +37,9 @@ static const struct argp_option g_mqtt_argp_options[] = {
|
||||
{NULL, 0, NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
static const char* g_host = "localhost"; //!< MQTT Host to use [localhost]
|
||||
static uint16_t g_port = 0; //!< optional port of MQTT broker, 0 to disable [0]
|
||||
static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without wildcards) [ebusd]
|
||||
static const char* g_host = "localhost"; //!< MQTT Host to use [localhost]
|
||||
static uint16_t g_port = 0; //!< optional port of MQTT broker, 0 to disable [0]
|
||||
static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without wildcards) [ebusd]
|
||||
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
result_t result = RESULT_OK;
|
||||
|
||||
switch (key) {
|
||||
case 1: // --mqtthost=localhost
|
||||
case 1: // --mqtthost=localhost
|
||||
if (arg == NULL || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqtthost");
|
||||
return EINVAL;
|
||||
@@ -60,7 +60,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
g_host = arg;
|
||||
break;
|
||||
|
||||
case 2: // --mqttport=1883
|
||||
case 2: // --mqttport=1883
|
||||
g_port = (uint16_t)parseInt(arg, 10, 1, 65535, result);
|
||||
if (result != RESULT_OK) {
|
||||
argp_error(state, "invalid mqttport");
|
||||
@@ -68,7 +68,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // --mqtttopic=ebusd
|
||||
case 3: // --mqtttopic=ebusd
|
||||
if (arg == NULL || arg[0] == 0 || arg[0] == '/' || arg[strlen(arg)-1] == '/') {
|
||||
argp_error(state, "invalid mqtttopic");
|
||||
return EINVAL;
|
||||
@@ -136,7 +136,7 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
|
||||
}
|
||||
for (vector<size_t>::iterator it=cols.begin(); it != cols.end(); it++) {
|
||||
if (*it == col) {
|
||||
return false; // duplicate column
|
||||
return false; // duplicate column
|
||||
}
|
||||
}
|
||||
strs.push_back(topic.substr(lastpos, pos-lastpos));
|
||||
@@ -178,12 +178,12 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
m_topicStrs[0] = str+"/";
|
||||
}
|
||||
}
|
||||
m_topicCols.push_back(COLUMN_CIRCUIT); // circuit
|
||||
m_topicCols.push_back(COLUMN_CIRCUIT); // circuit
|
||||
m_topicStrs.push_back("/");
|
||||
m_topicCols.push_back(COLUMN_NAME); // name
|
||||
m_topicCols.push_back(COLUMN_NAME); // name
|
||||
} else {
|
||||
for (size_t i = 0; i < m_topicCols.size(); i++) {
|
||||
if (m_topicCols[i] == COLUMN_FIELDS) { // fields
|
||||
if (m_topicCols[i] == COLUMN_FIELDS) { // fields
|
||||
m_publishByField = true;
|
||||
break;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ void MqttHandler::notifyTopic(string topic, string data) {
|
||||
if (!isWrite && direction != "get") {
|
||||
return;
|
||||
}
|
||||
suffix = suffix.substr(3); // security level
|
||||
suffix = suffix.substr(3); // security level
|
||||
logOtherDebug("mqtt", "received topic %s", topic.c_str(), data.c_str());
|
||||
string remain = topic.substr(0, pos);
|
||||
size_t last = 0;
|
||||
@@ -314,7 +314,7 @@ void MqttHandler::notifyTopic(string topic, string data) {
|
||||
name = field;
|
||||
break;
|
||||
case COLUMN_FIELDS:
|
||||
//field = field; // TODO add support for writing a single field
|
||||
//field = field; // TODO add support for writing a single field
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -339,7 +339,8 @@ void MqttHandler::notifyTopic(string topic, string data) {
|
||||
if (!message->isPassive()) {
|
||||
result_t result = m_busHandler->readFromBus(message, data);
|
||||
if (result != RESULT_OK) {
|
||||
logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), getResultCode(result));
|
||||
logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(),
|
||||
getResultCode(result));
|
||||
return;
|
||||
}
|
||||
logOtherNotice("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), data.c_str());
|
||||
@@ -436,7 +437,8 @@ string MqttHandler::getTopic(Message* message, signed char fieldIndex) {
|
||||
void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
|
||||
result_t result = message->decodeLastData(updates);
|
||||
if (result != RESULT_OK) {
|
||||
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result));
|
||||
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
|
||||
getResultCode(result));
|
||||
return;
|
||||
}
|
||||
if (m_publishByField) {
|
||||
@@ -455,7 +457,8 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
|
||||
|
||||
void MqttHandler::publishTopic(string topic, string data, bool retain) {
|
||||
logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str());
|
||||
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain);
|
||||
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(),
|
||||
reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -55,7 +55,7 @@ DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages);
|
||||
* The main class supporting MQTT data handling.
|
||||
*/
|
||||
class MqttHandler : public DataSink, public DataSource, public Thread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param busHandler the @a BusHandler instance.
|
||||
@@ -79,12 +79,12 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
|
||||
void notifyTopic(string topic, string data);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void run();
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Called regularly to handle MQTT traffic.
|
||||
*/
|
||||
@@ -132,6 +132,6 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
|
||||
struct mosquitto* m_mosquitto;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_MQTTHANDLER_H_
|
||||
#endif // EBUSD_MQTTHANDLER_H_
|
||||
|
||||
@@ -86,7 +86,8 @@ void Connection::run() {
|
||||
if (ret != 0) {
|
||||
#ifdef HAVE_PPOLL
|
||||
// new data from notify
|
||||
if (ret < 0 || (fds[0].revents & (POLLIN | POLLERR | POLLHUP | POLLRDHUP)) || (fds[1].revents & (POLLERR | POLLHUP))) {
|
||||
if (ret < 0 || (fds[0].revents & (POLLIN | POLLERR | POLLHUP | POLLRDHUP))
|
||||
|| (fds[1].revents & (POLLERR | POLLHUP))) {
|
||||
break;
|
||||
}
|
||||
// new data from socket
|
||||
@@ -282,7 +283,8 @@ void Network::run() {
|
||||
}
|
||||
connection->start("connection");
|
||||
m_connections.push_back(connection);
|
||||
logInfo(lf_network, "[%05d] %s connection opened %s", connection->getID(), isHttp ? "HTTP" : "client", socket->getIP().c_str());
|
||||
logInfo(lf_network, "[%05d] %s connection opened %s", connection->getID(), isHttp ? "HTTP" : "client",
|
||||
socket->getIP().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,4 +301,4 @@ void Network::cleanConnections() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+13
-13
@@ -39,7 +39,7 @@ class Connection;
|
||||
* Class for data/message transfer between @a Connection and @a MainLoop.
|
||||
*/
|
||||
class NetMessage {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param isHttp whether this is a HTTP message.
|
||||
@@ -59,7 +59,7 @@ class NetMessage {
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
@@ -67,7 +67,7 @@ class NetMessage {
|
||||
NetMessage(const NetMessage& src);
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Add request data received from the client.
|
||||
* @param request the request data from the client.
|
||||
@@ -82,11 +82,11 @@ class NetMessage {
|
||||
if (pos != string::npos) {
|
||||
if (m_isHttp) {
|
||||
pos = m_request.find("\n");
|
||||
m_request.resize(pos); // reduce to first line
|
||||
m_request.resize(pos); // reduce to first line
|
||||
// typical first line: GET /ehp/outsidetemp HTTP/1.1
|
||||
pos = m_request.rfind(" HTTP/");
|
||||
if (pos != string::npos) {
|
||||
m_request.resize(pos); // remove "HTTP/x.x" suffix
|
||||
m_request.resize(pos); // remove "HTTP/x.x" suffix
|
||||
}
|
||||
pos = 0;
|
||||
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
|
||||
@@ -98,7 +98,7 @@ class NetMessage {
|
||||
m_request.erase(pos+1, 2);
|
||||
}
|
||||
} else if (pos+1 == m_request.length()) {
|
||||
m_request.resize(pos); // reduce to complete lines
|
||||
m_request.resize(pos); // reduce to complete lines
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ class NetMessage {
|
||||
bool isDisconnect() { return m_disconnect; }
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** whether this is a HTTP message. */
|
||||
const bool m_isHttp;
|
||||
|
||||
@@ -201,7 +201,7 @@ class NetMessage {
|
||||
* class connection which handle client and baseloop communication.
|
||||
*/
|
||||
class Connection : public Thread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param socket the @a TCPSocket for communication.
|
||||
@@ -231,7 +231,7 @@ class Connection : public Thread {
|
||||
int getID() { return m_id; }
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** whether this is a HTTP connection. */
|
||||
const bool m_isHttp;
|
||||
|
||||
@@ -255,7 +255,7 @@ class Connection : public Thread {
|
||||
* class network which listening on tcp socket for incoming connections.
|
||||
*/
|
||||
class Network : public Thread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* create a network instance and listening for incoming connections.
|
||||
* @param local true to accept connections only for local host.
|
||||
@@ -281,7 +281,7 @@ class Network : public Thread {
|
||||
void stop() const { m_notify.notify(); usleep(100000); }
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the list of active @a Connection instances. */
|
||||
list<Connection*> m_connections;
|
||||
|
||||
@@ -306,6 +306,6 @@ class Network : public Thread {
|
||||
void cleanConnections();
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_NETWORK_H_
|
||||
#endif // EBUSD_NETWORK_H_
|
||||
|
||||
@@ -26,4 +26,4 @@ bool libebus_contrib_register() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -32,6 +32,6 @@ namespace ebusd {
|
||||
*/
|
||||
bool libebus_contrib_register();
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_CONTRIB_CONTRIB_H_
|
||||
#endif // LIB_EBUS_CONTRIB_CONTRIB_H_
|
||||
|
||||
@@ -73,11 +73,11 @@ result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
}
|
||||
int grp = 0, num = 0;
|
||||
if (isMaster) {
|
||||
grp = (value & 0x1f); // grp in bits 0...5
|
||||
num = ((value >> 8) & 0x7f); // num in bits 8...13
|
||||
grp = (value & 0x1f); // grp in bits 0...5
|
||||
num = ((value >> 8) & 0x7f); // num in bits 8...13
|
||||
} else {
|
||||
grp = ((value >> 7) & 0x1f); // grp in bits 7...11
|
||||
num = (value & 0x7f); // num in bits 0...6
|
||||
grp = ((value >> 7) & 0x1f); // grp in bits 7...11
|
||||
num = (value & 0x7f); // num in bits 0...6
|
||||
}
|
||||
if (outputFormat & OF_JSON) {
|
||||
output << '"';
|
||||
@@ -86,7 +86,7 @@ result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
if (outputFormat & OF_JSON) {
|
||||
output << '"';
|
||||
}
|
||||
output << setfill(' ') << setw(0); // reset
|
||||
output << setfill(' ') << setw(0); // reset
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
@@ -99,45 +99,45 @@ result_t TemParamDataType::writeSymbols(istringstream& input,
|
||||
|
||||
const char* str = input.str().c_str();
|
||||
if (strcasecmp(str, NULL_VALUE) == 0) {
|
||||
value = m_replacement; // replacement value
|
||||
value = m_replacement; // replacement value
|
||||
} else {
|
||||
if (input.eof() || !getline(input, token, '-')) {
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
}
|
||||
str = token.c_str();
|
||||
if (str == NULL || *str == 0) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
char* strEnd = NULL;
|
||||
grp = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (input.eof() || !getline(input, token, '-')) {
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
}
|
||||
str = token.c_str();
|
||||
if (str == NULL || *str == 0) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
strEnd = NULL;
|
||||
num = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (grp < 0 || grp > 0x1f || num < 0 || num > 0x7f) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
if (isMaster) {
|
||||
value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13
|
||||
value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13
|
||||
} else {
|
||||
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
|
||||
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
|
||||
}
|
||||
}
|
||||
if (value < getMinValue() || value > getMaxValue()) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
return writeRawValue(value, offset, length, output, usedLength);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ebusd {
|
||||
* data.
|
||||
*/
|
||||
class TemParamDataType : public NumberDataType {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -68,6 +68,6 @@ class TemParamDataType : public NumberDataType {
|
||||
*/
|
||||
void contrib_tem_register();
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_CONTRIB_TEM_H_
|
||||
#endif // LIB_EBUS_CONTRIB_TEM_H_
|
||||
|
||||
@@ -108,7 +108,8 @@ int main() {
|
||||
fields = NULL;
|
||||
}
|
||||
vector<string>::iterator it = entries.begin();
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, false,
|
||||
(mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
@@ -132,13 +133,15 @@ int main() {
|
||||
SymbolString writeMstr(false);
|
||||
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
|
||||
if (result != RESULT_OK) {
|
||||
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) << endl;
|
||||
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result)
|
||||
<< endl;
|
||||
error = true;
|
||||
}
|
||||
SymbolString writeSstr(false);
|
||||
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
|
||||
if (result != RESULT_OK) {
|
||||
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) << endl;
|
||||
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result)
|
||||
<< endl;
|
||||
error = true;
|
||||
}
|
||||
result = fields->read(pt_masterData, mstr, 0, output, 0, -1, false);
|
||||
@@ -183,7 +186,8 @@ int main() {
|
||||
error = true;
|
||||
} else {
|
||||
bool match = mstr == writeMstr && sstr == writeSstr;
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " + sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
|
||||
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
|
||||
}
|
||||
delete fields;
|
||||
fields = NULL;
|
||||
|
||||
+72
-64
@@ -60,7 +60,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
|
||||
// template: name,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
|
||||
// std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
|
||||
const string name = *it++; // name
|
||||
const string name = *it++; // name
|
||||
if (it == end) {
|
||||
if (!name.empty()) {
|
||||
result = RESULT_ERR_MISSING_TYPE;
|
||||
@@ -71,7 +71,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
if (isTemplate) {
|
||||
partType = pt_any;
|
||||
} else {
|
||||
const char* partStr = (*it++).c_str(); // part
|
||||
const char* partStr = (*it++).c_str(); // part
|
||||
hasPartStr = partStr[0] != 0;
|
||||
if (it == end) {
|
||||
if (!name.empty() || hasPartStr) {
|
||||
@@ -81,10 +81,10 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
}
|
||||
if (isBroadcastOrMasterDestination
|
||||
|| (isWriteMessage && !hasPartStr)
|
||||
|| strcasecmp(partStr, "M") == 0) { // master data
|
||||
|| strcasecmp(partStr, "M") == 0) { // master data
|
||||
partType = pt_masterData;
|
||||
} else if ((!isWriteMessage && !hasPartStr)
|
||||
|| strcasecmp(partStr, "S") == 0) { // slave data
|
||||
|| strcasecmp(partStr, "S") == 0) { // slave data
|
||||
partType = pt_slaveData;
|
||||
} else {
|
||||
result = RESULT_ERR_INVALID_PART;
|
||||
@@ -97,7 +97,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
firstComment = comment;
|
||||
}
|
||||
|
||||
const string typeStr = *it++; // basetype[:len]|template[:name]
|
||||
const string typeStr = *it++; // basetype[:len]|template[:name]
|
||||
vector<string>::iterator typePos = it;
|
||||
if (typeStr.empty()) {
|
||||
if (!name.empty() || hasPartStr) {
|
||||
@@ -110,13 +110,13 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
string constantValue;
|
||||
bool verifyValue = false;
|
||||
if (it != end) {
|
||||
const string divisorStr = *it++; // [divisor|values]
|
||||
const string divisorStr = *it++; // [divisor|values]
|
||||
if (!divisorStr.empty()) {
|
||||
size_t equalPos = divisorStr.find('=');
|
||||
if (equalPos == string::npos) {
|
||||
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
|
||||
} else if (equalPos == 0 && divisorStr.length() > 1) {
|
||||
verifyValue = divisorStr[1] == '='; // == forced verification of constant value
|
||||
verifyValue = divisorStr[1] == '='; // == forced verification of constant value
|
||||
if (verifyValue && divisorStr.length() == 1) {
|
||||
result = RESULT_ERR_INVALID_LIST;
|
||||
break;
|
||||
@@ -131,9 +131,9 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
unsigned long id;
|
||||
if (strncasecmp(str, "0x", 2) == 0) {
|
||||
str += 2;
|
||||
id = strtoul(str, &strEnd, 16); // hexadecimal
|
||||
id = strtoul(str, &strEnd, 16); // hexadecimal
|
||||
} else {
|
||||
id = strtoul(str, &strEnd, 10); // decimal
|
||||
id = strtoul(str, &strEnd, 10); // decimal
|
||||
}
|
||||
if (strEnd == NULL || strEnd == str || id > MAX_VALUE) {
|
||||
result = RESULT_ERR_INVALID_LIST;
|
||||
@@ -159,7 +159,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
if (it == end) {
|
||||
unit = "";
|
||||
} else {
|
||||
const string str = *it++; // [unit]
|
||||
const string str = *it++; // [unit]
|
||||
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
|
||||
unit = "";
|
||||
} else {
|
||||
@@ -170,7 +170,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
if (it == end) {
|
||||
comment = "";
|
||||
} else {
|
||||
const string str = *it++; // [comment]
|
||||
const string str = *it++; // [comment]
|
||||
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
|
||||
comment = "";
|
||||
} else {
|
||||
@@ -187,11 +187,11 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
if (templ == NULL && pos != string::npos) {
|
||||
templ = templates->get(token.substr(0, pos));
|
||||
}
|
||||
if (templ == NULL) { // basetype[:len]
|
||||
if (templ == NULL) { // basetype[:len]
|
||||
unsigned char length;
|
||||
string typeName;
|
||||
if (pos == string::npos) {
|
||||
length = 0; // no length specified
|
||||
length = 0; // no length specified
|
||||
typeName = token;
|
||||
} else {
|
||||
if (pos+2 == token.length() && token[pos+1] == '*') {
|
||||
@@ -206,29 +206,31 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
}
|
||||
transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper);
|
||||
SingleDataField* add = NULL;
|
||||
result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, constantValue, verifyValue, add);
|
||||
result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "",
|
||||
firstType ? unit : "", partType, divisor, values, constantValue, verifyValue, add);
|
||||
if (add != NULL) {
|
||||
fields.push_back(add);
|
||||
} else {
|
||||
it = typePos; // back to type
|
||||
it = typePos; // back to type
|
||||
if (result == RESULT_OK) {
|
||||
result = RESULT_ERR_NOTFOUND; // type not found
|
||||
result = RESULT_ERR_NOTFOUND; // type not found
|
||||
}
|
||||
}
|
||||
} else if (!constantValue.empty()) {
|
||||
it = typePos; // back to type
|
||||
result = RESULT_ERR_INVALID_ARG; // invalid value list
|
||||
} else { // template[:name]
|
||||
it = typePos; // back to type
|
||||
result = RESULT_ERR_INVALID_ARG; // invalid value list
|
||||
} else { // template[:name]
|
||||
string fieldName;
|
||||
bool lastType = stream.eof();
|
||||
if (pos != string::npos) { // replacement name specified
|
||||
if (pos != string::npos) { // replacement name specified
|
||||
fieldName = token.substr(pos+1);
|
||||
} else {
|
||||
fieldName = (firstType && lastType) ? name : "";
|
||||
}
|
||||
result = templ->derive(fieldName, firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields);
|
||||
result = templ->derive(fieldName, firstType ? comment : "", firstType ? unit : "", partType, divisor, values,
|
||||
fields);
|
||||
if (result != RESULT_OK) {
|
||||
it = typePos; // back to type
|
||||
it = typePos; // back to type
|
||||
}
|
||||
}
|
||||
firstType = false;
|
||||
@@ -236,7 +238,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
}
|
||||
|
||||
if (result != RESULT_OK) {
|
||||
while (!fields.empty()) { // cleanup already created fields
|
||||
while (!fields.empty()) { // cleanup already created fields
|
||||
delete fields.back();
|
||||
fields.pop_back();
|
||||
}
|
||||
@@ -276,19 +278,19 @@ result_t SingleDataField::create(const string id, const unsigned char length,
|
||||
// check length
|
||||
if ((bitCount % 8) != 0) {
|
||||
if (length == 0) {
|
||||
bitCount = 1; // default bit count: 1 bit
|
||||
bitCount = 1; // default bit count: 1 bit
|
||||
} else if (length <= bitCount) {
|
||||
bitCount = length;
|
||||
} else {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid length
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid length
|
||||
}
|
||||
byteCount = (unsigned char)((bitCount + 7) / 8);
|
||||
} else if (length == 0) {
|
||||
byteCount = 1; //default byte count: 1 byte
|
||||
byteCount = 1; //default byte count: 1 byte
|
||||
} else if (length <= byteCount || length == REMAIN_LEN) {
|
||||
byteCount = length;
|
||||
} else {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid length
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid length
|
||||
}
|
||||
}
|
||||
if (!constantValue.empty()) {
|
||||
@@ -316,14 +318,14 @@ result_t SingleDataField::create(const string id, const unsigned char length,
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (divisor != 0 || !values.empty()) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
|
||||
}
|
||||
returnField = new SingleDataField(name, comment, unit, dataType, partType, byteCount);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void SingleDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData) {
|
||||
@@ -346,10 +348,10 @@ result_t SingleDataField::read(const PartType partType,
|
||||
}
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
case pt_slaveData:
|
||||
offset++; // skip NN
|
||||
offset++; // skip NN
|
||||
break;
|
||||
default:
|
||||
return RESULT_ERR_INVALID_PART;
|
||||
@@ -373,10 +375,10 @@ result_t SingleDataField::read(const PartType partType,
|
||||
}
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
case pt_slaveData:
|
||||
offset++; // skip NN
|
||||
offset++; // skip NN
|
||||
break;
|
||||
default:
|
||||
return RESULT_ERR_INVALID_PART;
|
||||
@@ -394,7 +396,8 @@ result_t SingleDataField::read(const PartType partType,
|
||||
output << ",";
|
||||
}
|
||||
if (outputIndex >= 0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
|
||||
output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
|
||||
output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \""
|
||||
<< m_name << "\"" << ", \"value\": ";
|
||||
} else {
|
||||
output << "\n \"" << m_name << "\": {\"value\": ";
|
||||
}
|
||||
@@ -439,10 +442,10 @@ result_t SingleDataField::write(istringstream& input,
|
||||
}
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
case pt_slaveData:
|
||||
offset++; // skip NN
|
||||
offset++; // skip NN
|
||||
break;
|
||||
default:
|
||||
return RESULT_ERR_INVALID_PART;
|
||||
@@ -471,11 +474,11 @@ result_t SingleDataField::derive(string name, string comment,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
}
|
||||
bool numeric = m_dataType->isNumeric();
|
||||
if (!numeric && (divisor != 0 || !values.empty())) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
@@ -498,7 +501,8 @@ result_t SingleDataField::derive(string name, string comment,
|
||||
if (values.empty()) {
|
||||
fields.push_back(new SingleDataField(name, comment, unit, dataType, partType, m_length));
|
||||
} else if (numeric) {
|
||||
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(dataType), partType, m_length, values));
|
||||
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(dataType),
|
||||
partType, m_length, values));
|
||||
} else {
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -537,7 +541,7 @@ result_t ValueListDataField::derive(string name, string comment,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
@@ -549,7 +553,7 @@ result_t ValueListDataField::derive(string name, string comment,
|
||||
unit = m_unit;
|
||||
}
|
||||
if (divisor != 0 && divisor != 1) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
|
||||
}
|
||||
if (!m_dataType->isNumeric()) {
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
@@ -557,17 +561,18 @@ result_t ValueListDataField::derive(string name, string comment,
|
||||
if (!values.empty()) {
|
||||
NumberDataType* num = reinterpret_cast<NumberDataType*>(m_dataType);
|
||||
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
|
||||
}
|
||||
} else {
|
||||
values = m_values;
|
||||
}
|
||||
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(m_dataType), partType, m_length, values));
|
||||
fields.push_back(new ValueListDataField(name, comment, unit, reinterpret_cast<NumberDataType*>(m_dataType),
|
||||
partType, m_length, values));
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void ValueListDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData) {
|
||||
@@ -576,14 +581,14 @@ void ValueListDataField::dump(ostream& output) {
|
||||
output << "s";
|
||||
}
|
||||
output << FIELD_SEPARATOR;
|
||||
if (!m_dataType->dump(output, m_length)) { // no divisor appended
|
||||
if (!m_dataType->dump(output, m_length)) { // no divisor appended
|
||||
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
|
||||
if (it != m_values.begin()) {
|
||||
output << VALUE_SEPARATOR;
|
||||
}
|
||||
output << static_cast<unsigned>(it->first) << "=" << it->second;
|
||||
}
|
||||
} // else: impossible since divisor is not allowed for ValueListDataField
|
||||
} // else: impossible since divisor is not allowed for ValueListDataField
|
||||
dumpString(output, m_unit);
|
||||
dumpString(output, m_comment);
|
||||
}
|
||||
@@ -624,7 +629,8 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength) {
|
||||
NumberDataType* numType = reinterpret_cast<NumberDataType*>(m_dataType);
|
||||
if (isIgnored()) {
|
||||
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
|
||||
// replacement value
|
||||
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength);
|
||||
}
|
||||
const char* str = input.str().c_str();
|
||||
|
||||
@@ -634,18 +640,19 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
|
||||
}
|
||||
}
|
||||
if (strcasecmp(str, NULL_VALUE) == 0) {
|
||||
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
|
||||
// replacement value
|
||||
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength);
|
||||
}
|
||||
char* strEnd = NULL; // fall back to raw value in input
|
||||
char* strEnd = NULL; // fall back to raw value in input
|
||||
unsigned int value;
|
||||
value = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_values.find(value) != m_values.end()) {
|
||||
return numType->writeRawValue(value, offset, m_length, output, usedLength);
|
||||
}
|
||||
return RESULT_ERR_NOTFOUND; // value assignment not found
|
||||
return RESULT_ERR_NOTFOUND; // value assignment not found
|
||||
}
|
||||
|
||||
|
||||
@@ -658,7 +665,7 @@ result_t ConstantDataField::derive(string name, string comment,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
@@ -670,17 +677,17 @@ result_t ConstantDataField::derive(string name, string comment,
|
||||
unit = m_unit;
|
||||
}
|
||||
if (divisor != 0) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
|
||||
}
|
||||
if (!values.empty()) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
|
||||
}
|
||||
fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify));
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void ConstantDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData) {
|
||||
@@ -689,9 +696,9 @@ void ConstantDataField::dump(ostream& output) {
|
||||
output << "s";
|
||||
}
|
||||
output << FIELD_SEPARATOR;
|
||||
if (!m_dataType->dump(output, m_length)) { // no divisor appended
|
||||
if (!m_dataType->dump(output, m_length)) { // no divisor appended
|
||||
output << (m_verify?"==":"=") << m_value;
|
||||
} // else: impossible since divisor is not allowed for ConstantDataField
|
||||
} // else: impossible since divisor is not allowed for ConstantDataField
|
||||
dumpString(output, m_unit);
|
||||
dumpString(output, m_comment);
|
||||
}
|
||||
@@ -825,7 +832,7 @@ result_t DataFieldSet::derive(string name, string comment,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (!values.empty()) {
|
||||
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
|
||||
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
|
||||
}
|
||||
bool first = true;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
@@ -919,7 +926,8 @@ result_t DataFieldSet::read(const PartType partType,
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
offset--;
|
||||
}
|
||||
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex);
|
||||
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator,
|
||||
fieldName, fieldIndex);
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -1021,7 +1029,7 @@ result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
|
||||
map<string, DataField*>::iterator it = m_fieldsByName.find(name);
|
||||
if (it != m_fieldsByName.end()) {
|
||||
if (!replace) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
}
|
||||
delete it->second;
|
||||
it->second = field;
|
||||
@@ -1033,8 +1041,8 @@ result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
|
||||
}
|
||||
|
||||
result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo) {
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string& filename, unsigned int lineNo) {
|
||||
vector<string>::iterator restart = begin;
|
||||
DataField* field = NULL;
|
||||
string name;
|
||||
@@ -1051,7 +1059,7 @@ result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const
|
||||
}
|
||||
result = add(field, name, true);
|
||||
if (result == RESULT_ERR_DUPLICATE_NAME) {
|
||||
begin = restart+1; // mark name as invalid
|
||||
begin = restart+1; // mark name as invalid
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
delete field;
|
||||
@@ -1067,4 +1075,4 @@ DataField* DataFieldTemplates::get(const string name) {
|
||||
return ref->second;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+30
-20
@@ -55,7 +55,7 @@ class SingleDataField;
|
||||
* Base class for all kinds of data fields.
|
||||
*/
|
||||
class DataField {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -205,7 +205,7 @@ class DataField {
|
||||
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the field name. */
|
||||
const string m_name;
|
||||
|
||||
@@ -218,7 +218,7 @@ class DataField {
|
||||
* A single @a DataField holding a value.
|
||||
*/
|
||||
class SingleDataField : public DataField {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -322,7 +322,7 @@ class SingleDataField : public DataField {
|
||||
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* Internal method for reading the field from a @a SymbolString.
|
||||
* @param input the unescaped @a SymbolString to read the binary value from.
|
||||
@@ -367,7 +367,7 @@ class SingleDataField : public DataField {
|
||||
* A numeric data field with a list of value=text assignments and a string representation.
|
||||
*/
|
||||
class ValueListDataField : public SingleDataField {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -402,7 +402,7 @@ class ValueListDataField : public SingleDataField {
|
||||
virtual void dump(ostream& output);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
@@ -414,7 +414,7 @@ class ValueListDataField : public SingleDataField {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the value=text assignments. */
|
||||
map<unsigned int, string> m_values;
|
||||
};
|
||||
@@ -424,7 +424,7 @@ class ValueListDataField : public SingleDataField {
|
||||
* A data field with a constant value.
|
||||
*/
|
||||
class ConstantDataField : public SingleDataField {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -460,7 +460,7 @@ class ConstantDataField : public SingleDataField {
|
||||
virtual void dump(ostream& output);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
@@ -472,7 +472,7 @@ class ConstantDataField : public SingleDataField {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the constant value. */
|
||||
const string m_value;
|
||||
|
||||
@@ -485,7 +485,7 @@ class ConstantDataField : public SingleDataField {
|
||||
* A set of @a DataField instances.
|
||||
*/
|
||||
class DataFieldSet : public DataField {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Get the @a DataFieldSet for parsing the identification message (service 0x07 0x04).
|
||||
* @return the @a DataFieldSet for parsing the identification message. This is:<ul>
|
||||
@@ -550,14 +550,24 @@ class DataFieldSet : public DataField {
|
||||
* @param index the index of the @a SingleDataField to return.
|
||||
* @return the @a SingleDataField at the specified index, or NULL.
|
||||
*/
|
||||
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
|
||||
SingleDataField* operator[](const size_t index) {
|
||||
if (index >= m_fields.size()) {
|
||||
return NULL;
|
||||
}
|
||||
return m_fields[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the @a SingleDataField at the specified index.
|
||||
* @param index the index of the @a SingleDataField to return.
|
||||
* @return the @a SingleDataField at the specified index, or NULL.
|
||||
*/
|
||||
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
|
||||
const SingleDataField* operator[](const size_t index) const {
|
||||
if (index >= m_fields.size()) {
|
||||
return NULL;
|
||||
}
|
||||
return m_fields[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of @a SingleDataFields instances in this set.
|
||||
@@ -588,7 +598,7 @@ class DataFieldSet : public DataField {
|
||||
unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the @a DataFieldSet containing the ident message @a SingleDataField instances, or NULL. */
|
||||
static DataFieldSet* s_identFields;
|
||||
|
||||
@@ -604,7 +614,7 @@ class DataFieldSet : public DataField {
|
||||
* A map of template @a DataField instances.
|
||||
*/
|
||||
class DataFieldTemplates : public FileReader {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
@@ -640,8 +650,8 @@ class DataFieldTemplates : public FileReader {
|
||||
|
||||
// @copydoc
|
||||
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo);
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string& filename, unsigned int lineNo);
|
||||
|
||||
/**
|
||||
* Gets the template @a DataField instance with the specified name.
|
||||
@@ -652,11 +662,11 @@ class DataFieldTemplates : public FileReader {
|
||||
DataField* get(string name);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the known template @a DataField instances by name. */
|
||||
map<string, DataField*> m_fieldsByName;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_DATA_H_
|
||||
#endif // LIB_EBUS_DATA_H_
|
||||
|
||||
+198
-153
@@ -40,18 +40,19 @@ using std::setfill;
|
||||
using std::setprecision;
|
||||
using std::setw;
|
||||
|
||||
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length) {
|
||||
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
|
||||
result_t& result, unsigned int* length) {
|
||||
char* strEnd = NULL;
|
||||
|
||||
unsigned long ret = strtoul(str, &strEnd, base);
|
||||
|
||||
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
|
||||
result = RESULT_ERR_INVALID_NUM; // invalid value
|
||||
result = RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (minValue > ret || ret > maxValue) {
|
||||
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
return 0;
|
||||
}
|
||||
if (length != NULL) {
|
||||
@@ -61,18 +62,19 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
|
||||
return (unsigned int)ret;
|
||||
}
|
||||
|
||||
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length) {
|
||||
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
|
||||
unsigned int* length) {
|
||||
char* strEnd = NULL;
|
||||
|
||||
long ret = strtol(str, &strEnd, base);
|
||||
|
||||
if (strEnd == NULL || *strEnd != 0) {
|
||||
result = RESULT_ERR_INVALID_NUM; // invalid value
|
||||
result = RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (minValue > ret || ret > maxValue) {
|
||||
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
return 0;
|
||||
}
|
||||
if (length != NULL) {
|
||||
@@ -82,11 +84,14 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
|
||||
return static_cast<int>(ret);
|
||||
}
|
||||
|
||||
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
|
||||
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
|
||||
vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
|
||||
if (pos > begin) {
|
||||
pos--;
|
||||
}
|
||||
out << "Error reading \"" << filename << "\" line " << setw(0) << dec << static_cast<unsigned>(lineNo) << " field " << static_cast<unsigned>(1+pos.base()-begin.base()) << " value \"" << *pos << "\": " << getResultCode(result) << endl;
|
||||
out << "Error reading \"" << filename << "\" line " << setw(0) << dec << static_cast<unsigned>(lineNo)
|
||||
<< " field " << static_cast<unsigned>(1+pos.base()-begin.base()) << " value \"" << *pos << "\": "
|
||||
<< getResultCode(result) << endl;
|
||||
out << "Erroneous item is here:" << endl;
|
||||
bool first = true;
|
||||
int cnt = 0;
|
||||
@@ -161,7 +166,7 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
} else if (baseOffset + count > input.size()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -187,7 +192,7 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
ch = '?';
|
||||
} else if (outputFormat & OF_JSON) {
|
||||
if (ch == '"' || ch == '\\') {
|
||||
output << '\\'; // escape
|
||||
output << '\\'; // escape
|
||||
}
|
||||
}
|
||||
output << static_cast<char>(ch);
|
||||
@@ -209,7 +214,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
unsigned int value = 0;
|
||||
string token;
|
||||
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -218,7 +223,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
count = 1;
|
||||
}
|
||||
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
}
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)count;
|
||||
@@ -232,21 +237,21 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
while (!input.eof() && input.peek() == ' ') {
|
||||
input.get();
|
||||
}
|
||||
if (input.eof()) { // no more digits
|
||||
value = m_replacement; // fill up with replacement
|
||||
if (input.eof()) { // no more digits
|
||||
value = m_replacement; // fill up with replacement
|
||||
} else {
|
||||
token.clear();
|
||||
token.push_back((unsigned char)input.get());
|
||||
if (input.eof()) {
|
||||
return RESULT_ERR_INVALID_NUM; // too short hex value
|
||||
return RESULT_ERR_INVALID_NUM; // too short hex value
|
||||
}
|
||||
token.push_back((unsigned char)input.get());
|
||||
if (input.eof()) {
|
||||
return RESULT_ERR_INVALID_NUM; // too short hex value
|
||||
return RESULT_ERR_INVALID_NUM; // too short hex value
|
||||
}
|
||||
value = parseInt(token.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid hex value
|
||||
return result; // invalid hex value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -267,13 +272,13 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
break;
|
||||
}
|
||||
if (value > 0xff) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
output[baseOffset + offset] = (unsigned char)value;
|
||||
}
|
||||
|
||||
if (!remainder && i < count) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)((offset-start)*incr);
|
||||
@@ -298,7 +303,7 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
} else if (baseOffset + count > input.size()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -309,34 +314,34 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
int type = (m_hasDate?2:0) | (m_hasTime?1:0);
|
||||
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
|
||||
if (length == 4 && i == 2 && m_hasDate) {
|
||||
continue; // skip weekday in between
|
||||
continue; // skip weekday in between
|
||||
}
|
||||
ch = input[baseOffset + offset];
|
||||
if (hasFlag(BCD) && (hasFlag(REQ) || ch != m_replacement)) {
|
||||
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
}
|
||||
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
|
||||
}
|
||||
switch (type) {
|
||||
case 2: // date only
|
||||
case 2: // date only
|
||||
if (!hasFlag(REQ) && ch == m_replacement) {
|
||||
if (i + 1 != length) {
|
||||
output << NULL_VALUE << ".";
|
||||
break;
|
||||
} else if (last == m_replacement) {
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
output << NULL_VALUE << ".";
|
||||
}
|
||||
output << NULL_VALUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
if (i == 0) {
|
||||
break;
|
||||
}
|
||||
int mjd = last + ch*256 + 15020; // 01.01.1900
|
||||
int mjd = last + ch*256 + 15020; // 01.01.1900
|
||||
int y = static_cast<int>((mjd-15078.2)/365.25);
|
||||
int m = static_cast<int>((mjd-14956.1-static_cast<int>(y*365.25))/30.6001);
|
||||
int d = mjd-14956-static_cast<int>(y*365.25)-static_cast<int>(m*30.6001);
|
||||
@@ -352,15 +357,15 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
if (i + 1 == length) {
|
||||
output << (2000 + ch);
|
||||
} else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid date
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid date
|
||||
} else {
|
||||
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch) << ".";
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // time only
|
||||
case 1: // time only
|
||||
if (!hasFlag(REQ) && ch == m_replacement) {
|
||||
if (length == 1) { // truncated time
|
||||
if (length == 1) { // truncated time
|
||||
output << NULL_VALUE << ":" << NULL_VALUE;
|
||||
break;
|
||||
}
|
||||
@@ -370,37 +375,37 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
output << NULL_VALUE;
|
||||
break;
|
||||
}
|
||||
if (hasFlag(SPE)) { // minutes since midnight
|
||||
if (hasFlag(SPE)) { // minutes since midnight
|
||||
if (i == 0) {
|
||||
last = ch;
|
||||
continue;
|
||||
}
|
||||
int minutes = ch*256 + last;
|
||||
if (minutes > 24*60) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
}
|
||||
int hour = minutes / 60;
|
||||
if (hour > 24) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
|
||||
}
|
||||
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(hour);
|
||||
ch = (unsigned char)(minutes % 60);
|
||||
} else if (length == 1) { // truncated time
|
||||
} else if (length == 1) { // truncated time
|
||||
if (i == 0) {
|
||||
ch = (unsigned char)(ch/(60/m_resolution)); // convert to hours
|
||||
offset -= incr; // repeat for minutes
|
||||
ch = (unsigned char)(ch/(60/m_resolution)); // convert to hours
|
||||
offset -= incr; // repeat for minutes
|
||||
count++;
|
||||
} else {
|
||||
ch = (unsigned char)((ch % (60/m_resolution)) * m_resolution); // convert to minutes
|
||||
ch = (unsigned char)((ch % (60/m_resolution)) * m_resolution); // convert to minutes
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
if (ch > 24) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid hour
|
||||
}
|
||||
hour = ch;
|
||||
} else if (ch > 59 || (hour == 24 && ch > 0)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time
|
||||
}
|
||||
if (i > 0) {
|
||||
output << ":";
|
||||
@@ -425,7 +430,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
unsigned int value = 0, last = 0, lastLast = 0;
|
||||
string token;
|
||||
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -434,7 +439,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
count = 1;
|
||||
}
|
||||
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
}
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)count;
|
||||
@@ -448,12 +453,12 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
for (offset = start; i < count; offset += skip ? 0 : incr, i++) {
|
||||
skip = false;
|
||||
switch (type) {
|
||||
case 2: // date only
|
||||
case 2: // date only
|
||||
if (length == 4 && i == 2) {
|
||||
continue; // skip weekday in between
|
||||
continue; // skip weekday in between
|
||||
}
|
||||
if (input.eof() || !getline(input, token, '.')) {
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
}
|
||||
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) {
|
||||
value = m_replacement;
|
||||
@@ -461,9 +466,9 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
}
|
||||
value = parseInt(token.c_str(), 10, 0, 2099, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid date part
|
||||
return result; // invalid date part
|
||||
}
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
if (length == 2) { // number of days since 01.01.1900
|
||||
skip = true;
|
||||
if (i == 0) {
|
||||
count++;
|
||||
@@ -471,7 +476,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
int y = (value < 100 ? value + 2000 : value) - 1900;
|
||||
int l = last <= 2 ? 1 : 0;
|
||||
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
|
||||
value = mjd - 15020; // 01.01.1900
|
||||
value = mjd - 15020; // 01.01.1900
|
||||
output[baseOffset + offset] = (unsigned char)(value&0xff);
|
||||
value >>= 8;
|
||||
offset += incr;
|
||||
@@ -485,67 +490,68 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
int y = (value < 100 ? value + 2000 : value) - 1900;
|
||||
int l = last <= 2 ? 1 : 0;
|
||||
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
|
||||
int daysSinceSunday = (mjd+3) % 7; // Sun=0
|
||||
int daysSinceSunday = (mjd+3) % 7; // Sun=0
|
||||
if (hasFlag(BCD)) {
|
||||
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
|
||||
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
|
||||
} else {
|
||||
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday == 0 ? 7 : daysSinceSunday); // Sun=0x07
|
||||
// Sun=0x07
|
||||
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday == 0 ? 7 : daysSinceSunday);
|
||||
}
|
||||
}
|
||||
if (value >= 2000) {
|
||||
value -= 2000;
|
||||
}
|
||||
if (value > 99) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid year
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid year
|
||||
}
|
||||
} else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // time only
|
||||
case 1: // time only
|
||||
if (input.eof() || !getline(input, token, LENGTH_SEPARATOR)) {
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
}
|
||||
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) {
|
||||
value = m_replacement;
|
||||
if (length == 1) { // truncated time
|
||||
if (length == 1) { // truncated time
|
||||
if (i == 0) {
|
||||
skip = true; // repeat for minutes
|
||||
skip = true; // repeat for minutes
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
if (last != m_replacement) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
|
||||
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
value = parseInt(token.c_str(), 10, 0, 59, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid time part
|
||||
return result; // invalid time part
|
||||
}
|
||||
if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) )) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
|
||||
}
|
||||
if (hasFlag(SPE)) { // minutes since midnight
|
||||
if (hasFlag(SPE)) { // minutes since midnight
|
||||
if (i == 0) {
|
||||
skip = true; // repeat for minutes
|
||||
skip = true; // repeat for minutes
|
||||
break;
|
||||
}
|
||||
value += last*60;
|
||||
output[baseOffset + offset] = (unsigned char)(value&0xff);
|
||||
value >>= 8;
|
||||
offset += incr;
|
||||
} else if (length == 1) { // truncated time
|
||||
} else if (length == 1) { // truncated time
|
||||
if (i == 0) {
|
||||
skip = true; // repeat for minutes
|
||||
skip = true; // repeat for minutes
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
value = (last * 60 + value + m_resolution/2)/m_resolution;
|
||||
if (value > 24 * 6) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -555,19 +561,19 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
if (!skip) {
|
||||
if (hasFlag(BCD) && (hasFlag(REQ) || value != m_replacement)) {
|
||||
if (value > 99) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
}
|
||||
value = ((value / 10) << 4) | (value % 10);
|
||||
}
|
||||
if (value > 0xff) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
output[baseOffset + offset] = (unsigned char)value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!remainder && i < count) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)((offset-start)*incr);
|
||||
@@ -667,9 +673,9 @@ result_t NumberDataType::readRawValue(SymbolString& input,
|
||||
unsigned char ch;
|
||||
|
||||
if (baseOffset + length > input.size()) {
|
||||
return RESULT_ERR_INVALID_POS; // not enough data available
|
||||
return RESULT_ERR_INVALID_POS; // not enough data available
|
||||
}
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -685,11 +691,11 @@ result_t NumberDataType::readRawValue(SymbolString& input,
|
||||
}
|
||||
if (!hasFlag(HCD)) {
|
||||
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
|
||||
}
|
||||
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
|
||||
} else if (ch > 0x63) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
|
||||
}
|
||||
value += ch * exp;
|
||||
exp *= 100;
|
||||
@@ -717,7 +723,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
output << setw(0) << dec; // initialize output
|
||||
output << setw(0) << dec; // initialize output
|
||||
|
||||
if (!hasFlag(REQ) && value == m_replacement) {
|
||||
if (outputFormat & OF_JSON) {
|
||||
@@ -739,7 +745,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
unsigned char* pval = (unsigned char*)&value;
|
||||
val = *reinterpret_cast<float*>(pval);
|
||||
#else
|
||||
int exp = (value >> 23) & 0xff; // 8 bits, signed
|
||||
int exp = (value >> 23) & 0xff; // 8 bits, signed
|
||||
if (exp == 0) {
|
||||
val = 0.0;
|
||||
} else {
|
||||
@@ -777,8 +783,8 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
signedValue = static_cast<int>(value); // negative signed value
|
||||
} else if (negative) { // negative signed value
|
||||
signedValue = static_cast<int>(value); // negative signed value
|
||||
} else if (negative) { // negative signed value
|
||||
signedValue = static_cast<int>(value) - (1 << m_bitCount);
|
||||
} else {
|
||||
signedValue = static_cast<int>(value);
|
||||
@@ -819,7 +825,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
value <<= m_firstBit;
|
||||
}
|
||||
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
start = length - 1;
|
||||
incr = -1;
|
||||
}
|
||||
@@ -858,14 +864,14 @@ result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
|
||||
const char* str = input.str().c_str();
|
||||
if (!hasFlag(REQ) && (isIgnored() || strcasecmp(str, NULL_VALUE) == 0)) {
|
||||
value = m_replacement; // replacement value
|
||||
value = m_replacement; // replacement value
|
||||
} else if (str == NULL || *str == 0) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
} else if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
} else if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
char* strEnd = NULL;
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue /= -m_divisor;
|
||||
@@ -888,7 +894,7 @@ result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
}
|
||||
int exp = ilogb(dvalue);
|
||||
if (exp < -126 || exp > 127) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
dvalue = scalbln(dvalue, -exp) - 1.0;
|
||||
unsigned int sig = (unsigned int)(dvalue * exp2(23));
|
||||
@@ -913,13 +919,13 @@ result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
value = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
}
|
||||
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
} else {
|
||||
char* strEnd = NULL;
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue = round(dvalue / -m_divisor);
|
||||
@@ -928,7 +934,7 @@ result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
}
|
||||
if (hasFlag(SIG)) {
|
||||
if (dvalue < -(1LL << (8 * length)) || dvalue >= (1LL << (8 * length))) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
if (dvalue < 0 && m_bitCount != 32) {
|
||||
value = static_cast<int>(dvalue + (1 << m_bitCount));
|
||||
@@ -937,22 +943,22 @@ result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
}
|
||||
} else {
|
||||
if (dvalue < 0.0 || dvalue >= (1LL << (8 * length))) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
value = (unsigned int)dvalue;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFlag(SIG)) { // signed value
|
||||
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
|
||||
if (hasFlag(SIG)) { // signed value
|
||||
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
|
||||
if (value < m_minValue) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
} else if (value > m_maxValue) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
} else if (value < m_minValue || value > m_maxValue) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,66 +974,105 @@ bool DataTypeList::s_contrib_initialized = libebus_contrib_register();
|
||||
|
||||
|
||||
DataTypeList::DataTypeList() {
|
||||
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
|
||||
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1)); // unsigned decimal in BCD, 0000 - 9999 (fixed length)
|
||||
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
|
||||
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
|
||||
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0)); // >= 1 byte character string filled up with 0x00 (null terminated string)
|
||||
add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true)); // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
|
||||
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0)); // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
|
||||
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0)); // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
|
||||
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0)); // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63, WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
|
||||
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0)); // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
|
||||
add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0)); // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
|
||||
add(new DateTimeDataType("BTI", 24, BCD|REV, 0xff, false, true, 0)); // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
|
||||
add(new DateTimeDataType("HTI", 24, 0, 0xff, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
|
||||
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
|
||||
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0)); // time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
|
||||
add(new DateTimeDataType("HTM", 16, 0, 0xff, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
|
||||
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
|
||||
add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0)); // time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
|
||||
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10)); // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
|
||||
add(new DateTimeDataType("TTH", 8, 0, 0, false, true, 30)); // truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
|
||||
add(new DateTimeDataType("TTQ", 8, 0, 0, false, true, 15)); // truncated time (only multiple of 15 minutes), 00:00 - 24:00 (minutes div 15 + hour * 4 as integer)
|
||||
add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
|
||||
add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
|
||||
add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
|
||||
add(new NumberDataType("BCD", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999
|
||||
add(new NumberDataType("BCD", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999
|
||||
add(new NumberDataType("BCD", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999
|
||||
add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
|
||||
add(new NumberDataType("HCD", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99
|
||||
add(new NumberDataType("HCD", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
|
||||
add(new NumberDataType("HCD", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
|
||||
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
|
||||
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
|
||||
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2)); // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
|
||||
add(new NumberDataType("D2B", 16, SIG, 0x8000, 0x8001, 0x7fff, 256)); // signed number (fraction 1/256), -127.99 - +127.99
|
||||
add(new NumberDataType("D2C", 16, SIG, 0x8000, 0x8001, 0x7fff, 16)); // signed number (fraction 1/16), -2047.9 - +2047.9
|
||||
add(new NumberDataType("FLT", 16, SIG, 0x8000, 0x8001, 0x7fff, 1000)); // signed number (fraction 1/1000), -32.767 - +32.767, little endian
|
||||
add(new NumberDataType("FLR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1000)); // signed number (fraction 1/1000), -32.767 - +32.767, big endian
|
||||
add(new NumberDataType("EXP", 32, SIG|EXP, 0x7f800000, 0x00000000, 0xffffffff, 1)); // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), little endian
|
||||
add(new NumberDataType("EXR", 32, SIG|EXP|REV, 0x7f800000, 0x00000000, 0xffffffff, 1)); // signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), big endian
|
||||
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1)); // unsigned integer, 0 - 65534, little endian
|
||||
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1)); // unsigned integer, 0 - 65534, big endian
|
||||
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1)); // signed integer, -32767 - +32767, little endian
|
||||
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1)); // signed integer, -32767 - +32767, big endian
|
||||
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1)); // unsigned 3 bytes int, 0 - 16777214, little endian
|
||||
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1)); // unsigned 3 bytes int, 0 - 16777214, big endian
|
||||
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0xffffff, 1)); // signed 3 bytes int, -8388607 - +8388607, little endian
|
||||
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0xffffff, 1)); // signed 3 bytes int, -8388607 - +8388607, big endian
|
||||
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1)); // unsigned integer, 0 - 4294967294, little endian
|
||||
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1)); // unsigned integer, 0 - 4294967294, big endian
|
||||
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0xffffffff, 1)); // signed integer, -2147483647 - +2147483647, little endian
|
||||
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0xffffffff, 1)); // signed integer, -2147483647 - +2147483647, big endian
|
||||
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
|
||||
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
|
||||
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
|
||||
add(new NumberDataType("BI3", 5, ADJ|REQ, 0, 3, 1)); // bit 3 (up to 5 bits until bit 7)
|
||||
add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7)
|
||||
add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7)
|
||||
add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7)
|
||||
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
|
||||
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
|
||||
// unsigned decimal in BCD, 0000 - 9999 (fixed length)
|
||||
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1));
|
||||
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
|
||||
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
|
||||
// >= 1 byte character string filled up with 0x00 (null terminated string)
|
||||
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0));
|
||||
// >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
|
||||
add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true));
|
||||
// date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99,
|
||||
// WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
|
||||
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0));
|
||||
// date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
|
||||
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0));
|
||||
// date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63,
|
||||
// WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
|
||||
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0));
|
||||
// date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
|
||||
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0));
|
||||
// date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
|
||||
add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0));
|
||||
// time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
|
||||
add(new DateTimeDataType("BTI", 24, BCD|REV, 0xff, false, true, 0));
|
||||
// time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
|
||||
add(new DateTimeDataType("HTI", 24, 0, 0xff, false, true, 0));
|
||||
// time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
|
||||
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0));
|
||||
// time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
|
||||
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0));
|
||||
// time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
|
||||
add(new DateTimeDataType("HTM", 16, 0, 0xff, false, true, 0));
|
||||
// time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
|
||||
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0));
|
||||
// time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
|
||||
add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0));
|
||||
// truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
|
||||
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10));
|
||||
// truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
|
||||
add(new DateTimeDataType("TTH", 8, 0, 0, false, true, 30));
|
||||
// truncated time (only multiple of 15 minutes), 00:00 - 24:00 (minutes div 15 + hour * 4 as integer)
|
||||
add(new DateTimeDataType("TTQ", 8, 0, 0, false, true, 15));
|
||||
add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
|
||||
add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
|
||||
add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
|
||||
add(new NumberDataType("BCD", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999
|
||||
add(new NumberDataType("BCD", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999
|
||||
add(new NumberDataType("BCD", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999
|
||||
add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999
|
||||
add(new NumberDataType("HCD", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99
|
||||
add(new NumberDataType("HCD", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
|
||||
add(new NumberDataType("HCD", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
|
||||
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
|
||||
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
|
||||
// unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
|
||||
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2));
|
||||
// signed number (fraction 1/256), -127.99 - +127.99
|
||||
add(new NumberDataType("D2B", 16, SIG, 0x8000, 0x8001, 0x7fff, 256));
|
||||
// signed number (fraction 1/16), -2047.9 - +2047.9
|
||||
add(new NumberDataType("D2C", 16, SIG, 0x8000, 0x8001, 0x7fff, 16));
|
||||
// signed number (fraction 1/1000), -32.767 - +32.767, little endian
|
||||
add(new NumberDataType("FLT", 16, SIG, 0x8000, 0x8001, 0x7fff, 1000));
|
||||
// signed number (fraction 1/1000), -32.767 - +32.767, big endian
|
||||
add(new NumberDataType("FLR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1000));
|
||||
// signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), little endian
|
||||
add(new NumberDataType("EXP", 32, SIG|EXP, 0x7f800000, 0x00000000, 0xffffffff, 1));
|
||||
// signed number (IEEE 754 binary32: 1 bit sign, 8 bits exponent, 23 bits significand), big endian
|
||||
add(new NumberDataType("EXR", 32, SIG|EXP|REV, 0x7f800000, 0x00000000, 0xffffffff, 1));
|
||||
// unsigned integer, 0 - 65534, little endian
|
||||
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1));
|
||||
// unsigned integer, 0 - 65534, big endian
|
||||
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1));
|
||||
// signed integer, -32767 - +32767, little endian
|
||||
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
|
||||
// signed integer, -32767 - +32767, big endian
|
||||
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1));
|
||||
// unsigned 3 bytes int, 0 - 16777214, little endian
|
||||
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
|
||||
// unsigned 3 bytes int, 0 - 16777214, big endian
|
||||
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1));
|
||||
// signed 3 bytes int, -8388607 - +8388607, little endian
|
||||
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0xffffff, 1));
|
||||
// signed 3 bytes int, -8388607 - +8388607, big endian
|
||||
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0xffffff, 1));
|
||||
// unsigned integer, 0 - 4294967294, little endian
|
||||
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
|
||||
// unsigned integer, 0 - 4294967294, big endian
|
||||
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
|
||||
// signed integer, -2147483647 - +2147483647, little endian
|
||||
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0xffffffff, 1));
|
||||
// signed integer, -2147483647 - +2147483647, big endian
|
||||
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0xffffffff, 1));
|
||||
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
|
||||
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
|
||||
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
|
||||
add(new NumberDataType("BI3", 5, ADJ|REQ, 0, 3, 1)); // bit 3 (up to 5 bits until bit 7)
|
||||
add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7)
|
||||
add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7)
|
||||
add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7)
|
||||
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
|
||||
}
|
||||
|
||||
DataTypeList* DataTypeList::getInstance() {
|
||||
@@ -1050,15 +1095,15 @@ result_t DataTypeList::add(DataType* dataType) {
|
||||
str << dataType->getId() << LENGTH_SEPARATOR << static_cast<unsigned>(bitCount >= 8?bitCount/8:bitCount);
|
||||
map<string, DataType*>::iterator it = m_typesByIdLength.find(str.str());
|
||||
if (it != m_typesByIdLength.end()) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
}
|
||||
m_typesByIdLength[str.str()] = dataType;
|
||||
if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
|
||||
m_cleanupTypes.push_back(dataType);
|
||||
return RESULT_OK; // only store first one as default
|
||||
return RESULT_OK; // only store first one as default
|
||||
}
|
||||
} else if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
}
|
||||
m_typesById[dataType->getId()] = dataType;
|
||||
m_cleanupTypes.push_back(dataType);
|
||||
@@ -1081,4 +1126,4 @@ DataType* DataTypeList::get(const string id, const unsigned char length) {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+43
-34
@@ -83,7 +83,7 @@ typedef int OutputFormat;
|
||||
/* the bit flags for @a OutputFormat. */
|
||||
static const unsigned int OF_NAMES = 0x01; //!< include names.
|
||||
static const unsigned int OF_UNITS = 0x02; //!< include units.
|
||||
static const unsigned int OF_COMMENTS = 0x04; //!< include comments.
|
||||
static const unsigned int OF_COMMENTS = 0x04; //!< include comments.
|
||||
static const unsigned int OF_NUMERIC = 0x08; //!< numeric format (keep numeric value of value=name pairs).
|
||||
static const unsigned int OF_JSON = 0x10; //!< JSON format.
|
||||
|
||||
@@ -95,19 +95,20 @@ enum PartType {
|
||||
};
|
||||
|
||||
/* flags for @a DataType. */
|
||||
static const unsigned int ADJ = 0x01; //!< adjustable length, bitCount is maximum length
|
||||
static const unsigned int BCD = 0x02; //!< binary representation is BCD
|
||||
static const unsigned int REV = 0x04; //!< reverted binary representation (most significant byte first)
|
||||
static const unsigned int SIG = 0x08; //!< signed value
|
||||
static const unsigned int IGN = 0x10; //!< ignore value during read and write
|
||||
static const unsigned int FIX = 0x20; //!< fixed width formatting
|
||||
static const unsigned int REQ = 0x40; //!< value may not be NULL
|
||||
static const unsigned int HCD = 0x80; //!< binary representation is hex converted to decimal and interpreted as 2 digits (also requires #BCD)
|
||||
static const unsigned int EXP = 0x100; //!< exponential numeric representation
|
||||
static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days
|
||||
static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType
|
||||
static const unsigned int SPE = 0x800; //!< special marker for certain types
|
||||
static const unsigned int CON = 0x1000; //!< marker for a constant value
|
||||
static const unsigned int ADJ = 0x01; //!< adjustable length, bitCount is maximum length
|
||||
static const unsigned int BCD = 0x02; //!< binary representation is BCD
|
||||
static const unsigned int REV = 0x04; //!< reverted binary representation (most significant byte first)
|
||||
static const unsigned int SIG = 0x08; //!< signed value
|
||||
static const unsigned int IGN = 0x10; //!< ignore value during read and write
|
||||
static const unsigned int FIX = 0x20; //!< fixed width formatting
|
||||
static const unsigned int REQ = 0x40; //!< value may not be NULL
|
||||
/** binary representation is hex converted to decimal and interpreted as 2 digits (also requires #BCD). */
|
||||
static const unsigned int HCD = 0x80;
|
||||
static const unsigned int EXP = 0x100; //!< exponential numeric representation
|
||||
static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days
|
||||
static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType
|
||||
static const unsigned int SPE = 0x800; //!< special marker for certain types
|
||||
static const unsigned int CON = 0x1000; //!< marker for a constant value
|
||||
|
||||
|
||||
/**
|
||||
@@ -120,7 +121,8 @@ static const unsigned int CON = 0x1000; //!< marker for a constant value
|
||||
* @param length the optional variable in which to store the number of read characters.
|
||||
* @return the parsed value.
|
||||
*/
|
||||
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length = NULL);
|
||||
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
|
||||
result_t& result, unsigned int* length = NULL);
|
||||
|
||||
/**
|
||||
* Parse a signed int value.
|
||||
@@ -132,7 +134,8 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
|
||||
* @param length the optional variable in which to store the number of read characters.
|
||||
* @return the parsed value.
|
||||
*/
|
||||
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length = NULL);
|
||||
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
|
||||
unsigned int* length = NULL);
|
||||
|
||||
/**
|
||||
* Print the error position of the iterator.
|
||||
@@ -144,20 +147,22 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
|
||||
* @param lineNo the current line number in the file being read.
|
||||
* @param result the result code.
|
||||
*/
|
||||
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
|
||||
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
|
||||
vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all kinds of data types.
|
||||
*/
|
||||
class DataType {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
* @param bitCount the number of bits (maximum length if #ADJ flag is set, must be multiple of 8 with flag #BCD).
|
||||
* @param flags the combination of flags (like #BCD).
|
||||
* @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue).
|
||||
* @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to
|
||||
* @a NumberDataType#minValue).
|
||||
*/
|
||||
DataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement)
|
||||
: m_id(id), m_bitCount(bitCount), m_flags(flags), m_replacement(replacement) {}
|
||||
@@ -200,7 +205,8 @@ class DataType {
|
||||
bool isNumeric() const { return hasFlag(NUM); }
|
||||
|
||||
/**
|
||||
* @return the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue).
|
||||
* @return the replacement value (fill-up value for @a StringDataType, no replacement if equal to
|
||||
* @a NumberDataType#minValue).
|
||||
*/
|
||||
unsigned int getReplacement() const { return m_replacement; }
|
||||
|
||||
@@ -254,7 +260,7 @@ class DataType {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the type identifier. */
|
||||
const string m_id;
|
||||
|
||||
@@ -264,7 +270,8 @@ class DataType {
|
||||
/** the combination of flags (like #BCD). */
|
||||
const uint16_t m_flags;
|
||||
|
||||
/** the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue). */
|
||||
/** the replacement value (fill-up value for @a StringDataType, no replacement if equal to
|
||||
* @a NumberDataType#minValue). */
|
||||
const unsigned int m_replacement;
|
||||
};
|
||||
|
||||
@@ -273,7 +280,7 @@ class DataType {
|
||||
* A string based @a DataType.
|
||||
*/
|
||||
class StringDataType : public DataType {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -307,7 +314,7 @@ class StringDataType : public DataType {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** true for hex digits instead of characters. */
|
||||
const bool m_isHex;
|
||||
};
|
||||
@@ -317,7 +324,7 @@ class StringDataType : public DataType {
|
||||
* A date/time based @a DataType.
|
||||
*/
|
||||
class DateTimeDataType : public DataType {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -368,7 +375,7 @@ class DateTimeDataType : public DataType {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** true if date part is present. */
|
||||
const bool m_hasDate;
|
||||
|
||||
@@ -384,7 +391,7 @@ class DateTimeDataType : public DataType {
|
||||
* A number based @a DataType.
|
||||
*/
|
||||
class NumberDataType : public DataType {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance for multiple of 8 bits.
|
||||
* @param id the type identifier.
|
||||
@@ -397,7 +404,8 @@ class NumberDataType : public DataType {
|
||||
*/
|
||||
NumberDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement,
|
||||
const unsigned int minValue, const unsigned int maxValue, const int divisor)
|
||||
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(NULL) {}
|
||||
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor),
|
||||
m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(NULL) {}
|
||||
|
||||
/**
|
||||
* Constructs a new instance for less than 8 bits.
|
||||
@@ -410,7 +418,8 @@ class NumberDataType : public DataType {
|
||||
*/
|
||||
NumberDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement,
|
||||
const int16_t firstBit, const int divisor)
|
||||
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor), m_precision(0), m_firstBit(firstBit), m_baseType(NULL) {}
|
||||
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor),
|
||||
m_precision(0), m_firstBit(firstBit), m_baseType(NULL) {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -495,7 +504,7 @@ class NumberDataType : public DataType {
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the minimum raw value. */
|
||||
const unsigned int m_minValue;
|
||||
|
||||
@@ -520,7 +529,7 @@ class NumberDataType : public DataType {
|
||||
* A map of base @a DataType instances.
|
||||
*/
|
||||
class DataTypeList {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance and registers the known base data types.
|
||||
*/
|
||||
@@ -568,7 +577,7 @@ class DataTypeList {
|
||||
DataType* get(const string id, const unsigned char length = 0);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the known @a DataType instances by ID only. */
|
||||
map<string, DataType*> m_typesById;
|
||||
|
||||
@@ -588,6 +597,6 @@ class DataTypeList {
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_DATATYPE_H_
|
||||
#endif // LIB_EBUS_DATATYPE_H_
|
||||
|
||||
@@ -54,13 +54,13 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
|
||||
}
|
||||
if (portpos == NULL) {
|
||||
free(in);
|
||||
return NULL; // invalid protocol or missing port
|
||||
return NULL; // invalid protocol or missing port
|
||||
}
|
||||
result_t result = RESULT_OK;
|
||||
unsigned int port = parseInt(portpos+1, 10, 1, 65535, result);
|
||||
if (result != RESULT_OK) {
|
||||
free(in);
|
||||
return NULL; // invalid port
|
||||
return NULL; // invalid port
|
||||
}
|
||||
struct sockaddr_in address;
|
||||
memset(reinterpret_cast<char*>(&address), 0, sizeof(address));
|
||||
@@ -69,7 +69,7 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
|
||||
struct hostent* h = gethostbyname(addrpos);
|
||||
if (h == NULL) {
|
||||
free(in);
|
||||
return NULL; // invalid host
|
||||
return NULL; // invalid host
|
||||
}
|
||||
memcpy(&address.sin_addr, h->h_addr_list[0], h->h_length);
|
||||
}
|
||||
@@ -142,7 +142,7 @@ result_t Device::recv(const unsigned int timeout, unsigned char& value) {
|
||||
|
||||
ret = pselect(m_fd + 1, &readfds, NULL, NULL, &tdiff, NULL);
|
||||
#else
|
||||
ret = 1; // ignore timeout if neither ppoll nor pselect are available
|
||||
ret = 1; // ignore timeout if neither ppoll nor pselect are available
|
||||
#endif
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
@@ -197,8 +197,8 @@ result_t SerialDevice::open() {
|
||||
memset(&newSettings, '\0', sizeof(newSettings));
|
||||
|
||||
newSettings.c_cflag |= (B2400 | CS8 | CLOCAL | CREAD);
|
||||
newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode
|
||||
newSettings.c_iflag |= IGNPAR; // ignore parity errors
|
||||
newSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // non-canonical mode
|
||||
newSettings.c_iflag |= IGNPAR; // ignore parity errors
|
||||
newSettings.c_oflag &= ~OPOST;
|
||||
|
||||
// non-canonical mode: read() blocks until at least one byte is available
|
||||
@@ -290,7 +290,7 @@ void NetworkDevice::checkDevice() {
|
||||
unsigned char value;
|
||||
ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
if (c == 0 || (c < 0 && errno != EAGAIN)) {
|
||||
m_bufLen = 0; // flush read buffer
|
||||
m_bufLen = 0; // flush read buffer
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -300,7 +300,7 @@ bool NetworkDevice::available() {
|
||||
}
|
||||
|
||||
ssize_t NetworkDevice::write(const unsigned char value) {
|
||||
m_bufLen = 0; // flush read buffer
|
||||
m_bufLen = 0; // flush read buffer
|
||||
return Device::write(value);
|
||||
}
|
||||
|
||||
@@ -324,4 +324,4 @@ ssize_t NetworkDevice::read(unsigned char& value) {
|
||||
return Device::read(value);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+17
-16
@@ -42,7 +42,7 @@ namespace ebusd {
|
||||
* Interface for listening to data received on/sent to a device.
|
||||
*/
|
||||
class DeviceListener {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
@@ -53,7 +53,7 @@ class DeviceListener {
|
||||
* @param byte the data byte received/sent.
|
||||
* @param received @a true on reception, @a false on sending.
|
||||
*/
|
||||
virtual void notifyDeviceData(const unsigned char byte, bool received) = 0; // abstract
|
||||
virtual void notifyDeviceData(const unsigned char byte, bool received) = 0; // abstract
|
||||
};
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ class DeviceListener {
|
||||
* The base class for accessing an eBUS.
|
||||
*/
|
||||
class Device {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -87,7 +87,8 @@ class Device {
|
||||
* @return the new @a Device, or NULL on error.
|
||||
* Note: the caller needs to free the created instance.
|
||||
*/
|
||||
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, const bool initialSend = false);
|
||||
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false,
|
||||
const bool initialSend = false);
|
||||
|
||||
/**
|
||||
* Get the transfer latency of this device.
|
||||
@@ -99,7 +100,7 @@ class Device {
|
||||
* Open the file descriptor.
|
||||
* @return the @a result_t code.
|
||||
*/
|
||||
virtual result_t open() = 0; // abstract
|
||||
virtual result_t open() = 0; // abstract
|
||||
|
||||
/**
|
||||
* Close the file descriptor if opened.
|
||||
@@ -146,11 +147,11 @@ class Device {
|
||||
void setListener(DeviceListener* listener) { m_listener = listener; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* Check if the device is still available and close it if not.
|
||||
*/
|
||||
virtual void checkDevice() = 0; // abstract
|
||||
virtual void checkDevice() = 0; // abstract
|
||||
|
||||
/**
|
||||
* Check whether a byte is available immediately (without waiting).
|
||||
@@ -188,7 +189,7 @@ class Device {
|
||||
int m_fd;
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the @a DeviceListener, or NULL. */
|
||||
DeviceListener* m_listener;
|
||||
};
|
||||
@@ -197,7 +198,7 @@ class Device {
|
||||
* The @a Device for directly connected serial interfaces (tty).
|
||||
*/
|
||||
class SerialDevice : public Device {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -215,12 +216,12 @@ class SerialDevice : public Device {
|
||||
virtual void close();
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void checkDevice();
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the previous settings of the device for restoring. */
|
||||
termios m_oldSettings;
|
||||
};
|
||||
@@ -229,7 +230,7 @@ class SerialDevice : public Device {
|
||||
* The @a Device for remote network interfaces.
|
||||
*/
|
||||
class NetworkDevice : public Device {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -250,7 +251,7 @@ class NetworkDevice : public Device {
|
||||
virtual result_t open();
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void checkDevice();
|
||||
|
||||
@@ -264,7 +265,7 @@ class NetworkDevice : public Device {
|
||||
virtual ssize_t read(unsigned char& value);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the socket address of the device. */
|
||||
const struct sockaddr_in m_address;
|
||||
|
||||
@@ -284,6 +285,6 @@ class NetworkDevice : public Device {
|
||||
unsigned char m_bufPos;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_DEVICE_H_
|
||||
#endif // LIB_EBUS_DEVICE_H_
|
||||
|
||||
+29
-25
@@ -62,15 +62,17 @@ using std::endl;
|
||||
/** the separator character used between multiple values (in CSV only). */
|
||||
#define VALUE_SEPARATOR ';'
|
||||
|
||||
extern void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
|
||||
extern void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end,
|
||||
vector<string>::iterator pos, string filename, size_t lineNo, result_t result);
|
||||
|
||||
extern unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length);
|
||||
extern unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
|
||||
result_t& result, unsigned int* length);
|
||||
|
||||
/**
|
||||
* An abstract class that support reading definitions from a file.
|
||||
*/
|
||||
class FileReader {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -100,13 +102,14 @@ class FileReader {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
size_t lastSep = filename.find_last_of('/');
|
||||
if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
|
||||
if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
|
||||
// extract defaultDest, defaultCircuit, defaultSuffix from filename:
|
||||
// ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv
|
||||
unsigned char checkDest;
|
||||
string checkIdent, useCircuit, useSuffix;
|
||||
unsigned int checkSw, checkHw;
|
||||
if (extractDefaultsFromFilename(filename.substr(lastSep+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
|
||||
if (extractDefaultsFromFilename(filename.substr(lastSep+1), checkDest, checkIdent, useCircuit, useSuffix,
|
||||
checkSw, checkHw)) {
|
||||
defaultDest = filename.substr(lastSep+1, 2);
|
||||
if (!useCircuit.empty()) {
|
||||
defaultCircuit = useCircuit;
|
||||
@@ -202,8 +205,8 @@ class FileReader {
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo) = 0;
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string& filename, unsigned int lineNo) = 0;
|
||||
|
||||
/**
|
||||
* Left and right trim the string.
|
||||
@@ -249,7 +252,7 @@ class FileReader {
|
||||
|
||||
size_t length = line.length();
|
||||
if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) {
|
||||
continue; // skip empty lines and comments
|
||||
continue; // skip empty lines and comments
|
||||
}
|
||||
for (size_t pos = 0; pos < length; pos++) {
|
||||
char ch = line[pos];
|
||||
@@ -267,7 +270,7 @@ class FileReader {
|
||||
}
|
||||
break;
|
||||
case TEXT_SEPARATOR:
|
||||
if (prev == TEXT_SEPARATOR && !quotedText) { // double dquote
|
||||
if (prev == TEXT_SEPARATOR && !quotedText) { // double dquote
|
||||
field << ch;
|
||||
quotedText = true;
|
||||
} else if (quotedText) {
|
||||
@@ -282,7 +285,7 @@ class FileReader {
|
||||
break;
|
||||
default:
|
||||
if (prev == TEXT_SEPARATOR && !quotedText && wasQuoted) {
|
||||
field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text
|
||||
field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text
|
||||
quotedText = true;
|
||||
} else if (quotedText && pos == 0 && field.tellp() > 0 && *(field.str().end()-1) != VALUE_SEPARATOR) {
|
||||
field << VALUE_SEPARATOR;
|
||||
@@ -322,48 +325,49 @@ class FileReader {
|
||||
ident = circuit = suffix = "";
|
||||
software = hardware = UINT_MAX;
|
||||
if (name.length() > 4 && name.substr(name.length()-4) == ".csv") {
|
||||
name = name.substr(0, name.length()-3); // including trailing "."
|
||||
name = name.substr(0, name.length()-3); // including trailing "."
|
||||
}
|
||||
size_t pos = name.find('.');
|
||||
if (pos != 2) {
|
||||
return false; // missing "ZZ."
|
||||
return false; // missing "ZZ."
|
||||
}
|
||||
result_t result = RESULT_OK;
|
||||
dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL);
|
||||
if (result != RESULT_OK || !isValidAddress(dest)) {
|
||||
return false; // invalid "ZZ"
|
||||
return false; // invalid "ZZ"
|
||||
}
|
||||
name.erase(0, pos);
|
||||
if (name.length() > 1) {
|
||||
pos = name.rfind(".SW"); // check for ".SWxxxx."
|
||||
pos = name.rfind(".SW"); // check for ".SWxxxx."
|
||||
if (pos != string::npos && name.find(".", pos+1) == pos+7) {
|
||||
software = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
|
||||
if (result != RESULT_OK) {
|
||||
return false; // invalid "SWxxxx"
|
||||
return false; // invalid "SWxxxx"
|
||||
}
|
||||
name.erase(pos, 7);
|
||||
}
|
||||
}
|
||||
if (name.length() > 1) {
|
||||
pos = name.rfind(".HW"); // check for ".HWxxxx."
|
||||
pos = name.rfind(".HW"); // check for ".HWxxxx."
|
||||
if (pos != string::npos && name.find(".", pos+1) == pos+7) {
|
||||
hardware = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
|
||||
if (result != RESULT_OK) {
|
||||
return false; // invalid "HWxxxx"
|
||||
return false; // invalid "HWxxxx"
|
||||
}
|
||||
name.erase(pos, 7);
|
||||
}
|
||||
}
|
||||
if (name.length() > 1) {
|
||||
pos = name.find('.', 1); // check for ".IDENT."
|
||||
if (pos != string::npos && pos >= 1 && pos <= 6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".."
|
||||
pos = name.find('.', 1); // check for ".IDENT."
|
||||
if (pos != string::npos && pos >= 1 && pos <= 6) {
|
||||
// up to 5 chars between two "."s, immediately after "ZZ.", or ".."
|
||||
ident = circuit = name.substr(1, pos-1);
|
||||
name.erase(0, pos);
|
||||
pos = name.find('.', 1); // check for ".CIRCUIT."
|
||||
pos = name.find('.', 1); // check for ".CIRCUIT."
|
||||
if (pos != string::npos && (pos>2 || name[1]<'0' || name[1]>'9')) {
|
||||
circuit = name.substr(1, pos-1);
|
||||
name.erase(0, pos);
|
||||
pos = name.find('.', 1); // check for ".SUFFIX."
|
||||
pos = name.find('.', 1); // check for ".SUFFIX."
|
||||
}
|
||||
if (pos != string::npos && pos == 2 && name[1] >= '0' && name[1] <= '9') {
|
||||
suffix = name.substr(0, 2);
|
||||
@@ -375,16 +379,16 @@ class FileReader {
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** whether this instance supports rows with defaults (starting with a star). */
|
||||
bool m_supportsDefaults;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** a @a string describing the last error position. */
|
||||
string m_lastError;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_FILEREADER_H_
|
||||
#endif // LIB_EBUS_FILEREADER_H_
|
||||
|
||||
+148
-125
@@ -83,18 +83,15 @@ Message::Message(const string circuit, const string name,
|
||||
const bool isWrite, const bool isPassive,
|
||||
const unsigned char pb, const unsigned char sb,
|
||||
DataField* data, const bool deleteData)
|
||||
: m_circuit(circuit), m_name(name), m_isWrite(isWrite),
|
||||
m_isPassive(isPassive), m_comment(),
|
||||
m_srcAddress(SYN), m_dstAddress(SYN),
|
||||
m_data(data), m_deleteData(true),
|
||||
m_pollPriority(0),
|
||||
m_usedByCondition(false), m_isScanMessage(false), m_condition(NULL),
|
||||
m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) {
|
||||
: m_circuit(circuit), m_name(name), m_isWrite(isWrite), m_isPassive(isPassive), m_comment(), m_srcAddress(SYN),
|
||||
m_dstAddress(SYN), m_data(data), m_deleteData(true), m_pollPriority(0), m_usedByCondition(false),
|
||||
m_isScanMessage(false), m_condition(NULL), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0),
|
||||
m_lastPollTime(0) {
|
||||
m_id.push_back(pb);
|
||||
m_id.push_back(sb);
|
||||
uint64_t key = 0;
|
||||
if (!isPassive) {
|
||||
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
}
|
||||
key |= (uint64_t)SYN << (8 * 6);
|
||||
key |= (uint64_t)pb << (8 * 5);
|
||||
@@ -116,7 +113,8 @@ Message::Message(const string circuit, const string name,
|
||||
* empty and @p replaceStar is @p true.
|
||||
* @return the default if available and value is empty, or the value.
|
||||
*/
|
||||
string getDefault(const string value, vector<string>* defaults, size_t pos, bool replaceStar = false, bool required = false) {
|
||||
string getDefault(const string value, vector<string>* defaults, size_t pos, bool replaceStar = false,
|
||||
bool required = false) {
|
||||
if (defaults == NULL || pos >= defaults->size()) {
|
||||
return value;
|
||||
}
|
||||
@@ -139,9 +137,9 @@ uint64_t Message::createKey(const vector<unsigned char> id,
|
||||
const unsigned char srcAddress, const unsigned char dstAddress) {
|
||||
uint64_t key = (uint64_t)(id.size()-2) << (8 * 7 + 5);
|
||||
if (isPassive) {
|
||||
key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25
|
||||
key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25
|
||||
} else {
|
||||
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active
|
||||
}
|
||||
key |= (uint64_t)dstAddress << (8 * 6);
|
||||
int exp = 5;
|
||||
@@ -166,10 +164,10 @@ uint64_t Message::createKey(SymbolString& master, unsigned char maxIdLength, boo
|
||||
return INVALID_KEY;
|
||||
}
|
||||
uint64_t key = (uint64_t)idLength << (8 * 7 + 5);
|
||||
key |= (uint64_t)getMasterNumber(master[0]) << (8 * 7); // QQ address for passive message
|
||||
key |= (uint64_t)(anyDestination ? SYN : master[1]) << (8 * 6); // ZZ address
|
||||
key |= (uint64_t)master[2] << (8 * 5); // PB
|
||||
key |= (uint64_t)master[3] << (8 * 4); // SB
|
||||
key |= (uint64_t)getMasterNumber(master[0]) << (8 * 7); // QQ address for passive message
|
||||
key |= (uint64_t)(anyDestination ? SYN : master[1]) << (8 * 6); // ZZ address
|
||||
key |= (uint64_t)master[2] << (8 * 5); // PB
|
||||
key |= (uint64_t)master[3] << (8 * 4); // SB
|
||||
int exp = 3;
|
||||
for (unsigned char i = 0; i < idLength; i++) {
|
||||
key ^= (uint64_t)master[5 + i] << (8 * exp--);
|
||||
@@ -186,20 +184,20 @@ result_t Message::parseId(string input, vector<unsigned char>& id) {
|
||||
while (in.peek() == ' ') {
|
||||
in.get();
|
||||
}
|
||||
if (in.eof()) { // no more digits
|
||||
if (in.eof()) { // no more digits
|
||||
break;
|
||||
}
|
||||
input.clear();
|
||||
input.push_back(static_cast<char>(in.get()));
|
||||
if (in.eof()) {
|
||||
return RESULT_ERR_INVALID_ARG; // too short hex
|
||||
return RESULT_ERR_INVALID_ARG; // too short hex
|
||||
}
|
||||
input.push_back(static_cast<char>(in.get()));
|
||||
|
||||
result_t result;
|
||||
unsigned char value = (unsigned char)parseInt(input.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid hex value
|
||||
return result; // invalid hex value
|
||||
}
|
||||
id.push_back(value);
|
||||
}
|
||||
@@ -219,28 +217,28 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
string typeStr = *it++;
|
||||
const char* str = typeStr.c_str(); // [type]
|
||||
const char* str = typeStr.c_str(); // [type]
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
size_t len = strlen(str);
|
||||
if (len == 0) { // default: active read
|
||||
if (len == 0) { // default: active read
|
||||
defaultName = "r";
|
||||
} else {
|
||||
defaultName = str;
|
||||
char type = str[0];
|
||||
if (type == 'r' || type == 'R') { // active read
|
||||
if (type == 'r' || type == 'R') { // active read
|
||||
char poll = str[1];
|
||||
if (poll >= '0' && poll <= '9') { // poll priority (=active read)
|
||||
if (poll >= '0' && poll <= '9') { // poll priority (=active read)
|
||||
pollPriority = (unsigned char)(poll - '0');
|
||||
defaultName.erase(1, 1); // cut off priority digit
|
||||
defaultName.erase(1, 1); // cut off priority digit
|
||||
}
|
||||
} else if (type == 'w' || type == 'W') { // active write
|
||||
} else if (type == 'w' || type == 'W') { // active write
|
||||
isWrite = true;
|
||||
} else { // any other: passive read/write
|
||||
} else { // any other: passive read/write
|
||||
isPassive = true;
|
||||
type = str[1];
|
||||
isWrite = type == 'w' || type == 'W'; // if type continues with "w" it is treated as passive write
|
||||
isWrite = type == 'w' || type == 'W'; // if type continues with "w" it is treated as passive write
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,28 +253,28 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
}
|
||||
}
|
||||
|
||||
string circuit = getDefault(*it++, defaults, defaultPos++, true); // [circuit]
|
||||
string circuit = getDefault(*it++, defaults, defaultPos++, true); // [circuit]
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
string name = getDefault(*it++, defaults, defaultPos++, true, true); // name
|
||||
string name = getDefault(*it++, defaults, defaultPos++, true, true); // name
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
if (name.length() == 0) {
|
||||
return RESULT_ERR_INVALID_ARG; // empty name
|
||||
return RESULT_ERR_INVALID_ARG; // empty name
|
||||
}
|
||||
string comment = getDefault(*it++, defaults, defaultPos++, true); // [comment]
|
||||
string comment = getDefault(*it++, defaults, defaultPos++, true); // [comment]
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [QQ[;QQ]*]
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [QQ[;QQ]*]
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
unsigned char srcAddress;
|
||||
if (*str == 0) {
|
||||
srcAddress = SYN; // no specific source
|
||||
srcAddress = SYN; // no specific source
|
||||
} else {
|
||||
srcAddress = (unsigned char)parseInt(str, 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK) {
|
||||
@@ -287,14 +285,14 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
}
|
||||
}
|
||||
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [ZZ]
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str(); // [ZZ]
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
vector<unsigned char> dstAddresses;
|
||||
bool isBroadcastOrMasterDestination = false;
|
||||
if (*str == 0) {
|
||||
dstAddresses.push_back(SYN); // no specific destination
|
||||
dstAddresses.push_back(SYN); // no specific destination
|
||||
} else {
|
||||
istringstream stream(str);
|
||||
string token;
|
||||
@@ -320,7 +318,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
}
|
||||
|
||||
vector<unsigned char> id;
|
||||
string token = *it++; // [PBSB]
|
||||
string token = *it++; // [PBSB]
|
||||
bool useDefaults = token.empty();
|
||||
if (useDefaults) {
|
||||
token = getDefault(token, defaults, defaultPos);
|
||||
@@ -331,12 +329,12 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
return result;
|
||||
}
|
||||
if (id.size() != 2) {
|
||||
return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB
|
||||
return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB
|
||||
}
|
||||
if (it == end) {
|
||||
token = "";
|
||||
} else {
|
||||
token = *it++;// [ID] (optional master data)
|
||||
token = *it++; // [ID] (optional master data)
|
||||
}
|
||||
string defaultIdPrefix;
|
||||
if (useDefaults) {
|
||||
@@ -406,7 +404,8 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
}
|
||||
vector<string>::iterator realEnd = end;
|
||||
vector<string> newTypes;
|
||||
if (defaults != NULL && defaults->size() > defaultPos + 2) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
|
||||
if (defaults != NULL && defaults->size() > defaultPos + 2) {
|
||||
// need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
|
||||
while (defaults->size() > defaultPos + 2 && defaults->at(defaultPos + 2).size() > 0) {
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
if (defaults->size() > defaultPos) {
|
||||
@@ -430,12 +429,14 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
vector<SingleDataField*> fields;
|
||||
data = new DataFieldSet("", "", fields);
|
||||
} else {
|
||||
result = DataField::create(it, realEnd, templates, data, isWrite, false, isBroadcastOrMasterDestination, (unsigned char)maxLength);
|
||||
result = DataField::create(it, realEnd, templates, data, isWrite, false, isBroadcastOrMasterDestination,
|
||||
(unsigned char)maxLength);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (id.size() + data->getLength(pt_masterData, (unsigned char)maxLength) > 2 + maxLength || data->getLength(pt_slaveData, (unsigned char)maxLength) > maxLength) {
|
||||
if (id.size() + data->getLength(pt_masterData, (unsigned char)maxLength) > 2 + maxLength
|
||||
|| data->getLength(pt_slaveData, (unsigned char)maxLength) > maxLength) {
|
||||
// max NN exceeded
|
||||
delete data;
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
@@ -452,9 +453,11 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
}
|
||||
Message* message;
|
||||
if (chainIds.size() > 1) {
|
||||
message = new ChainedMessage(useCircuit, name, isWrite, comment, srcAddress, dstAddress, id, chainIds, chainLengths, data, index == 0, pollPriority, condition);
|
||||
message = new ChainedMessage(useCircuit, name, isWrite, comment, srcAddress, dstAddress, id, chainIds,
|
||||
chainLengths, data, index == 0, pollPriority, condition);
|
||||
} else {
|
||||
message = new Message(useCircuit, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data, index == 0, pollPriority, condition);
|
||||
message = new Message(useCircuit, name, isWrite, isPassive, comment, srcAddress, dstAddress, id, data,
|
||||
index == 0, pollPriority, condition);
|
||||
}
|
||||
messages.push_back(message);
|
||||
}
|
||||
@@ -500,7 +503,7 @@ bool Message::checkIdPrefix(vector<unsigned char>& id) {
|
||||
|
||||
bool Message::checkId(SymbolString& master, unsigned char* index) {
|
||||
unsigned char idLen = getIdLength();
|
||||
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
|
||||
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
|
||||
return false;
|
||||
}
|
||||
for (unsigned char pos = 0; pos < idLen; pos++) {
|
||||
@@ -516,7 +519,7 @@ bool Message::checkId(SymbolString& master, unsigned char* index) {
|
||||
|
||||
bool Message::checkId(Message& other) {
|
||||
unsigned char idLen = getIdLength();
|
||||
if (idLen != other.getIdLength() || getCount() > 1) { // only equal for non-chained messages
|
||||
if (idLen != other.getIdLength() || getCount() > 1) { // only equal for non-chained messages
|
||||
return false;
|
||||
}
|
||||
return other.checkIdPrefix(m_id);
|
||||
@@ -560,7 +563,7 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma
|
||||
istringstream& input, char separator,
|
||||
const unsigned char dstAddress, unsigned char index) {
|
||||
if (m_isPassive) {
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
}
|
||||
SymbolString master(false);
|
||||
result_t result = master.push_back(srcAddress, false, false);
|
||||
@@ -604,7 +607,7 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
unsigned char pos = master.size();
|
||||
result_t result = master.push_back(0, false, false); // length, will be set later
|
||||
result_t result = master.push_back(0, false, false); // length, will be set later
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -624,10 +627,10 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
|
||||
|
||||
result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) {
|
||||
if (m_isWrite) {
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
}
|
||||
SymbolString slave(false);
|
||||
result_t result = slave.push_back(0, false, false); // length, will be set later
|
||||
result_t result = slave.push_back(0, false, false); // length, will be set later
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -661,11 +664,11 @@ result_t Message::storeLastData(const PartType partType, SymbolString& data, uns
|
||||
}
|
||||
if (partType == pt_masterData) {
|
||||
switch (data.compareMaster(m_lastMasterData)) {
|
||||
case 1: // completely different
|
||||
case 1: // completely different
|
||||
m_lastChangeTime = m_lastUpdateTime;
|
||||
m_lastMasterData = data;
|
||||
break;
|
||||
case 2: // only master address is different
|
||||
case 2: // only master address is different
|
||||
m_lastMasterData = data;
|
||||
break;
|
||||
}
|
||||
@@ -687,7 +690,8 @@ result_t Message::decodeLastData(const PartType partType,
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
result_t result = m_data->read(partType, partType == pt_masterData ? m_lastMasterData : m_lastSlaveData, offset, output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
|
||||
result_t result = m_data->read(partType, partType == pt_masterData ? m_lastMasterData : m_lastSlaveData, offset,
|
||||
output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -700,18 +704,20 @@ result_t Message::decodeLastData(const PartType partType,
|
||||
result_t Message::decodeLastData(ostringstream& output, OutputFormat outputFormat,
|
||||
bool leadingSeparator, const char* fieldName, signed char fieldIndex) {
|
||||
size_t startPos = output.str().length();
|
||||
result_t result = m_data->read(pt_masterData, m_lastMasterData, getIdLength(), output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
|
||||
result_t result = m_data->read(pt_masterData, m_lastMasterData, getIdLength(), output, outputFormat, -1,
|
||||
leadingSeparator, fieldName, fieldIndex);
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
bool empty = result == RESULT_EMPTY;
|
||||
leadingSeparator |= output.str().length() > startPos;
|
||||
result = m_data->read(pt_slaveData, m_lastSlaveData, 0, output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex);
|
||||
result = m_data->read(pt_slaveData, m_lastSlaveData, 0, output, outputFormat, -1, leadingSeparator, fieldName,
|
||||
fieldIndex);
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
if (result == RESULT_EMPTY && !empty) {
|
||||
result = RESULT_OK; // OK if at least one part was non-empty
|
||||
result = RESULT_OK; // OK if at least one part was non-empty
|
||||
} else if (result == RESULT_EMPTY && fieldName != NULL) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
@@ -774,7 +780,7 @@ void Message::dump(ostream& output, vector<size_t>* columns, bool withConditions
|
||||
|
||||
void Message::dumpColumn(ostream& output, size_t column, bool withConditions) {
|
||||
switch (column) {
|
||||
case COLUMN_TYPE: // type
|
||||
case COLUMN_TYPE: // type
|
||||
if (withConditions && m_condition != NULL) {
|
||||
m_condition->dump(output);
|
||||
}
|
||||
@@ -792,36 +798,36 @@ void Message::dumpColumn(ostream& output, size_t column, bool withConditions) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COLUMN_CIRCUIT: // circuit
|
||||
case COLUMN_CIRCUIT: // circuit
|
||||
DataField::dumpString(output, m_circuit, false);
|
||||
break;
|
||||
case COLUMN_NAME: // name
|
||||
case COLUMN_NAME: // name
|
||||
DataField::dumpString(output, m_name, false);
|
||||
break;
|
||||
case COLUMN_COMMENT: // comment
|
||||
case COLUMN_COMMENT: // comment
|
||||
DataField::dumpString(output, m_comment, false);
|
||||
break;
|
||||
case COLUMN_QQ: // QQ
|
||||
case COLUMN_QQ: // QQ
|
||||
if (m_srcAddress != SYN) {
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_srcAddress);
|
||||
}
|
||||
break;
|
||||
case COLUMN_ZZ: // ZZ
|
||||
case COLUMN_ZZ: // ZZ
|
||||
if (m_dstAddress != SYN) {
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress);
|
||||
}
|
||||
break;
|
||||
case COLUMN_PBSB: // PBSB
|
||||
case COLUMN_PBSB: // PBSB
|
||||
for (vector<unsigned char>::const_iterator it = m_id.begin(); it < m_id.begin()+2 && it < m_id.end(); it++) {
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(*it);
|
||||
}
|
||||
break;
|
||||
case COLUMN_ID: // ID
|
||||
case COLUMN_ID: // ID
|
||||
for (vector<unsigned char>::const_iterator it = m_id.begin()+2; it < m_id.end(); it++) {
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(*it);
|
||||
}
|
||||
break;
|
||||
case COLUMN_FIELDS: // fields
|
||||
case COLUMN_FIELDS: // fields
|
||||
m_data->dump(output);
|
||||
break;
|
||||
}
|
||||
@@ -840,7 +846,7 @@ ChainedMessage::ChainedMessage(const string circuit, const string name,
|
||||
srcAddress, dstAddress, id,
|
||||
data, deleteData, pollPriority, condition),
|
||||
m_ids(ids), m_lengths(lengths),
|
||||
m_maxTimeDiff(m_ids.size()*15) { // 15 seconds per message
|
||||
m_maxTimeDiff(m_ids.size()*15) { // 15 seconds per message
|
||||
size_t cnt = ids.size();
|
||||
m_lastMasterDatas = reinterpret_cast<SymbolString**>(calloc(cnt, sizeof(SymbolString*)));
|
||||
m_lastSlaveDatas = reinterpret_cast<SymbolString**>(calloc(cnt, sizeof(SymbolString*)));
|
||||
@@ -879,16 +885,16 @@ Message* ChainedMessage::derive(const unsigned char dstAddress, const unsigned c
|
||||
|
||||
bool ChainedMessage::checkId(SymbolString& master, unsigned char* index) {
|
||||
unsigned char idLen = getIdLength();
|
||||
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
|
||||
if (master.size() < 5+idLen) { // QQ, ZZ, PB, SB, NN
|
||||
return false;
|
||||
}
|
||||
unsigned char chainPrefixLength = Message::getIdLength();
|
||||
for (unsigned char pos = 0; pos < chainPrefixLength; pos++) {
|
||||
if (m_id[2+pos] != master[5+pos]) {
|
||||
return false; // chain prefix mismatch
|
||||
return false; // chain prefix mismatch
|
||||
}
|
||||
}
|
||||
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
|
||||
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
|
||||
vector<unsigned char> id = m_ids[checkIndex];
|
||||
bool found = false;
|
||||
for (unsigned char pos = chainPrefixLength; pos < idLen; pos++) {
|
||||
@@ -910,15 +916,15 @@ bool ChainedMessage::checkId(SymbolString& master, unsigned char* index) {
|
||||
|
||||
bool ChainedMessage::checkId(Message& other) {
|
||||
unsigned char idLen = getIdLength();
|
||||
if (idLen != other.getIdLength() || other.getCount() == 1) { // only equal for chained messages
|
||||
if (idLen != other.getIdLength() || other.getCount() == 1) { // only equal for chained messages
|
||||
return false;
|
||||
}
|
||||
if (!other.checkIdPrefix(m_id)) {
|
||||
return false; // chain prefix mismatch
|
||||
return false; // chain prefix mismatch
|
||||
}
|
||||
vector< vector<unsigned char> > otherIds = ((ChainedMessage&)other).m_ids;
|
||||
unsigned char chainPrefixLength = Message::getIdLength();
|
||||
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
|
||||
for (unsigned char checkIndex = 0; checkIndex < m_ids.size(); checkIndex++) { // check suffix for each part
|
||||
vector<unsigned char> id = m_ids[checkIndex];
|
||||
for (unsigned char otherIndex = 0; otherIndex < otherIds.size(); otherIndex++) {
|
||||
vector<unsigned char> otherId = otherIds[otherIndex];
|
||||
@@ -938,7 +944,8 @@ bool ChainedMessage::checkId(Message& other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index) {
|
||||
result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream& input, char separator,
|
||||
unsigned char index) {
|
||||
size_t cnt = getCount();
|
||||
if (index >= cnt) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
@@ -960,7 +967,7 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
vector<unsigned char> id = m_ids[index];
|
||||
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN
|
||||
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -1003,10 +1010,10 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
|
||||
}
|
||||
if (partType == pt_masterData) {
|
||||
switch (data.compareMaster(*m_lastMasterDatas[index])) {
|
||||
case 1: // completely different
|
||||
case 1: // completely different
|
||||
*m_lastMasterDatas[index] = data;
|
||||
break;
|
||||
case 2: // only master address is different
|
||||
case 2: // only master address is different
|
||||
*m_lastMasterDatas[index] = data;
|
||||
break;
|
||||
}
|
||||
@@ -1043,7 +1050,7 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
|
||||
// everything was completely retrieved in short time
|
||||
SymbolString master(false);
|
||||
SymbolString slave(false);
|
||||
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
|
||||
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
|
||||
for (index = 0; index < m_ids.size(); index++) {
|
||||
SymbolString* add = m_lastMasterDatas[index];
|
||||
size_t end = 5+(*add)[4];
|
||||
@@ -1166,7 +1173,8 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
|
||||
valueRanges.push_back(0);
|
||||
}
|
||||
bool inclusive = str[1] == '=';
|
||||
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1, inclusive?UINT_MAX:(UINT_MAX-1), result);
|
||||
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1,
|
||||
inclusive?UINT_MAX:(UINT_MAX-1), result);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -1176,14 +1184,14 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
|
||||
}
|
||||
} else {
|
||||
size_t pos = str.find('-');
|
||||
if (pos != string::npos && pos > 0) { // range
|
||||
if (pos != string::npos && pos > 0) { // range
|
||||
unsigned int val = parseInt(str.substr(0, pos).c_str(), 10, 0, UINT_MAX, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
valueRanges.push_back(val);
|
||||
pos++;
|
||||
} else { // single value
|
||||
} else { // single value
|
||||
pos = 0;
|
||||
}
|
||||
unsigned int val = parseInt(str.substr(pos).c_str(), 10, 0, UINT_MAX, result);
|
||||
@@ -1192,22 +1200,23 @@ result_t splitValues(string valueList, vector<unsigned int>& valueRanges) {
|
||||
}
|
||||
valueRanges.push_back(val);
|
||||
if (pos == 0) {
|
||||
valueRanges.push_back(val); // single value
|
||||
valueRanges.push_back(val); // single value
|
||||
}
|
||||
}
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue) {
|
||||
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end,
|
||||
string defaultDest, string defaultCircuit, SimpleCondition*& returnValue) {
|
||||
// name,circuit,messagename,[comment],[fieldname],[ZZ],values (name already skipped by caller)
|
||||
string circuit = it == end ? "" : *(it++); // circuit
|
||||
string name = it == end ? "" : *(it++); // messagename
|
||||
string circuit = it == end ? "" : *(it++); // circuit
|
||||
string name = it == end ? "" : *(it++); // messagename
|
||||
if (it < end) {
|
||||
it++; // comment
|
||||
it++; // comment
|
||||
}
|
||||
string field = it == end ? "" : *(it++); // fieldname
|
||||
string zz = it == end ? "" : *(it++); // ZZ
|
||||
string field = it == end ? "" : *(it++); // fieldname
|
||||
string zz = it == end ? "" : *(it++); // ZZ
|
||||
unsigned char dstAddress = SYN;
|
||||
result_t result = RESULT_OK;
|
||||
if (zz.length() == 0) {
|
||||
@@ -1304,12 +1313,14 @@ CombinedCondition* SimpleCondition::combineAnd(Condition* other) {
|
||||
return ret->combineAnd(this)->combineAnd(other);
|
||||
}
|
||||
|
||||
result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)) {
|
||||
result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage,
|
||||
void (*readMessageFunc)(Message* message)) {
|
||||
if (m_message == NULL) {
|
||||
Message* message;
|
||||
if (m_name.length() == 0) {
|
||||
message = messages->getScanMessage(m_dstAddress);
|
||||
errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(m_dstAddress);
|
||||
errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0')
|
||||
<< static_cast<unsigned>(m_dstAddress);
|
||||
} else {
|
||||
message = messages->find(m_circuit, m_name, false);
|
||||
if (!message) {
|
||||
@@ -1339,7 +1350,8 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess
|
||||
} else {
|
||||
Message* first = getFirstAvailable(*derived, message);
|
||||
if (first == NULL) {
|
||||
errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName() << " for " << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress) << " not found";
|
||||
errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName()
|
||||
<< " for " << hex << setw(2) << setfill('0') << static_cast<unsigned>(m_dstAddress) << " not found";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
message = first;
|
||||
@@ -1369,7 +1381,7 @@ bool SimpleCondition::isTrue() {
|
||||
return false;
|
||||
}
|
||||
if (m_message->getLastChangeTime() > m_lastCheckTime) {
|
||||
bool isTrue = !m_hasValues; // for message seen check
|
||||
bool isTrue = !m_hasValues; // for message seen check
|
||||
if (!isTrue) {
|
||||
isTrue = checkValue(m_message, m_field);
|
||||
}
|
||||
@@ -1420,7 +1432,8 @@ void CombinedCondition::dump(ostream& output, bool matched) {
|
||||
}
|
||||
}
|
||||
|
||||
result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)) {
|
||||
result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage,
|
||||
void (*readMessageFunc)(Message* message)) {
|
||||
for (vector<Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
|
||||
Condition* condition = *it;
|
||||
ostringstream dummy;
|
||||
@@ -1443,8 +1456,9 @@ bool CombinedCondition::isTrue() {
|
||||
}
|
||||
|
||||
|
||||
result_t Instruction::create(const string contextPath, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue) {
|
||||
result_t Instruction::create(const string contextPath, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, Condition* condition, const string type, vector<string>::iterator& it,
|
||||
const vector<string>::iterator end, Instruction*& returnValue) {
|
||||
// type[,argument]* (type already skipped by caller)
|
||||
bool singleton = false;
|
||||
if ((singleton=(type == "load")) || type == "include") {
|
||||
@@ -1494,7 +1508,8 @@ result_t LoadInstruction::execute(MessageMap* messages, ostringstream& log, Cond
|
||||
log << ", ";
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \"" << getDestination() << "\": " << getResultCode(result);
|
||||
log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \""
|
||||
<< getDestination() << "\": " << getResultCode(result);
|
||||
return result;
|
||||
}
|
||||
log << (isSingleton() ? "loaded \"" : "included \"") << m_filename << "\" for \"" << getDestination() << "\"";
|
||||
@@ -1532,10 +1547,10 @@ result_t MessageMap::add(Message* message, bool storeByName) {
|
||||
Message* other = getFirstAvailable(keyIt->second, message);
|
||||
if (other != NULL) {
|
||||
if (!conditional) {
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
}
|
||||
if (!other->isConditional()) {
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1553,23 +1568,26 @@ result_t MessageMap::add(Message* message, bool storeByName) {
|
||||
if (nameIt != m_messagesByName.end()) {
|
||||
vector<Message*>* messages = &nameIt->second;
|
||||
if (!message->isConditional() || !messages->front()->isConditional()) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
}
|
||||
}
|
||||
}
|
||||
m_messagesByName[nameKey].push_back(message);
|
||||
|
||||
nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit
|
||||
nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit
|
||||
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
|
||||
if (nameIt == m_messagesByName.end()) {
|
||||
m_messagesByName[nameKey].push_back(message); // always store first message without circuit (in order of circuit name)
|
||||
// always store first message without circuit (in order of circuit name)
|
||||
m_messagesByName[nameKey].push_back(message);
|
||||
} else {
|
||||
vector<Message*>* messages = &nameIt->second;
|
||||
Message* first = messages->front();
|
||||
if (circuit < first->getCircuit()) {
|
||||
m_messagesByName[nameKey].at(0) = message; // always store first message without circuit (in order of circuit name)
|
||||
// always store first message without circuit (in order of circuit name)
|
||||
m_messagesByName[nameKey].at(0) = message;
|
||||
} else if (m_addAll || (conditional && first->isConditional())) {
|
||||
m_messagesByName[nameKey].push_back(message); // store further messages only if both are conditional or if storing everything
|
||||
// store further messages only if both are conditional or if storing everything
|
||||
m_messagesByName[nameKey].push_back(message);
|
||||
}
|
||||
}
|
||||
m_messageCount++;
|
||||
@@ -1618,22 +1636,26 @@ result_t MessageMap::addDefaultFromFile(vector< vector<string> >& defaults, vect
|
||||
}
|
||||
if (row.size() > 1 && defaultCircuit.length() > 0) {
|
||||
if (row[1].length() == 0) {
|
||||
row[1] = defaultCircuit+defaultSuffix; // set default circuit and suffix: "circuit[.suffix]"
|
||||
row[1] = defaultCircuit+defaultSuffix; // set default circuit and suffix: "circuit[.suffix]"
|
||||
} else if (row[1][0] == '#') {
|
||||
row[1] = defaultCircuit+defaultSuffix+row[1]; // move security suffix behind default circuit and suffix: "circuit[.suffix]#security"
|
||||
} else if (defaultSuffix.length() > 0 && row[1].find_last_of('.') == string::npos) { // circuit suffix not yet present
|
||||
// move security suffix behind default circuit and suffix: "circuit[.suffix]#security"
|
||||
row[1] = defaultCircuit+defaultSuffix+row[1];
|
||||
} else if (defaultSuffix.length() > 0 && row[1].find_last_of('.') == string::npos) {
|
||||
// circuit suffix not yet present
|
||||
size_t pos = row[1].find_first_of('#');
|
||||
if (pos == string::npos) {
|
||||
row[1] += defaultSuffix; // append default suffix: "circuit.suffix"
|
||||
row[1] += defaultSuffix; // append default suffix: "circuit.suffix"
|
||||
} else {
|
||||
row[1] = row[1].substr(0, pos)+defaultSuffix+row[1].substr(pos); // insert default suffix: "circuit.suffix#security"
|
||||
// insert default suffix: "circuit.suffix#security"
|
||||
row[1] = row[1].substr(0, pos)+defaultSuffix+row[1].substr(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (row.size() > 5 && defaultDest.length() > 0 && row[5].length() == 0) {
|
||||
row[5] = defaultDest; // set default destination
|
||||
row[5] = defaultDest; // set default destination
|
||||
}
|
||||
return FileReader::addDefaultFromFile(defaults, row, begin, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
|
||||
return FileReader::addDefaultFromFile(defaults, row, begin, defaultDest, defaultCircuit, defaultSuffix, filename,
|
||||
lineNo);
|
||||
}
|
||||
|
||||
result_t MessageMap::readConditions(string& types, const string& filename, Condition*& condition) {
|
||||
@@ -1665,7 +1687,7 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
|
||||
m_lastError = "derive condition with values "+key.substr(pos)+" failed";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
m_conditions[key] = add; // store derived condition
|
||||
m_conditions[key] = add; // store derived condition
|
||||
}
|
||||
}
|
||||
if (add == NULL) {
|
||||
@@ -1688,7 +1710,7 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
|
||||
}
|
||||
}
|
||||
if (store) {
|
||||
m_conditions[combinedkey] = condition; // store combined condition
|
||||
m_conditions[combinedkey] = condition; // store combined condition
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1696,8 +1718,8 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
|
||||
}
|
||||
|
||||
result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo) {
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string& filename, unsigned int lineNo) {
|
||||
vector<string>::iterator restart = begin;
|
||||
string types = *restart;
|
||||
Condition* condition = NULL;
|
||||
@@ -1709,7 +1731,8 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
|
||||
// instruction
|
||||
types = types.substr(1);
|
||||
Instruction* instruction = NULL;
|
||||
result_t result = Instruction::create(filename, defaultDest, defaultCircuit, defaultSuffix, condition, types, ++begin, end, instruction);
|
||||
result_t result = Instruction::create(filename, defaultDest, defaultCircuit, defaultSuffix, condition, types,
|
||||
++begin, end, instruction);
|
||||
if (instruction == NULL || result != RESULT_OK) {
|
||||
m_lastError = "invalid instruction";
|
||||
return result;
|
||||
@@ -1745,13 +1768,13 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
|
||||
if (result == RESULT_OK) {
|
||||
result = add(message);
|
||||
if (result == RESULT_ERR_DUPLICATE_NAME) {
|
||||
begin = restart+3; // mark name as invalid
|
||||
begin = restart+3; // mark name as invalid
|
||||
} else if (result == RESULT_ERR_DUPLICATE) {
|
||||
begin = restart+8; // mark ID as invalid
|
||||
begin = restart+8; // mark ID as invalid
|
||||
}
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
delete message; // delete all remaining messages on error
|
||||
delete message; // delete all remaining messages on error
|
||||
}
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
@@ -1906,9 +1929,9 @@ Message* MessageMap::find(const string& circuit, const string& name, const bool
|
||||
if (i == 0) {
|
||||
key = string(isPassive ? "P" : (isWrite ? "W" : "R")) + lcircuit + FIELD_SEPARATOR + lname;
|
||||
} else if (lcircuit.length() == 0) {
|
||||
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit
|
||||
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit
|
||||
} else {
|
||||
continue; // not allowed without circuit
|
||||
continue; // not allowed without circuit
|
||||
}
|
||||
map<string, vector<Message*> >::iterator it = m_messagesByName.find(key);
|
||||
if (it != m_messagesByName.end()) {
|
||||
@@ -1940,7 +1963,7 @@ deque<Message*> MessageMap::findAll(const string& circuit, const string& name, c
|
||||
}
|
||||
}
|
||||
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
|
||||
if (it->first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-"
|
||||
if (it->first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-"
|
||||
continue;
|
||||
}
|
||||
for (vector<Message*>::iterator msgIt = it->second.begin(); msgIt != it->second.end(); msgIt++) {
|
||||
@@ -2032,7 +2055,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
|
||||
}
|
||||
if ((key & ID_SOURCE_MASK) != 0) {
|
||||
key &= ~ID_SOURCE_MASK;
|
||||
it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master
|
||||
it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master);
|
||||
if (message) {
|
||||
@@ -2044,7 +2067,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
|
||||
key &= ~ID_SOURCE_MASK;
|
||||
}
|
||||
if (withRead) {
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master);
|
||||
if (message) {
|
||||
@@ -2053,7 +2076,7 @@ Message* MessageMap::find(SymbolString& master, bool anyDestination,
|
||||
}
|
||||
}
|
||||
if (withWrite) {
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write
|
||||
it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write
|
||||
if (it != m_messagesByKey.end()) {
|
||||
Message* message = getFirstAvailable(it->second, &master);
|
||||
if (message) {
|
||||
@@ -2102,7 +2125,7 @@ void MessageMap::clear() {
|
||||
// free message instances by name
|
||||
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
|
||||
vector<Message*> nameMessages = it->second;
|
||||
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
|
||||
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
|
||||
for (vector<Message*>::iterator nit = nameMessages.begin(); nit != nameMessages.end(); nit++) {
|
||||
Message* message = *nit;
|
||||
map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey());
|
||||
@@ -2163,14 +2186,14 @@ Message* MessageMap::getNextPoll() {
|
||||
m_pollMessages.pop();
|
||||
ret->m_pollCount++;
|
||||
time(&(ret->m_lastPollTime));
|
||||
m_pollMessages.push(ret); // re-insert at new position
|
||||
m_pollMessages.push(ret); // re-insert at new position
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MessageMap::dump(ostream& output, bool withConditions) {
|
||||
bool first = true;
|
||||
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
|
||||
if (it->first[0] == '-') { // skip instances stored multiple times (key starting with "-")
|
||||
if (it->first[0] == '-') { // skip instances stored multiple times (key starting with "-")
|
||||
continue;
|
||||
}
|
||||
if (m_addAll) {
|
||||
@@ -2204,4 +2227,4 @@ void MessageMap::dump(ostream& output, bool withConditions) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+91
-64
@@ -100,7 +100,7 @@ class MessageMap;
|
||||
*/
|
||||
class Message {
|
||||
friend class MessageMap;
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param circuit the optional circuit name.
|
||||
@@ -126,7 +126,7 @@ class Message {
|
||||
Condition* condition = NULL);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Construct a new scan @a Message instance.
|
||||
* @param circuit the circuit name, or empty for not storing by name.
|
||||
@@ -145,7 +145,7 @@ class Message {
|
||||
DataField* data, const bool deleteData);
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
@@ -229,7 +229,8 @@ class Message {
|
||||
* @param circuit the new circuit name, or empty to use the current circuit name.
|
||||
* @return the derived @a Message instance.
|
||||
*/
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN,
|
||||
const string circuit = "");
|
||||
|
||||
/**
|
||||
* Derive a new @a Message from this message.
|
||||
@@ -400,7 +401,7 @@ class Message {
|
||||
const unsigned char dstAddress = SYN, unsigned char index = 0);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* Prepare a part of the master data @a SymbolString for sending (everything including NN).
|
||||
* @param master the master data @a SymbolString for writing symbols to.
|
||||
@@ -412,7 +413,7 @@ class Message {
|
||||
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Prepare the slave @a SymbolString for sending an answer to the bus.
|
||||
* @param input the @a istringstream to parse the formatted value(s) from.
|
||||
@@ -527,7 +528,7 @@ class Message {
|
||||
virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the optional circuit name. */
|
||||
const string m_circuit;
|
||||
|
||||
@@ -618,7 +619,7 @@ class Message {
|
||||
* A chained @a Message that needs more than one read/write on the bus to collect/send the data.
|
||||
*/
|
||||
class ChainedMessage : public Message {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param circuit the optional circuit name.
|
||||
@@ -647,7 +648,8 @@ class ChainedMessage : public Message {
|
||||
virtual ~ChainedMessage();
|
||||
|
||||
// @copydoc
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN,
|
||||
const string circuit = "");
|
||||
|
||||
// @copydoc
|
||||
virtual unsigned char getIdLength() const { return (unsigned char)(m_ids[0].size() - 2); }
|
||||
@@ -662,12 +664,12 @@ class ChainedMessage : public Message {
|
||||
virtual unsigned char getCount() { return (unsigned char)m_ids.size(); }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
// @copydoc
|
||||
virtual result_t storeLastData(SymbolString& master, SymbolString& slave);
|
||||
|
||||
@@ -675,12 +677,12 @@ class ChainedMessage : public Message {
|
||||
virtual result_t storeLastData(const PartType partType, SymbolString& data, unsigned char index);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the primary, secondary, and optional further ID bytes for each part of the chain. */
|
||||
const vector< vector<unsigned char> > m_ids;
|
||||
|
||||
@@ -723,7 +725,7 @@ struct compareMessagePriority : binary_function<Message*, Message*, bool> {
|
||||
*/
|
||||
class MessagePriorityQueue
|
||||
: public priority_queue<Message*, vector<Message*>, compareMessagePriority> {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Add data to the queue and ensure it is contained only once.
|
||||
* @param __x the element to add.
|
||||
@@ -744,7 +746,7 @@ class MessagePriorityQueue
|
||||
* An abstract condition based on the value of one or more @a Message instances.
|
||||
*/
|
||||
class Condition {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -766,7 +768,8 @@ class Condition {
|
||||
* @param returnValue the variable in which to store the created instance.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
static result_t create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue);
|
||||
static result_t create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end,
|
||||
string defaultDest, string defaultCircuit, SimpleCondition*& returnValue);
|
||||
|
||||
/**
|
||||
* Derive a new @a SimpleCondition from this condition.
|
||||
@@ -796,7 +799,8 @@ class Condition {
|
||||
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL) = 0;
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
|
||||
void (*readMessageFunc)(Message* message) = NULL) = 0;
|
||||
|
||||
/**
|
||||
* Check and return whether this condition is fulfilled.
|
||||
@@ -805,7 +809,7 @@ class Condition {
|
||||
virtual bool isTrue() = 0;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the system time when the condition was last checked, 0 for never. */
|
||||
time_t m_lastCheckTime;
|
||||
|
||||
@@ -818,20 +822,23 @@ class Condition {
|
||||
* A simple @a Condition based on the value of one @a Message.
|
||||
*/
|
||||
class SimpleCondition : public Condition {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
* @param refName the reference name for dumping.
|
||||
* @param circuit the circuit name.
|
||||
* @param name the message name, or empty for scan message.
|
||||
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message).
|
||||
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination
|
||||
* as well as scan message).
|
||||
* @param field the field name.
|
||||
* @param hasValues whether a value has to be checked against.
|
||||
*/
|
||||
SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues = false)
|
||||
SimpleCondition(const string condName, const string refName, const string circuit, const string name,
|
||||
const unsigned char dstAddress, const string field, const bool hasValues = false)
|
||||
: Condition(),
|
||||
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
|
||||
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress),
|
||||
m_field(field), m_hasValues(hasValues), m_message(NULL) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -848,7 +855,8 @@ class SimpleCondition : public Condition {
|
||||
virtual CombinedCondition* combineAnd(Condition* other);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
|
||||
void (*readMessageFunc)(Message* message) = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool isTrue();
|
||||
@@ -860,7 +868,7 @@ class SimpleCondition : public Condition {
|
||||
virtual bool isNumeric() { return true; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* Check the values against the field in the @a Message.
|
||||
* @param message the @a Message to check against.
|
||||
@@ -873,7 +881,7 @@ class SimpleCondition : public Condition {
|
||||
string m_matchedValue;
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the condition name. */
|
||||
const string m_condName;
|
||||
|
||||
@@ -886,7 +894,8 @@ class SimpleCondition : public Condition {
|
||||
/** the message name, or empty for scan message. */
|
||||
const string m_name;
|
||||
|
||||
/** the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message). */
|
||||
/** the override destination address, or @a SYN (only for @a Message without specific destination as well as scan
|
||||
* message). */
|
||||
const unsigned char m_dstAddress;
|
||||
|
||||
/** the field name, or empty for first field. */
|
||||
@@ -904,7 +913,7 @@ class SimpleCondition : public Condition {
|
||||
* A simple @a Condition based on the numeric value of one @a Message.
|
||||
*/
|
||||
class SimpleNumericCondition : public SimpleCondition {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
@@ -915,7 +924,8 @@ class SimpleNumericCondition : public SimpleCondition {
|
||||
* @param field the field name.
|
||||
* @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check.
|
||||
*/
|
||||
SimpleNumericCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
|
||||
SimpleNumericCondition(const string condName, const string refName, const string circuit, const string name,
|
||||
const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
|
||||
: SimpleCondition(condName, refName, circuit, name, dstAddress, field, true),
|
||||
m_valueRanges(valueRanges) { }
|
||||
|
||||
@@ -925,12 +935,12 @@ class SimpleNumericCondition : public SimpleCondition {
|
||||
virtual ~SimpleNumericCondition() {}
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */
|
||||
const vector<unsigned int> m_valueRanges;
|
||||
};
|
||||
@@ -940,7 +950,7 @@ class SimpleNumericCondition : public SimpleCondition {
|
||||
* A simple @a Condition based on the string value of one @a Message.
|
||||
*/
|
||||
class SimpleStringCondition : public SimpleCondition {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
@@ -951,7 +961,8 @@ class SimpleStringCondition : public SimpleCondition {
|
||||
* @param field the field name.
|
||||
* @param values the valid values.
|
||||
*/
|
||||
SimpleStringCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<string> values)
|
||||
SimpleStringCondition(const string condName, const string refName, const string circuit, const string name,
|
||||
const unsigned char dstAddress, const string field, const vector<string> values)
|
||||
: SimpleCondition(condName, refName, circuit, name, dstAddress, field, true),
|
||||
m_values(values) { }
|
||||
|
||||
@@ -964,12 +975,12 @@ class SimpleStringCondition : public SimpleCondition {
|
||||
virtual bool isNumeric() { return false; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the valid values. */
|
||||
const vector<string> m_values;
|
||||
};
|
||||
@@ -979,7 +990,7 @@ class SimpleStringCondition : public SimpleCondition {
|
||||
* A @a Condition combining two or more @a SimpleCondition instances with a logical and.
|
||||
*/
|
||||
class CombinedCondition : public Condition {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -998,13 +1009,14 @@ class CombinedCondition : public Condition {
|
||||
virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; }
|
||||
|
||||
// @copydoc
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage,
|
||||
void (*readMessageFunc)(Message* message) = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool isTrue();
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the @a Condition instances used. */
|
||||
vector<Condition*> m_conditions;
|
||||
};
|
||||
@@ -1014,17 +1026,20 @@ class CombinedCondition : public Condition {
|
||||
* An abstract instruction based on the value of one or more @a Message instances.
|
||||
*/
|
||||
class Instruction {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be
|
||||
* executed for the same source file.
|
||||
* @param defaultDest the default destination address, or empty.
|
||||
* @param defaultCircuit the default circuit name, or empty.
|
||||
* @param defaultSuffix the default circuit name suffix (starting with a "."), or empty.
|
||||
*/
|
||||
Instruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix)
|
||||
: m_condition(condition), m_singleton(singleton), m_defaultDest(defaultDest), m_defaultCircuit(defaultCircuit), m_defaultSuffix(defaultSuffix) { }
|
||||
Instruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix)
|
||||
: m_condition(condition), m_singleton(singleton), m_defaultDest(defaultDest), m_defaultCircuit(defaultCircuit),
|
||||
m_defaultSuffix(defaultSuffix) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -1044,8 +1059,9 @@ class Instruction {
|
||||
* @param returnValue the variable in which to store the created instance.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
static result_t create(const string contextPath, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue);
|
||||
static result_t create(const string contextPath, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, Condition* condition, const string type, vector<string>::iterator& it,
|
||||
const vector<string>::iterator end, Instruction*& returnValue);
|
||||
|
||||
/**
|
||||
* Return the @a Condition this instruction requires.
|
||||
@@ -1054,8 +1070,10 @@ class Instruction {
|
||||
Condition* getCondition() { return m_condition; }
|
||||
|
||||
/**
|
||||
* Return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* @return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* Return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed
|
||||
* for the same source file.
|
||||
* @return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed
|
||||
* for the same source file.
|
||||
*/
|
||||
bool isSingleton() { return m_singleton; }
|
||||
|
||||
@@ -1075,15 +1093,16 @@ class Instruction {
|
||||
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition) = 0;
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the @a Condition this instruction requires, or null. */
|
||||
Condition* m_condition;
|
||||
|
||||
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file. */
|
||||
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the
|
||||
* same source file. */
|
||||
bool m_singleton;
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/** the default destination address, or empty. */
|
||||
const string m_defaultDest;
|
||||
|
||||
@@ -1099,17 +1118,20 @@ class Instruction {
|
||||
* An @a Instruction allowing to load another file.
|
||||
*/
|
||||
class LoadInstruction : public Instruction {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be
|
||||
* executed for the same source file.
|
||||
* @param defaultDest the default destination address (may be overwritten by file name), or empty.
|
||||
* @param defaultCircuit the default circuit name (may be overwritten by file name), or empty.
|
||||
* @param defaultSuffix the default circuit name suffix (starting with a ".", may be overwritten by file name), or empty.
|
||||
* @param defaultSuffix the default circuit name suffix (starting with a ".", may be overwritten by file name), or
|
||||
* empty.
|
||||
* @param filename the name of the file to load.
|
||||
*/
|
||||
LoadInstruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix, const string filename)
|
||||
LoadInstruction(Condition* condition, const bool singleton, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string filename)
|
||||
: Instruction(condition, singleton, defaultDest, defaultCircuit, defaultSuffix), m_filename(filename) { }
|
||||
|
||||
/**
|
||||
@@ -1121,7 +1143,7 @@ class LoadInstruction : public Instruction {
|
||||
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the name of the file to load. */
|
||||
const string m_filename;
|
||||
};
|
||||
@@ -1131,7 +1153,7 @@ class LoadInstruction : public Instruction {
|
||||
* Holds a map of all known @a Message instances.
|
||||
*/
|
||||
class MessageMap : public FileReader {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param addAll whether to add all messages, even if duplicate.
|
||||
@@ -1174,8 +1196,8 @@ class MessageMap : public FileReader {
|
||||
|
||||
// @copydoc
|
||||
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo);
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit,
|
||||
const string& defaultSuffix, const string& filename, unsigned int lineNo);
|
||||
|
||||
/**
|
||||
* Get the scan @a Message instance for the specified address.
|
||||
@@ -1219,7 +1241,8 @@ class MessageMap : public FileReader {
|
||||
/**
|
||||
* Get the loaded files for a participant.
|
||||
* @param address the slave address.
|
||||
* @return the name of the file(s) loaded for the participant (separated by comma and enclosed in double quotes), or empty.
|
||||
* @return the name of the file(s) loaded for the participant (separated by comma and enclosed in double quotes),
|
||||
* or empty.
|
||||
*/
|
||||
string getLoadedFiles(unsigned char address);
|
||||
|
||||
@@ -1246,15 +1269,19 @@ class MessageMap : public FileReader {
|
||||
* Find all active get @a Message instances for the specified circuit and name.
|
||||
* @param circuit the circuit name, or empty for any.
|
||||
* @param name the message name, or empty for any.
|
||||
* @param completeMatch false to also include messages where the circuit and name matches only a part of the given circuit and name (default true).
|
||||
* @param completeMatch false to also include messages where the circuit and name matches only a part of the given
|
||||
* circuit and name (default true).
|
||||
* @param withRead true to include read messages (default true).
|
||||
* @param withWrite true to include write messages (default false).
|
||||
* @param withPassive true to include passive messages (default false).
|
||||
* @return the found @a Message instances.
|
||||
* @param completeMatchIgnoreCircuitSuffix ignore different circuit suffixes (after "#") for completeMatch.
|
||||
* @param onlyAvailable true to include only available messages (default true), false to also include messages that are currently not available (e.g. due to unresolved or false conditions).
|
||||
* @param since the start time from which to add updates (inclusive, also removes messages with unset destination address), or 0 to ignore.
|
||||
* @param until the end time to which to add updates (exclusive, also removes messages with unset destination address), or 0 to ignore.
|
||||
* @param onlyAvailable true to include only available messages (default true), false to also include messages that
|
||||
* are currently not available (e.g. due to unresolved or false conditions).
|
||||
* @param since the start time from which to add updates (inclusive, also removes messages with unset destination
|
||||
* address), or 0 to ignore.
|
||||
* @param until the end time to which to add updates (exclusive, also removes messages with unset destination
|
||||
* address), or 0 to ignore.
|
||||
* Note: the caller may not free the returned instances.
|
||||
*/
|
||||
deque<Message*> findAll(const string& circuit, const string& name, const bool completeMatch = true,
|
||||
@@ -1344,7 +1371,7 @@ class MessageMap : public FileReader {
|
||||
void dump(ostream& output, bool withConditions = false);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** whether to add all messages, even if duplicate. */
|
||||
const bool m_addAll;
|
||||
|
||||
@@ -1382,6 +1409,6 @@ class MessageMap : public FileReader {
|
||||
map<string, vector<Instruction*> > m_instructions;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_MESSAGE_H_
|
||||
#endif // LIB_EBUS_MESSAGE_H_
|
||||
|
||||
@@ -58,4 +58,4 @@ const char* getResultCode(result_t resultCode) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
@@ -46,14 +46,14 @@ enum result_t {
|
||||
RESULT_ERR_EOF = -7, //!< end of input reached
|
||||
RESULT_ERR_INVALID_ARG = -8, //!< invalid argument
|
||||
RESULT_ERR_INVALID_NUM = -9, //!< invalid numeric argument
|
||||
RESULT_ERR_INVALID_ADDR = -10, //!< invalid address
|
||||
RESULT_ERR_INVALID_ADDR = -10, //!< invalid address
|
||||
RESULT_ERR_INVALID_POS = -11, //!< invalid position
|
||||
RESULT_ERR_OUT_OF_RANGE = -12, //!< argument value out of valid range
|
||||
RESULT_ERR_INVALID_PART = -13, //!< invalid part type value
|
||||
RESULT_ERR_MISSING_TYPE = -14, //!< missing data type
|
||||
RESULT_ERR_INVALID_LIST = -15, //!< invalid value list
|
||||
RESULT_ERR_OUT_OF_RANGE = -12, //!< argument value out of valid range
|
||||
RESULT_ERR_INVALID_PART = -13, //!< invalid part type value
|
||||
RESULT_ERR_MISSING_TYPE = -14, //!< missing data type
|
||||
RESULT_ERR_INVALID_LIST = -15, //!< invalid value list
|
||||
RESULT_ERR_DUPLICATE = -16, //!< duplicate entry
|
||||
RESULT_ERR_DUPLICATE_NAME = -17, //!< duplicate entry (name)
|
||||
RESULT_ERR_DUPLICATE_NAME = -17, //!< duplicate entry (name)
|
||||
|
||||
RESULT_ERR_BUS_LOST = -18, //!< arbitration lost
|
||||
RESULT_ERR_CRC = -19, //!< CRC error
|
||||
@@ -72,6 +72,6 @@ enum result_t {
|
||||
*/
|
||||
const char* getResultCode(result_t resultCode);
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_RESULT_H_
|
||||
#endif // LIB_EBUS_RESULT_H_
|
||||
|
||||
+11
-11
@@ -66,7 +66,7 @@ void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol) {
|
||||
push_back(data[i], isEscaped, addCrc);
|
||||
}
|
||||
if (addCrc) {
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,12 +78,12 @@ result_t SymbolString::parseHex(const string& str, const bool isEscaped) {
|
||||
unsigned long value = strtoul(strBegin, &strEnd, 16);
|
||||
|
||||
if (strEnd == NULL || strEnd != strBegin+2 || value > 0xff) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
push_back((unsigned char)value, isEscaped, addCrc);
|
||||
}
|
||||
if (addCrc) {
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -97,16 +97,16 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
|
||||
if (m_unescapeState == 0 && unescape && previousEscape) {
|
||||
if (!skipLastSymbol || i+1 < m_data.size()) {
|
||||
if (value == 0x00) {
|
||||
sstr << "a9"; // ESC
|
||||
sstr << "a9"; // ESC
|
||||
} else if (value == 0x01) {
|
||||
sstr << "aa"; // SYN
|
||||
sstr << "aa"; // SYN
|
||||
} else {
|
||||
sstr << "XX"; // invalid escape sequence
|
||||
sstr << "XX"; // invalid escape sequence
|
||||
}
|
||||
}
|
||||
previousEscape = false;
|
||||
} else if (m_unescapeState == 0 && unescape && value == ESC) {
|
||||
previousEscape = true; // escape sequence not yet finished
|
||||
previousEscape = true; // escape sequence not yet finished
|
||||
} else if (!skipLastSymbol || i+1 < m_data.size()) {
|
||||
sstr << nouppercase << setw(2) << hex
|
||||
<< setfill('0') << static_cast<unsigned>(value);
|
||||
@@ -116,7 +116,7 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
|
||||
}
|
||||
|
||||
result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) {
|
||||
if (m_unescapeState == 0) { // store escaped data
|
||||
if (m_unescapeState == 0) { // store escaped data
|
||||
if (!isEscaped && value == ESC) {
|
||||
m_data.push_back(ESC);
|
||||
m_data.push_back(0x00);
|
||||
@@ -141,7 +141,7 @@ result_t SymbolString::push_back(const unsigned char value, const bool isEscaped
|
||||
}
|
||||
if (!isEscaped) {
|
||||
if (m_unescapeState != 1) {
|
||||
return RESULT_ERR_ESC; // invalid unescape state
|
||||
return RESULT_ERR_ESC; // invalid unescape state
|
||||
}
|
||||
m_data.push_back(value);
|
||||
if (updateCRC) {
|
||||
@@ -171,7 +171,7 @@ result_t SymbolString::push_back(const unsigned char value, const bool isEscaped
|
||||
m_unescapeState = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
return RESULT_ERR_ESC; // invalid escape sequence
|
||||
return RESULT_ERR_ESC; // invalid escape sequence
|
||||
}
|
||||
if (value == ESC) {
|
||||
if (updateCRC) {
|
||||
@@ -261,4 +261,4 @@ bool isValidAddress(unsigned char addr, bool allowBroadcast) {
|
||||
return addr != SYN && addr != ESC && (allowBroadcast || addr != BROADCAST);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
+29
-15
@@ -68,18 +68,19 @@ namespace ebusd {
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static const unsigned char ESC = 0xA9; //!< escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA
|
||||
/** escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA. */
|
||||
static const unsigned char ESC = 0xA9;
|
||||
static const unsigned char SYN = 0xAA; //!< synchronization symbol
|
||||
static const unsigned char ACK = 0x00; //!< positive acknowledge
|
||||
static const unsigned char NAK = 0xFF; //!< negative acknowledge
|
||||
static const unsigned char BROADCAST = 0xFE; //!< the broadcast destination address
|
||||
static const unsigned char BROADCAST = 0xFE; //!< the broadcast destination address
|
||||
|
||||
|
||||
/**
|
||||
* A string of escaped or unescaped bus symbols.
|
||||
*/
|
||||
class SymbolString {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Creates a new empty escaped or unescaped instance.
|
||||
* @param escaped whether to create an escaped instance.
|
||||
@@ -114,24 +115,35 @@ class SymbolString {
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the reference to the symbol at the specified index.
|
||||
*/
|
||||
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) { m_data.resize(index+1, 0); } return m_data[index]; }
|
||||
unsigned char& operator[](const size_t index) {
|
||||
if (index >= m_data.size()) {
|
||||
m_data.resize(index+1, 0);
|
||||
}
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this instance is equal to the other instance.
|
||||
* @param other the other instance.
|
||||
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols).
|
||||
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same
|
||||
* symbols).
|
||||
*/
|
||||
bool operator == (SymbolString& other) { return m_unescapeState == other.m_unescapeState && m_data == other.m_data; }
|
||||
bool operator == (SymbolString& other) {
|
||||
return m_unescapeState == other.m_unescapeState && m_data == other.m_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this instance is different from the other instance.
|
||||
* @param other the other instance.
|
||||
* @return true if this instance is different from the other instance.
|
||||
*/
|
||||
bool operator != (SymbolString& other) { return m_unescapeState != other.m_unescapeState || m_data != other.m_data; }
|
||||
bool operator != (SymbolString& other) {
|
||||
return m_unescapeState != other.m_unescapeState || m_data != other.m_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master address and ending with the CRC).
|
||||
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master
|
||||
* address and ending with the CRC).
|
||||
* @param other the other instance.
|
||||
* @return 0 if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols),
|
||||
* 1 if this instance is completely different to the other instance,
|
||||
@@ -159,8 +171,8 @@ class SymbolString {
|
||||
* @param isEscaped whether the symbol is escaped.
|
||||
* @param updateCRC whether to update the calculated CRC in @a m_crc.
|
||||
* @return RESULT_OK if another symbol was appended,
|
||||
* RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received,
|
||||
* RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected.
|
||||
* RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was
|
||||
* received, RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected.
|
||||
*/
|
||||
result_t push_back(const unsigned char value, const bool isEscaped = true, const bool updateCRC = true);
|
||||
|
||||
@@ -188,7 +200,7 @@ class SymbolString {
|
||||
void clear(const bool escape) { m_data.clear(); m_unescapeState = escape ? 0 : 1; m_crc = 0; }
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param str the @a SymbolString to copy from.
|
||||
@@ -234,14 +246,16 @@ bool isSlaveMaster(unsigned char addr);
|
||||
/**
|
||||
* Return the slave address associated with the specified address (master or slave).
|
||||
* @param addr the address to check.
|
||||
* @return the slave address, or SYN if the specified address is neither a master address nor a slave address of a master.
|
||||
* @return the slave address, or SYN if the specified address is neither a master address nor a slave address of a
|
||||
* master.
|
||||
*/
|
||||
unsigned char getSlaveAddress(unsigned char addr);
|
||||
|
||||
/**
|
||||
* Return the master address associated with the specified address (master or slave).
|
||||
* @param addr the address to check.
|
||||
* @return the master address, or SYN if the specified address is neither a master address nor a slave address of a master.
|
||||
* @return the master address, or SYN if the specified address is neither a master address nor a slave address of a
|
||||
* master.
|
||||
*/
|
||||
unsigned char getMasterAddress(unsigned char addr);
|
||||
|
||||
@@ -260,6 +274,6 @@ unsigned char getMasterNumber(unsigned char addr);
|
||||
*/
|
||||
bool isValidAddress(unsigned char addr, bool allowBroadcast = true);
|
||||
|
||||
} // namespace ebusd
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // LIB_EBUS_SYMBOL_H_
|
||||
#endif // LIB_EBUS_SYMBOL_H_
|
||||
|
||||
@@ -59,7 +59,8 @@ int main() {
|
||||
{"x,,str:10", " ", "10fe07000a20202020202020202020", "00", ""},
|
||||
{"x,,str:10", "", "10fe07000a20202020202020202020", "00", "R"},
|
||||
{"x,,str:11", "", "10fe07000a20202020202020202020", "00", "rW"},
|
||||
{"x,,str:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778", "00", ""},
|
||||
{"x,,str:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778",
|
||||
"00", ""},
|
||||
{"x,,str:*", "abcde", "10fe0700056162636465", "00", ""},
|
||||
{"x,,str,2", "", "", "", "c"},
|
||||
{"x,,str:10,=dummy", "", "10fe07000a48616c6c6f2044752120", "00", "W"},
|
||||
@@ -73,7 +74,8 @@ int main() {
|
||||
{"x,,nts:10", "", "10fe07000a00000000000000000000", "00", ""},
|
||||
{"x,,nts:10", "abc", "10fe07000a6162630065666768696a", "00", "W"},
|
||||
{"x,,nts:11", "", "10fe07000a20202020202020202020", "00", "rW"},
|
||||
{"x,,nts:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778", "00", ""},
|
||||
{"x,,nts:24", "abcdefghijklmnopqrstuvwx", "10fe0700186162636465666768696a6b6c6d6e6f707172737475767778",
|
||||
"00", ""},
|
||||
{"x,,nts:*", "abcde", "10fe0700056162636465", "00", "W"},
|
||||
{"x,,nts:*", "abcde", "10fe070006616263646500", "00", ""},
|
||||
{"x,,nts,2", "", "", "", "c"},
|
||||
@@ -86,9 +88,9 @@ int main() {
|
||||
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"},
|
||||
{"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
|
||||
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
|
||||
{"x,,bda", "26.10.2014", "10fe07000426100614", "00", ""}, // Sunday
|
||||
{"x,,bda", "01.01.2000", "10fe07000401010500", "00", ""}, // Saturday
|
||||
{"x,,bda", "31.12.2099", "10fe07000431120399", "00", ""}, // Thursday
|
||||
{"x,,bda", "26.10.2014", "10fe07000426100614", "00", ""}, // Sunday
|
||||
{"x,,bda", "01.01.2000", "10fe07000401010500", "00", ""}, // Saturday
|
||||
{"x,,bda", "31.12.2099", "10fe07000431120399", "00", ""}, // Thursday
|
||||
{"x,,bda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,bda", "", "10fe07000432100014", "00", "rw"},
|
||||
{"x,,bda:3", "26.10.2014", "10fe070003261014", "00", ""},
|
||||
@@ -97,9 +99,9 @@ int main() {
|
||||
{"x,,bda:3", "-.-.-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,bda:3", "", "10fe070003321299", "00", "rw"},
|
||||
{"x,,bda,2", "", "", "", "c"},
|
||||
{"x,,hda", "26.10.2014", "10fe0700041a0a070e", "00", ""}, // Sunday
|
||||
{"x,,hda", "01.01.2000", "10fe07000401010600", "00", ""}, // Saturday
|
||||
{"x,,hda", "31.12.2099", "10fe0700041f0c0463", "00", ""}, // Thursday
|
||||
{"x,,hda", "26.10.2014", "10fe0700041a0a070e", "00", ""}, // Sunday
|
||||
{"x,,hda", "01.01.2000", "10fe07000401010600", "00", ""}, // Saturday
|
||||
{"x,,hda", "31.12.2099", "10fe0700041f0c0463", "00", ""}, // Thursday
|
||||
{"x,,hda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,hda", "", "10fe070004200c0463", "00", "rw"},
|
||||
{"x,,hda:3", "26.10.2014", "10fe0700031a0a0e", "00", ""},
|
||||
@@ -301,7 +303,7 @@ int main() {
|
||||
{"uin10,uin,-10", "", "", "", "t"}, // template
|
||||
{"x,,uin10", "380", "10feffff022600", "00", ""}, // template reference
|
||||
{"x,,uin10,-10", "3800", "10feffff022600", "00", ""}, // template reference, valid divider product
|
||||
{"x,,uin10,10", "", "", "", "c"}, // template reference, invalid divider product
|
||||
{"x,,uin10,10", "", "", "", "c"}, // template reference, invalid divider product
|
||||
{"x,,sin", "-90", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sin", "0", "10feffff020000", "00", ""},
|
||||
{"x,,sin", "-1", "10feffff02ffff", "00", ""},
|
||||
@@ -427,35 +429,43 @@ int main() {
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvv"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvvn"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "j"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108",
|
||||
"00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108",
|
||||
"00", "j"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert",
|
||||
"\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108",
|
||||
"00", "vvvj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1}", "10feffff0108", "00", "vnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00", "nj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert",
|
||||
"\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00",
|
||||
"vvvnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00",
|
||||
"nj"},
|
||||
{"x,,uch,1=test;2=high;3=off;0x10=on", "on", "10feffff0110", "00", ""},
|
||||
{"x,s,uch", "3", "1050ffff00", "0103", ""},
|
||||
{"x,,d2b,,°C,Aussentemperatur", "x=18.004 °C [Aussentemperatur]", "10fe0700090112", "00", "vvv"},
|
||||
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun", "10fe0700085804212610061406", "00", ""}, // combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;1", "10feffff0120", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;0", "10feffff0100", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9", "10feffff020009", "00", ""}, // bit combination
|
||||
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9", "10feffff03800109", "00", ""}, // bit combination
|
||||
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0", "ff75b50900", "0104", ""}, // bits
|
||||
{"temp,d2b,,°C,Aussentemperatur", "", "", "", "t"}, // template with relative pos
|
||||
{"x,,temp", "18.004", "10fe0700020112", "00", ""}, // reference to template
|
||||
{"x,,temp,10", "1.8004", "10fe0700020112", "00", ""}, // reference to template, valid divider product
|
||||
{"x,,temp,-10", "", "", "", "c"}, // reference to template, invalid divider product
|
||||
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun", "10fe0700085804212610061406", "00", ""}, // combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;1", "10feffff0120", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;0", "10feffff0100", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9", "10feffff020009", "00", ""}, // bit combination
|
||||
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9", "10feffff03800109", "00", ""}, // bit combination
|
||||
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0", "ff75b50900", "0104", ""}, // bits
|
||||
{"temp,d2b,,°C,Aussentemperatur", "", "", "", "t"}, // template with relative pos
|
||||
{"x,,temp", "18.004", "10fe0700020112", "00", ""}, // reference to template
|
||||
{"x,,temp,10", "1.8004", "10fe0700020112", "00", ""}, // reference to template, valid divider product
|
||||
{"x,,temp,-10", "", "", "", "c"}, // reference to template, invalid divider product
|
||||
{"relrel,d2b,,,,y,d1c", "", "", "", "t"}, // template struct with relative pos
|
||||
{"x,,relrel", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template struct
|
||||
{"x,,relrel", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template struct
|
||||
{"trelrel,temp;temp", "", "", "", "t"}, // template struct with relative pos and ref to templates
|
||||
{"x,,trelrel", "18.004;19.008", "10fe07000401120213", "00", ""}, // reference to template struct
|
||||
{"x,,temp,,,,y,,d1c", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template, normal def
|
||||
{"x,,temp;HEX:2", "18.004;13 14", "10fe07000401121314", "00", ""}, // reference to template and base type
|
||||
{"x,,temp;HEX:2", "temp=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
{"x,,temp:degrees;HEX:2", "degrees=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
{"x,,trelrel", "18.004;19.008", "10fe07000401120213", "00", ""}, // reference to template struct
|
||||
{"x,,temp,,,,y,,d1c", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template, normal def
|
||||
{"x,,temp;HEX:2", "18.004;13 14", "10fe07000401121314", "00", ""}, // reference to template and base type
|
||||
{"x,,temp;HEX:2", "temp=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
// reference to template and base type
|
||||
{"x,,temp:degrees;HEX:2", "degrees=18.004;=13 14", "10fe07000401121314", "00", "v"},
|
||||
};
|
||||
DataFieldTemplates* templates = new DataFieldTemplates();
|
||||
DataField* fields = NULL;
|
||||
@@ -510,7 +520,8 @@ int main() {
|
||||
fields = NULL;
|
||||
}
|
||||
vector<string>::iterator it = entries.begin();
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate,
|
||||
!isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
if (failedCreate) {
|
||||
if (result == RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
|
||||
@@ -555,18 +566,21 @@ int main() {
|
||||
SymbolString writeMstr(false);
|
||||
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
|
||||
if (result != RESULT_OK) {
|
||||
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) << endl;
|
||||
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result)
|
||||
<< endl;
|
||||
error = true;
|
||||
}
|
||||
SymbolString writeSstr(false);
|
||||
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
|
||||
if (result != RESULT_OK) {
|
||||
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) << endl;
|
||||
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result)
|
||||
<< endl;
|
||||
error = true;
|
||||
}
|
||||
result = fields->read(pt_masterData, mstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, false);
|
||||
if (result >= RESULT_OK) {
|
||||
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, !output.str().empty());
|
||||
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1,
|
||||
!output.str().empty());
|
||||
}
|
||||
if (failedRead) {
|
||||
if (result >= RESULT_OK) {
|
||||
@@ -607,7 +621,9 @@ int main() {
|
||||
error = true;
|
||||
} else {
|
||||
bool match = mstr == writeMstr && sstr == writeSstr;
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " + sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
|
||||
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " "
|
||||
+ writeSstr.getDataStr(true, false));
|
||||
}
|
||||
}
|
||||
delete fields;
|
||||
|
||||
@@ -47,7 +47,7 @@ DataFieldTemplates* templates = NULL;
|
||||
|
||||
namespace ebusd {
|
||||
DataFieldTemplates* getTemplates(const string filename) {
|
||||
if (filename == "") { // avoid compiler warning
|
||||
if (filename == "") { // avoid compiler warning
|
||||
return templates;
|
||||
}
|
||||
return templates;
|
||||
@@ -73,13 +73,23 @@ int main() {
|
||||
{"pumpstate,UCH,0=off;1=on;2=overrun,,Pumpenstatus", "", "", "", "template"},
|
||||
{"tempsensor,temp;sensor,,Temperatursensor", "", "", "", "template"},
|
||||
{"tempsensorc,temp;sensorc,,Temperatursensor", "", "", "", "template"},
|
||||
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate", "28.0;24.0;4.938;35.0;41.0;4", "ff08b5110101", "093830f00446520400ff", "d"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor", "temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00},\n \"sensor\": {\"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00, \"unit\": \"field unit\", \"comment\": \"field comment\"},\n \"sensor\": {\"value\": \"ok\", \"comment\": \"Fühlerstatus\"}", "ff25b509030d2800", "0320ff00", "mJ"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,D2C,,°C,Temperatur,,,sensor", "\n \"0\": {\"name\": \"\", \"value\": -14.00},\n \"1\": {\"name\": \"sensor\", \"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"},
|
||||
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate",
|
||||
"28.0;24.0;4.938;35.0;41.0;4", "ff08b5110101", "093830f00446520400ff", "d"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor",
|
||||
"temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
|
||||
"temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
|
||||
"\n \"temp\": {\"value\": -14.00},\n \"sensor\": {\"value\": \"ok\"}", "ff25b509030d2800", "0320ff00",
|
||||
"mj"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment",
|
||||
"\n \"temp\": {\"value\": -14.00, \"unit\": \"field unit\", \"comment\": \"field comment\"},\n"
|
||||
" \"sensor\": {\"value\": \"ok\", \"comment\": \"Fühlerstatus\"}", "ff25b509030d2800", "0320ff00", "mJ"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor",
|
||||
"temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,D2C,,°C,Temperatur,,,sensor",
|
||||
"\n \"0\": {\"name\": \"\", \"value\": -14.00},\n \"1\": {\"name\": \"sensor\", \"value\": \"ok\"}",
|
||||
"ff25b509030d2800", "0320ff00", "mj"},
|
||||
{"r,,name,,,25,B509,0d2800,,,tempsensorc", "-14.00", "ff25b509030d2800", "0320ff55", "m"},
|
||||
{"r,,name,,,25,B509,0d28,,m,sensorc,,,,,,temp", "-14.00", "ff25b509030d2855", "0220ff", "m"},
|
||||
{"u,,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"},
|
||||
@@ -92,20 +102,27 @@ int main() {
|
||||
{"r,ehp,time,,,08;10,b509,0d2800,,,time", "", "", "", "c"},
|
||||
{"r,ehp,time,,,08;09,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "md*"},
|
||||
{"r,ehp,date,,,08,b509,0d2900,,,date", "23.11.2014", "ff08b509030d2900", "03170b0e", "md"},
|
||||
{"r,700,date,,,15,b524,020000003400,,,IGN:4,,,,,,date", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"},
|
||||
{"r,700,time,,,15,b524,030000003500,,,IGN:4,,,,,,HTI", "12:29:06", "ff15b52406030000003500", "07030035000c1d06", "d"},
|
||||
{"r,700,date,,,15,b524,020000003400,,,IGN:4,,,,,,date", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f",
|
||||
"d"},
|
||||
{"r,700,time,,,15,b524,030000003500,,,IGN:4,,,,,,HTI", "12:29:06", "ff15b52406030000003500", "07030035000c1d06",
|
||||
"d"},
|
||||
{"", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"},
|
||||
{"", "12:29:06", "ff15b52406030000003500", "07030035000c1d06", "d"},
|
||||
{"w,700,date,,,15,b524,020000003400,,,date", "23.11.2015", "ff15b52409020000003400170b0f", "00", "m"},
|
||||
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "3;15:00:17", "ff08b509040d280003", "0311000f", "mdi"},
|
||||
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f", "mD"},
|
||||
{"u,ehp,ActualEnvironmentPower,Energiebezug,,08,B509,29BA00,,s,IGN:2,,,,,s,power", "8", "1008b5090329ba00", "03ba0008", "pm"},
|
||||
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f",
|
||||
"mD"},
|
||||
{"u,ehp,ActualEnvironmentPower,Energiebezug,,08,B509,29BA00,,s,IGN:2,,,,,s,power", "8", "1008b5090329ba00",
|
||||
"03ba0008", "pm"},
|
||||
{"uw,ehp,test,Test,,08,B5de,ab,,,power,,,,,s,hex:1", "8;39", "1008b5de02ab08", "0139", "pm"},
|
||||
{"u,ehp,hwTankTemp,Speichertemperatur IST,,25,B509,290000,,,IGN:2,,,,,,tempsensor", "", "", "", "M"},
|
||||
{"", "55.50;ok", "1025b50903290000", "050000780300", "d"},
|
||||
{"r,ehp,datetime,Datum Uhrzeit,,50,B504,00,,,dcfstate,,,,time,,BTI,,,,date,,BDA,,,,temp,,temp2", "valid;08:24:51;31.12.2014;-0.875", "1050b5040100", "0a035124083112031420ff", "md" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,000102,,m,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,,,s,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
|
||||
{"r,ehp,datetime,Datum Uhrzeit,,50,B504,00,,,dcfstate,,,,time,,BTI,,,,date,,BDA,,,,temp,,temp2",
|
||||
"valid;08:24:51;31.12.2014;-0.875", "1050b5040100", "0a035124083112031420ff", "md" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,000102,,m,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "",
|
||||
"", "", "c" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,,,s,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,",
|
||||
"", "", "", "c" },
|
||||
{"r,ehp,ApplianceCode,,,08,b509,0d4301,,,UCH,", "9", "ff08b509030d4301", "0109", "d" },
|
||||
{"r,ehp,,,,08,b509,0d", "", "", "", "defaults" },
|
||||
{"w,ehp,,,,08,b509,0e", "", "", "", "defaults" },
|
||||
@@ -113,22 +130,39 @@ int main() {
|
||||
{"[airtowater]r,ehp,notavailable,,,,,0100,,,uch", "1", "", "", "c" },
|
||||
{"[brinetowater]r,ehp,available,,,,,0100,,,uch", "1", "ff08b509030d0100", "0101", "d" },
|
||||
{"r,,x,,,,,\"6800\",,,UCH,,,bit0=\"comment, continued comment", "", "", "", "c" },
|
||||
{"r,,x,,,,,\"6800\",,,UCH,,\"\",\"bit0=\"comment, continued comment\"", "=1 [bit0=\"comment, continued comment]", "ff08b509030d6800", "0101", "mD" },
|
||||
{"r,ehp,multi,,,,,0001:5;0002;0003,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509030d0001;ff08b509030d0003;ff08b509030d0002", "054142434445;054b4c4d4e4f;05464748494a", "mdC" },
|
||||
{"r,ehp,multi,,,,,01;02;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509020d01;ff08b509020d03;ff08b509020d02", "084142434445464748;054b4c4d4e4f;02494a", "mdC" },
|
||||
{"w,ehp,multi,,,,,01:8;02:2;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "mdC" },
|
||||
{"w,ehp,multi,,,,,01:8;02:2;0304,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "cC" },
|
||||
{"r,ehp,scan,chained scan,,08,B509,24:9;25;26;27,,,IGN,,,,id4,,STR:28", "21074500100027790000000000N8", "ff08b5090124;ff08b5090125;ff08b5090126;ff08b5090127", "09003231303734353030;09313030303237373930;09303030303030303030;024E38", "mdC" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509030d6900", "03138040", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509030d6900", "0313ffbf", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509030d6900", "03137fff", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509030d6900", "03137fbf", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71", "ff08b509030d6900", "0213ff", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71", "ff08b509030d6900", "0213bf", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70", "ff08b509030d6900", "02137f", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70", "ff08b509030d6900", "02133f", "md" },
|
||||
{"r,,x,,,,,\"6800\",,,UCH,,\"\",\"bit0=\"comment, continued comment\"", "=1 [bit0=\"comment, continued comment]",
|
||||
"ff08b509030d6800", "0101", "mD" },
|
||||
{"r,ehp,multi,,,,,0001:5;0002;0003,longname,,STR:15", "ABCDEFGHIJKLMNO",
|
||||
"ff08b509030d0001;ff08b509030d0003;ff08b509030d0002", "054142434445;054b4c4d4e4f;05464748494a", "mdC" },
|
||||
{"r,ehp,multi,,,,,01;02;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b509020d01;ff08b509020d03;ff08b509020d02",
|
||||
"084142434445464748;054b4c4d4e4f;02494a", "mdC" },
|
||||
{"w,ehp,multi,,,,,01:8;02:2;03,longname,,STR:15", "ABCDEFGHIJKLMNO",
|
||||
"ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "mdC" },
|
||||
{"w,ehp,multi,,,,,01:8;02:2;0304,longname,,STR:15", "ABCDEFGHIJKLMNO",
|
||||
"ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "cC" },
|
||||
{"r,ehp,scan,chained scan,,08,B509,24:9;25;26;27,,,IGN,,,,id4,,STR:28", "21074500100027790000000000N8",
|
||||
"ff08b5090124;ff08b5090125;ff08b5090126;ff08b5090127",
|
||||
"09003231303734353030;09313030303237373930;09303030303030303030;024E38", "mdC" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61",
|
||||
"ff08b509030d6900", "03138040", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60",
|
||||
"ff08b509030d6900", "0313ffbf", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61",
|
||||
"ff08b509030d6900", "03137fff", "md" },
|
||||
{"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60",
|
||||
"ff08b509030d6900", "03137fbf", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71",
|
||||
"ff08b509030d6900", "0213ff", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71",
|
||||
"ff08b509030d6900", "0213bf", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70",
|
||||
"ff08b509030d6900", "02137f", "md" },
|
||||
{"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70",
|
||||
"ff08b509030d6900", "02133f", "md" },
|
||||
{"r,cir*cuit#level,na*me,com*ment,ff,75,b509,0d", "", "", "", "defaults" },
|
||||
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH", "r,cirCIRCUITcuit#level,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42", "ff08b509030d0100", "012a", "mDN"},
|
||||
{"r,CIRCUIT,NAME,COMMENT,,,,0100,field,,UCH",
|
||||
"r,cirCIRCUITcuit#level,naNAMEme,comCOMMENTment,ff,75,b509,0d0100,field,s,UCH,,,: field=42",
|
||||
"ff08b509030d0100", "012a", "mDN"},
|
||||
};
|
||||
templates = new DataFieldTemplates();
|
||||
MessageMap* messages = new MessageMap();
|
||||
@@ -174,7 +208,8 @@ int main() {
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": template fields create error: " << getResultCode(result) << endl;
|
||||
} else if (it != entries.end()) {
|
||||
cout << "\"" << check[0] << "\": template fields create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
|
||||
cout << "\"" << check[0] << "\": template fields create error: trailing input "
|
||||
<< static_cast<unsigned>(entries.end()-it) << endl;
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": create template OK" << endl;
|
||||
result = templates->add(fields, "", true);
|
||||
@@ -195,7 +230,8 @@ int main() {
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": defaults read error: " << getResultCode(result) << endl;
|
||||
} else if (it != entries.end()) {
|
||||
cout << "\"" << check[0] << "\": defaults read error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
|
||||
cout << "\"" << check[0] << "\": defaults read error: trailing input "
|
||||
<< static_cast<unsigned>(entries.end()-it) << endl;
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": read defaults OK" << endl;
|
||||
if (isCondition) {
|
||||
@@ -204,7 +240,8 @@ int main() {
|
||||
} else {
|
||||
result = messages->resolveConditions();
|
||||
if (result != RESULT_OK) {
|
||||
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError() << endl;
|
||||
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError()
|
||||
<< endl;
|
||||
} else {
|
||||
cout << " resolve conditions OK" << endl;
|
||||
}
|
||||
@@ -314,7 +351,8 @@ int main() {
|
||||
continue;
|
||||
}
|
||||
if (it != entries.end()) {
|
||||
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
|
||||
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it)
|
||||
<< endl;
|
||||
continue;
|
||||
}
|
||||
if (multi && deleteMessages.size() == 1) {
|
||||
@@ -368,7 +406,8 @@ int main() {
|
||||
message->dump(output, NULL, true);
|
||||
output << ": ";
|
||||
}
|
||||
result = message->decodeLastData(output, (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false);
|
||||
result = message->decodeLastData(output,
|
||||
(decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false);
|
||||
if (result != RESULT_OK) {
|
||||
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: "
|
||||
<< getResultCode(result) << endl;
|
||||
@@ -399,7 +438,8 @@ int main() {
|
||||
cout << " \"" << inputStr << "\": prepare OK" << endl;
|
||||
|
||||
bool match = writeMstr == *mstrs[0];
|
||||
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false), writeMstr.getDataStr(true, false));
|
||||
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false),
|
||||
writeMstr.getDataStr(true, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
*/
|
||||
void clockGettime(struct timespec* t);
|
||||
|
||||
#endif // LIB_UTILS_CLOCK_H_
|
||||
#endif // LIB_UTILS_CLOCK_H_
|
||||
|
||||
@@ -71,7 +71,6 @@ bool setLogFacilities(const char* facilities) {
|
||||
newFacilites |= 1 << val;
|
||||
}
|
||||
}
|
||||
//s_lastFacilities = newFacilites;
|
||||
s_logFacilites = newFacilites;
|
||||
free(input);
|
||||
return true;
|
||||
@@ -81,7 +80,7 @@ bool getLogFacilities(char* buffer) {
|
||||
if (s_logFacilites == LF_ALL) {
|
||||
return snprintf(buffer, 48, "%s", facilityNames[lf_COUNT]) != 0;
|
||||
}
|
||||
*buffer = 0; // for strcat to work
|
||||
*buffer = 0; // for strcat to work
|
||||
bool found = false;
|
||||
size_t len = 0;
|
||||
for (int val = 0; val < lf_COUNT; val++) {
|
||||
|
||||
+11
-7
@@ -36,12 +36,12 @@ enum LogFacility {
|
||||
|
||||
/** the available log levels. */
|
||||
enum LogLevel {
|
||||
ll_none = 0, //!< no level at all
|
||||
ll_none = 0, //!< no level at all
|
||||
ll_error, //!< error message
|
||||
ll_notice, //!< important message
|
||||
ll_info, //!< informational message
|
||||
ll_debug, //!< debugging message (normally suppressed)
|
||||
ll_COUNT = 5 //!< number of available log levels
|
||||
ll_COUNT = 5 //!< number of available log levels
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -125,15 +125,19 @@ void logWrite(const char* facility, const LogLevel level, const char* message, .
|
||||
#define logDebug(facility, ...) (needsLog(facility, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
|
||||
|
||||
/** A macro for an error message that calls the logging function only if needed. */
|
||||
#define logOtherError(facility, ...) (needsLog(lf_other, ll_error) ? logWrite(facility, ll_error, __VA_ARGS__) : void(0))
|
||||
#define logOtherError(facility, ...) \
|
||||
(needsLog(lf_other, ll_error) ? logWrite(facility, ll_error, __VA_ARGS__) : void(0))
|
||||
|
||||
/** A macro for a notice message that calls the logging function only if needed. */
|
||||
#define logOtherNotice(facility, ...) (needsLog(lf_other, ll_notice) ? logWrite(facility, ll_notice, __VA_ARGS__) : void(0))
|
||||
#define logOtherNotice(facility, ...) \
|
||||
(needsLog(lf_other, ll_notice) ? logWrite(facility, ll_notice, __VA_ARGS__) : void(0))
|
||||
|
||||
/** A macro for an info message that calls the logging function only if needed. */
|
||||
#define logOtherInfo(facility, ...) (needsLog(lf_other, ll_info) ? logWrite(facility, ll_info, __VA_ARGS__) : void(0))
|
||||
#define logOtherInfo(facility, ...) \
|
||||
(needsLog(lf_other, ll_info) ? logWrite(facility, ll_info, __VA_ARGS__) : void(0))
|
||||
|
||||
/** A macro for a debug message that calls the logging function only if needed. */
|
||||
#define logOtherDebug(facility, ...) (needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
|
||||
#define logOtherDebug(facility, ...) \
|
||||
(needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
|
||||
|
||||
#endif // LIB_UTILS_LOG_H_
|
||||
#endif // LIB_UTILS_LOG_H_
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
* class to notify other thread per pipe.
|
||||
*/
|
||||
class Notify {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* constructs a new instance and do notifying.
|
||||
*/
|
||||
@@ -61,7 +61,7 @@ class Notify {
|
||||
*/
|
||||
int notify() const { return write(m_sendfd, "1", 1); }
|
||||
|
||||
private:
|
||||
private:
|
||||
/** file descriptor to watch */
|
||||
int m_recvfd;
|
||||
|
||||
@@ -69,6 +69,6 @@ class Notify {
|
||||
int m_sendfd;
|
||||
};
|
||||
|
||||
#endif // LIB_UTILS_NOTIFY_H_
|
||||
#endif // LIB_UTILS_NOTIFY_H_
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ using std::list;
|
||||
*/
|
||||
template <typename T>
|
||||
class Queue {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -52,7 +52,7 @@ class Queue {
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
@@ -60,7 +60,7 @@ class Queue {
|
||||
Queue(const Queue& src);
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Add an item to the end of queue.
|
||||
* @param item the item to add.
|
||||
@@ -141,7 +141,7 @@ class Queue {
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the queue itself */
|
||||
list<T> m_queue;
|
||||
|
||||
@@ -152,4 +152,4 @@ class Queue {
|
||||
pthread_cond_t m_cond;
|
||||
};
|
||||
|
||||
#endif // LIB_UTILS_QUEUE_H_
|
||||
#endif // LIB_UTILS_QUEUE_H_
|
||||
|
||||
@@ -35,7 +35,7 @@ using std::string;
|
||||
* Helper class for writing to a rotating file with maximum size.
|
||||
*/
|
||||
class RotateFile {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param fileName the name of the file write to.
|
||||
@@ -72,7 +72,7 @@ class RotateFile {
|
||||
void write(unsigned char* value, unsigned int size, bool received = true);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** whether writing to the file is enabled. */
|
||||
bool m_enabled;
|
||||
|
||||
@@ -92,5 +92,5 @@ class RotateFile {
|
||||
uint64_t m_fileSize;
|
||||
};
|
||||
|
||||
#endif // LIB_UTILS_ROTATEFILE_H_
|
||||
#endif // LIB_UTILS_ROTATEFILE_H_
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ using std::string;
|
||||
* class for low level tcp socket operations. (open, close, send, receive).
|
||||
*/
|
||||
class TCPSocket {
|
||||
public:
|
||||
public:
|
||||
/** grant access for friend class TCPClient */
|
||||
friend class TCPClient;
|
||||
|
||||
@@ -91,7 +91,7 @@ class TCPSocket {
|
||||
bool isValid();
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** file descriptor from tcp socket */
|
||||
int m_sfd;
|
||||
|
||||
@@ -113,7 +113,7 @@ class TCPSocket {
|
||||
* class to initiate a tcp socket connection to a listening server.
|
||||
*/
|
||||
class TCPClient {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* initiate a tcp socket connection to a listening server.
|
||||
* @param server the server name or ip address to connect.
|
||||
@@ -127,7 +127,7 @@ class TCPClient {
|
||||
* class for a tcp based network server.
|
||||
*/
|
||||
class TCPServer {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* creates a new instance of a listening tcp server.
|
||||
* @param port the tcp port.
|
||||
@@ -160,7 +160,7 @@ class TCPServer {
|
||||
int getFD() const { return m_lfd; }
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** file descriptor from listening tcp socket */
|
||||
int m_lfd;
|
||||
|
||||
@@ -174,5 +174,5 @@ class TCPServer {
|
||||
bool m_listening;
|
||||
};
|
||||
|
||||
#endif // LIB_UTILS_TCPSOCKET_H_
|
||||
#endif // LIB_UTILS_TCPSOCKET_H_
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* wrapper class for pthread.
|
||||
*/
|
||||
class Thread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* constructor.
|
||||
*/
|
||||
@@ -76,14 +76,14 @@ class Thread {
|
||||
pthread_t self() { return m_threadid; }
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
/**
|
||||
* Thread entry method to be overridden by derived class.
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Enter the Thread loop by calling run().
|
||||
*/
|
||||
@@ -107,7 +107,7 @@ class Thread {
|
||||
* A @a Thread that can be waited on.
|
||||
*/
|
||||
class WaitThread : public Thread {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -132,7 +132,7 @@ class WaitThread : public Thread {
|
||||
bool Wait(int seconds);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
/** the mutex for waiting. */
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
@@ -140,4 +140,4 @@ class WaitThread : public Thread {
|
||||
pthread_cond_t m_cond;
|
||||
};
|
||||
|
||||
#endif // LIB_UTILS_THREAD_H_
|
||||
#endif // LIB_UTILS_THREAD_H_
|
||||
|
||||
+11
-11
@@ -39,20 +39,20 @@ using std::endl;
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options {
|
||||
const char* server; //!< ebusd server host (name or ip) [localhost]
|
||||
uint16_t port; //!< ebusd server port [8888]
|
||||
const char* server; //!< ebusd server host (name or ip) [localhost]
|
||||
uint16_t port; //!< ebusd server port [8888]
|
||||
|
||||
char* const *args; //!< arguments to pass to ebusd
|
||||
unsigned int argCount; //!< number of arguments to pass to ebusd
|
||||
char* const *args; //!< arguments to pass to ebusd
|
||||
unsigned int argCount; //!< number of arguments to pass to ebusd
|
||||
};
|
||||
|
||||
/** the program options. */
|
||||
static struct options opt = {
|
||||
"localhost", // server
|
||||
8888, // port
|
||||
"localhost", // server
|
||||
8888, // port
|
||||
|
||||
NULL, // args
|
||||
0 // argCount
|
||||
NULL, // args
|
||||
0 // argCount
|
||||
};
|
||||
|
||||
/** the version string of the program. */
|
||||
@@ -92,14 +92,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
unsigned int port;
|
||||
switch (key) {
|
||||
// Device settings:
|
||||
case 's': // --server=localhost
|
||||
case 's': // --server=localhost
|
||||
if (arg == NULL || arg[0] == 0) {
|
||||
argp_error(state, "invalid server");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->server = arg;
|
||||
break;
|
||||
case 'p': // --port=8888
|
||||
case 'p': // --port=8888
|
||||
port = strtoul(arg, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == arg || *strEnd != 0 || port < 1 || port > 65535) {
|
||||
argp_error(state, "invalid port");
|
||||
@@ -156,7 +156,7 @@ string fetchData(TCPSocket* socket, bool& listening) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
#ifdef HAVE_PPOLL
|
||||
// wait for new fd event
|
||||
ret = ppoll(fds, nfds, &tdiff, NULL);
|
||||
|
||||
@@ -42,18 +42,18 @@ using ebusd::Device;
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options {
|
||||
const char* device; //!< device to write to [/dev/ttyUSB60]
|
||||
unsigned int time; //!< delay between bytes in us [10000]
|
||||
const char* device; //!< device to write to [/dev/ttyUSB60]
|
||||
unsigned int time; //!< delay between bytes in us [10000]
|
||||
|
||||
const char* dumpFile; //!< dump file to read
|
||||
const char* dumpFile; //!< dump file to read
|
||||
};
|
||||
|
||||
/** the program options. */
|
||||
static struct options opt = {
|
||||
"/dev/ttyUSB60", // device
|
||||
10000, // time
|
||||
"/dev/ttyUSB60", // device
|
||||
10000, // time
|
||||
|
||||
"/tmp/ebus_dump.bin", // dumpFile
|
||||
"/tmp/ebus_dump.bin", // dumpFile
|
||||
};
|
||||
|
||||
/** the version string of the program. */
|
||||
@@ -98,14 +98,14 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
char* strEnd = NULL;
|
||||
switch (key) {
|
||||
// Device settings:
|
||||
case 'd': // --device=/dev/ttyUSB60
|
||||
case 'd': // --device=/dev/ttyUSB60
|
||||
if (arg == NULL || arg[0] == 0) {
|
||||
argp_error(state, "invalid device");
|
||||
return EINVAL;
|
||||
}
|
||||
opt->device = arg;
|
||||
break;
|
||||
case 't': // --time=10000
|
||||
case 't': // --time=10000
|
||||
opt->time = (unsigned int)strtoul(arg, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == arg || *strEnd != 0 || opt->time < 1000 || opt->time > 100000000) {
|
||||
argp_error(state, "invalid time");
|
||||
|
||||
Reference in New Issue
Block a user