code style

This commit is contained in:
john30
2017-01-14 13:00:04 +01:00
parent d13b271a05
commit b3bb2e08ac
49 changed files with 1853 additions and 1858 deletions
+186 -189
View File
@@ -16,22 +16,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "bushandler.h" #include "bushandler.h"
#include <unistd.h>
#include <time.h>
#include <string>
#include <vector>
#include <deque>
#include <cstring>
#include <iomanip>
#include "message.h" #include "message.h"
#include "data.h" #include "data.h"
#include "result.h" #include "result.h"
#include "symbol.h" #include "symbol.h"
#include "log.h" #include "log.h"
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <string>
#include <vector>
#include <deque>
#include <cstring>
#include <time.h>
#include <iomanip>
using namespace std; using namespace std;
@@ -62,20 +63,19 @@ const char* getStateCode(BusState state) {
} }
} }
result_t PollRequest::prepare(unsigned char ownMasterAddress) result_t PollRequest::prepare(unsigned char ownMasterAddress) {
{
istringstream input; istringstream input;
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, SYN, m_index); result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, SYN, m_index);
if (result == RESULT_OK) if (result == RESULT_OK) {
logInfo(lf_bus, "poll cmd: %s", m_master.getDataStr().c_str()); logInfo(lf_bus, "poll cmd: %s", m_master.getDataStr().c_str());
}
return result; return result;
} }
bool PollRequest::notify(result_t result, SymbolString& slave) bool PollRequest::notify(result_t result, SymbolString& slave) {
{
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = m_message->storeLastData(pt_slaveData, slave, m_index); result = m_message->storeLastData(pt_slaveData, slave, m_index);
if (result>=RESULT_OK && m_index+1 < m_message->getCount()) { if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
m_index++; m_index++;
result = prepare(m_master[0]); result = prepare(m_master[0]);
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
@@ -84,73 +84,79 @@ bool PollRequest::notify(result_t result, SymbolString& slave)
} }
} }
ostringstream output; ostringstream output;
if (result==RESULT_OK) if (result == RESULT_OK) {
result = m_message->decodeLastData(output); // decode data result = m_message->decodeLastData(output); // decode data
if (result < RESULT_OK) }
if (result < RESULT_OK) {
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), getResultCode(result)); logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), getResultCode(result));
else } else {
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), output.str().c_str()); logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), output.str().c_str());
}
return false; return false;
} }
result_t ScanRequest::prepare(unsigned char ownMasterAddress) result_t ScanRequest::prepare(unsigned char ownMasterAddress) {
{ if (m_slaves.empty()) {
if (m_slaves.empty())
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
}
unsigned char dstAddress = m_slaves.front(); unsigned char dstAddress = m_slaves.front();
if (m_index==0 && m_messages.size()==m_allMessages.size()) // first message for this address if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
m_busHandler->setScanResult(dstAddress, ""); m_busHandler->setScanResult(dstAddress, "");
}
istringstream input; istringstream input;
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index); result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index);
if (result >= RESULT_OK) if (result >= RESULT_OK) {
logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getDataStr().c_str()); logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getDataStr().c_str());
}
return result; return result;
} }
bool ScanRequest::notify(result_t result, SymbolString& slave) bool ScanRequest::notify(result_t result, SymbolString& slave) {
{
unsigned char dstAddress = m_master[1]; unsigned char dstAddress = m_master[1];
if (result == RESULT_OK) { if (result == RESULT_OK) {
if (m_message==m_messageMap->getScanMessage()) { if (m_message == m_messageMap->getScanMessage()) {
Message* message = m_messageMap->getScanMessage(dstAddress); Message* message = m_messageMap->getScanMessage(dstAddress);
if (message!=NULL) { if (message != NULL) {
m_message = message; m_message = message;
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
} }
} else if (m_message->getDstAddress()==SYN) { } else if (m_message->getDstAddress() == SYN) {
m_message = m_message->derive(dstAddress, true); m_message = m_message->derive(dstAddress, true);
m_messageMap->add(m_message); m_messageMap->add(m_message);
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
} }
result = m_message->storeLastData(pt_slaveData, slave, m_index); result = m_message->storeLastData(pt_slaveData, slave, m_index);
if (result>=RESULT_OK && m_index+1 < m_message->getCount()) { if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
m_index++; m_index++;
result = prepare(m_master[0]); result = prepare(m_master[0]);
if (result >= RESULT_OK) if (result >= RESULT_OK) {
return true; return true;
}
} }
if (result==RESULT_OK) if (result == RESULT_OK) {
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
}
} }
if (result < RESULT_OK) { if (result < RESULT_OK) {
if (!m_slaves.empty()) if (!m_slaves.empty()) {
m_slaves.pop_front(); m_slaves.pop_front();
if (result == RESULT_ERR_TIMEOUT) }
if (result == RESULT_ERR_TIMEOUT) {
logNotice(lf_bus, "scan %2.2x timed out (%d slaves left)", dstAddress, m_slaves.size()); logNotice(lf_bus, "scan %2.2x timed out (%d slaves left)", dstAddress, m_slaves.size());
else } else {
logError(lf_bus, "scan %2.2x failed (%d slaves left): %s", dstAddress, m_slaves.size(), getResultCode(result)); logError(lf_bus, "scan %2.2x failed (%d slaves left): %s", dstAddress, m_slaves.size(), getResultCode(result));
}
m_messages.clear(); // skip remaining secondary messages m_messages.clear(); // skip remaining secondary messages
} else if (m_messages.empty()) { } else if (m_messages.empty()) {
if (!m_slaves.empty()) if (!m_slaves.empty()) {
m_slaves.pop_front(); m_slaves.pop_front();
}
logNotice(lf_bus, "scan %2.2x completed (%d slaves left)", dstAddress, m_slaves.size()); logNotice(lf_bus, "scan %2.2x completed (%d slaves left)", dstAddress, m_slaves.size());
} }
if (m_messages.empty()) // last message for this address if (m_messages.empty()) { // last message for this address
m_busHandler->setScanResult(dstAddress, m_scanResult.str()); m_busHandler->setScanResult(dstAddress, m_scanResult.str());
}
if (m_slaves.empty()) { if (m_slaves.empty()) {
logNotice(lf_bus, "scan finished"); logNotice(lf_bus, "scan finished");
m_busHandler->setScanFinished(); m_busHandler->setScanFinished();
@@ -172,19 +178,16 @@ bool ScanRequest::notify(result_t result, SymbolString& slave)
} }
bool ActiveBusRequest::notify(result_t result, SymbolString& slave) bool ActiveBusRequest::notify(result_t result, SymbolString& slave) {
{ if (result == RESULT_OK) {
if (result == RESULT_OK)
logDebug(lf_bus, "read res: %s", slave.getDataStr().c_str()); logDebug(lf_bus, "read res: %s", slave.getDataStr().c_str());
}
m_result = result; m_result = result;
m_slave.addAll(slave, true); m_slave.addAll(slave, true);
return false; return false;
} }
void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) {
{
m_lastMaster.clear(false); m_lastMaster.clear(false);
m_lastMaster.addAll(master); m_lastMaster.addAll(master);
m_lastSlave.clear(false); m_lastSlave.clear(false);
@@ -192,8 +195,7 @@ void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave)
m_count++; m_count++;
} }
bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output) bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output) {
{
Message* message = messages->find(m_lastMaster); Message* message = messages->find(m_lastMaster);
if (unknown && message) { if (unknown && message) {
return false; return false;
@@ -214,15 +216,13 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first,
} }
void BusHandler::clear() void BusHandler::clear() {
{
memset(m_seenAddresses, 0, sizeof(m_seenAddresses)); memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
m_masterCount = 1; m_masterCount = 1;
m_scanResults.clear(); m_scanResults.clear();
} }
result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave) {
{
result_t result = RESULT_ERR_NO_SIGNAL; result_t result = RESULT_ERR_NO_SIGNAL;
slave.clear(); slave.clear();
ActiveBusRequest request(master, slave); ActiveBusRequest request(master, slave);
@@ -232,31 +232,28 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave)
m_nextRequests.push(&request); m_nextRequests.push(&request);
bool success = m_finishedRequests.remove(&request, true); bool success = m_finishedRequests.remove(&request, true);
result = success ? request.m_result : RESULT_ERR_TIMEOUT; result = success ? request.m_result : RESULT_ERR_TIMEOUT;
if (result == RESULT_OK) { if (result == RESULT_OK) {
Message* message = m_messages->find(master); Message* message = m_messages->find(master);
if (message != NULL) if (message != NULL) {
m_messages->invalidateCache(message); m_messages->invalidateCache(message);
}
break; break;
} }
if (!success || result == RESULT_ERR_NO_SIGNAL || result == RESULT_ERR_SEND || result == RESULT_ERR_DEVICE) { if (!success || result == RESULT_ERR_NO_SIGNAL || result == RESULT_ERR_SEND || result == RESULT_ERR_DEVICE) {
logError(lf_bus, "send to %2.2x: %s, give up", master[1], getResultCode(result)); logError(lf_bus, "send to %2.2x: %s, give up", master[1], getResultCode(result));
break; break;
} }
logError(lf_bus, "send to %2.2x: %s%s", master[1], getResultCode(result), sendRetries>0 ? ", retry" : ""); logError(lf_bus, "send to %2.2x: %s%s", master[1], getResultCode(result), sendRetries > 0 ? ", retry" : "");
request.m_busLostRetries = 0; request.m_busLostRetries = 0;
} }
return result; return result;
} }
result_t BusHandler::readFromBus(Message* message, string inputStr, const unsigned char dstAddress) result_t BusHandler::readFromBus(Message* message, string inputStr, const unsigned char dstAddress) {
{
result_t ret = RESULT_EMPTY; result_t ret = RESULT_EMPTY;
SymbolString master(true); SymbolString master(true);
SymbolString slave(false); SymbolString slave(false);
for (unsigned char index=0; index<message->getCount(); index++) { for (unsigned char index = 0; index < message->getCount(); index++) {
istringstream input(inputStr); istringstream input(inputStr);
ret = message->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index); ret = message->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
@@ -278,16 +275,16 @@ result_t BusHandler::readFromBus(Message* message, string inputStr, const unsign
return ret; return ret;
} }
void BusHandler::run() void BusHandler::run() {
{
unsigned int symCount = 0; unsigned int symCount = 0;
time_t lastTime; time_t lastTime;
time(&lastTime); time(&lastTime);
do { do {
if (m_device->isValid() && !m_reconnect) { if (m_device->isValid() && !m_reconnect) {
result_t result = handleSymbol(); result_t result = handleSymbol();
if (result != RESULT_ERR_TIMEOUT) if (result != RESULT_ERR_TIMEOUT) {
symCount++; symCount++;
}
time_t now; time_t now;
time(&now); time(&now);
if (now > lastTime) { if (now > lastTime) {
@@ -318,8 +315,7 @@ void BusHandler::run()
} while (isRunning()); } while (isRunning());
} }
result_t BusHandler::handleSymbol() result_t BusHandler::handleSymbol() {
{
long timeout = SYN_TIMEOUT; long timeout = SYN_TIMEOUT;
unsigned char sendSymbol = ESC; unsigned char sendSymbol = ESC;
bool sending = false; bool sending = false;
@@ -329,7 +325,7 @@ result_t BusHandler::handleSymbol()
switch (m_state) switch (m_state)
{ {
case bs_noSignal: case bs_noSignal:
timeout = m_generateSynInterval>0 ? m_generateSynInterval : SIGNAL_TIMEOUT; timeout = m_generateSynInterval > 0 ? m_generateSynInterval : SIGNAL_TIMEOUT;
break; break;
case bs_skip: case bs_skip:
@@ -373,10 +369,11 @@ result_t BusHandler::handleSymbol()
break; break;
case bs_recvRes: case bs_recvRes:
if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) {
timeout = m_slaveRecvTimeout; timeout = m_slaveRecvTimeout;
else } else {
timeout = SYN_TIMEOUT; timeout = SYN_TIMEOUT;
}
break; break;
case bs_recvResAck: case bs_recvResAck:
@@ -422,10 +419,11 @@ result_t BusHandler::handleSymbol()
if (sending) { if (sending) {
result = m_device->send(sendSymbol); result = m_device->send(sendSymbol);
if (result == RESULT_OK) { if (result == RESULT_OK) {
if (m_state == bs_ready) if (m_state == bs_ready) {
timeout = m_transferLatency+m_busAcquireTimeout; timeout = m_transferLatency+m_busAcquireTimeout;
else } else {
timeout = m_transferLatency+SEND_TIMEOUT; timeout = m_transferLatency+SEND_TIMEOUT;
}
} else { } else {
sending = false; sending = false;
timeout = SYN_TIMEOUT; timeout = SYN_TIMEOUT;
@@ -450,9 +448,9 @@ result_t BusHandler::handleSymbol()
if (result == RESULT_ERR_TIMEOUT) { if (result == RESULT_ERR_TIMEOUT) {
return setState(bs_noSignal, result); return setState(bs_noSignal, result);
} }
if (result != RESULT_OK) if (result != RESULT_OK) {
logError(lf_bus, "unable to receive sent AUTO-SYN symbol: %s", getResultCode(result)); logError(lf_bus, "unable to receive sent AUTO-SYN symbol: %s", getResultCode(result));
else if (recvSymbol != SYN) { } else if (recvSymbol != SYN) {
logError(lf_bus, "received %2.2x instead of AUTO-SYN symbol", recvSymbol); logError(lf_bus, "received %2.2x instead of AUTO-SYN symbol", recvSymbol);
} else { } else {
if (m_generateSynInterval != SYN_TIMEOUT) { if (m_generateSynInterval != SYN_TIMEOUT) {
@@ -473,19 +471,19 @@ result_t BusHandler::handleSymbol()
m_currentRequest = startRequest; // force the failed request to be notified m_currentRequest = startRequest; // force the failed request to be notified
} }
if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1) // at least one full second has passed since last received symbol if ((m_generateSynInterval != SYN_TIMEOUT && difftime(now, m_lastReceive) > 1) // at least one full second has passed since last received symbol
|| m_state == bs_noSignal) || m_state == bs_noSignal) {
return setState(bs_noSignal, result); return setState(bs_noSignal, result);
}
return setState(bs_skip, result); return setState(bs_skip, result);
} }
m_lastReceive = now; m_lastReceive = now;
if ((recvSymbol == SYN) && (m_state != bs_sendSyn)) { if ((recvSymbol == SYN) && (m_state != bs_sendSyn)) {
if (!sending && m_remainLockCount > 0 && m_command.size() != 1) if (!sending && m_remainLockCount > 0 && m_command.size() != 1) {
m_remainLockCount--; m_remainLockCount--;
else if (!sending && m_remainLockCount == 0 && m_command.size() == 1) } else if (!sending && m_remainLockCount == 0 && m_command.size() == 1) {
m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority) m_remainLockCount = 1; // wait for next AUTO-SYN after SYN / address / SYN (bus locked for own priority)
}
return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN); return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN);
} }
@@ -514,15 +512,16 @@ result_t BusHandler::handleSymbol()
} }
// arbitration lost. if same priority class found, try again after next AUTO-SYN // arbitration lost. if same priority class found, try again after next AUTO-SYN
m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try m_remainLockCount = isMaster(recvSymbol) ? 2 : 1; // number of SYN to wait for before next send try
if ((recvSymbol & 0x0f) != (sendSymbol & 0x0f) && m_lockCount > m_remainLockCount) if ((recvSymbol & 0x0f) != (sendSymbol & 0x0f) && m_lockCount > m_remainLockCount) {
// if different priority class found, try again after N AUTO-SYN symbols (at least next AUTO-SYN) // if different priority class found, try again after N AUTO-SYN symbols (at least next AUTO-SYN)
m_remainLockCount = m_lockCount; m_remainLockCount = m_lockCount;
}
setState(m_state, RESULT_ERR_BUS_LOST); // try again later setState(m_state, RESULT_ERR_BUS_LOST); // try again later
} }
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address result = m_command.push_back(recvSymbol, false); // expect no escaping for master address
if (result < RESULT_OK) if (result < RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
}
m_repeat = false; m_repeat = false;
return setState(bs_recvCmd, RESULT_OK); return setState(bs_recvCmd, RESULT_OK);
@@ -530,9 +529,9 @@ result_t BusHandler::handleSymbol()
headerLen = 4; headerLen = 4;
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; // header symbols are never escaped crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; // header symbols are never escaped
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos); result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
if (result < RESULT_OK) if (result < RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
}
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
unsigned char dstAddress = m_command[1]; unsigned char dstAddress = m_command[1];
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); // header symbols are never escaped m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); // header symbols are never escaped
@@ -542,36 +541,34 @@ result_t BusHandler::handleSymbol()
return setState(bs_skip, RESULT_OK); return setState(bs_skip, RESULT_OK);
} }
addSeenAddress(m_command[0]); addSeenAddress(m_command[0]);
if (m_answer if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
&& (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress))
return setState(bs_sendCmdAck, RESULT_OK); return setState(bs_sendCmdAck, RESULT_OK);
}
return setState(bs_recvCmdAck, RESULT_OK); return setState(bs_recvCmdAck, RESULT_OK);
} }
if (dstAddress == BROADCAST) if (dstAddress == BROADCAST) {
return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC);
}
if (m_answer if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
&& (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
return setState(bs_sendCmdAck, RESULT_ERR_CRC); return setState(bs_sendCmdAck, RESULT_ERR_CRC);
} }
if (m_repeat) if (m_repeat) {
return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC);
}
return setState(bs_recvCmdAck, RESULT_ERR_CRC); return setState(bs_recvCmdAck, RESULT_ERR_CRC);
} }
return RESULT_OK; return RESULT_OK;
case bs_recvCmdAck: case bs_recvCmdAck:
if (recvSymbol == ACK) { if (recvSymbol == ACK) {
if (!m_commandCrcValid) if (!m_commandCrcValid) {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
}
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
if (isMaster(m_currentRequest->m_master[1])) { if (isMaster(m_currentRequest->m_master[1])) {
return setState(bs_sendSyn, RESULT_OK); return setState(bs_sendSyn, RESULT_OK);
} }
} } else if (isMaster(m_command[1])) { // header symbols are never escaped
else if (isMaster(m_command[1])) { // header symbols are never escaped
receiveCompleted(); receiveCompleted();
return setState(bs_skip, RESULT_OK); return setState(bs_skip, RESULT_OK);
} }
@@ -584,50 +581,48 @@ result_t BusHandler::handleSymbol()
m_repeat = true; m_repeat = true;
m_nextSendPos = 0; m_nextSendPos = 0;
m_command.clear(); m_command.clear();
if (m_currentRequest != NULL) if (m_currentRequest != NULL) {
return setState(bs_sendCmd, RESULT_ERR_NAK, true); return setState(bs_sendCmd, RESULT_ERR_NAK, true);
}
return setState(bs_recvCmd, RESULT_ERR_NAK); return setState(bs_recvCmd, RESULT_ERR_NAK);
} }
return setState(bs_skip, RESULT_ERR_NAK); return setState(bs_skip, RESULT_ERR_NAK);
} }
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
case bs_recvRes: case bs_recvRes:
headerLen = 0; headerLen = 0;
crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff; crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff;
result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos); result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos);
if (result < RESULT_OK) if (result < RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
}
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC(); m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC();
if (m_responseCrcValid) { if (m_responseCrcValid) {
if (m_currentRequest != NULL) if (m_currentRequest != NULL) {
return setState(bs_sendResAck, RESULT_OK); return setState(bs_sendResAck, RESULT_OK);
}
return setState(bs_recvResAck, RESULT_OK); return setState(bs_recvResAck, RESULT_OK);
} }
if (m_repeat) { if (m_repeat) {
if (m_currentRequest != NULL) if (m_currentRequest != NULL) {
return setState(bs_sendSyn, RESULT_ERR_CRC); return setState(bs_sendSyn, RESULT_ERR_CRC);
}
return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC);
} }
if (m_currentRequest != NULL) if (m_currentRequest != NULL) {
return setState(bs_sendResAck, RESULT_ERR_CRC); return setState(bs_sendResAck, RESULT_ERR_CRC);
}
return setState(bs_recvResAck, RESULT_ERR_CRC); return setState(bs_recvResAck, RESULT_ERR_CRC);
} }
return RESULT_OK; return RESULT_OK;
case bs_recvResAck: case bs_recvResAck:
if (recvSymbol == ACK) { if (recvSymbol == ACK) {
if (!m_responseCrcValid) if (!m_responseCrcValid) {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
}
receiveCompleted(); receiveCompleted();
return setState(bs_skip, RESULT_OK); return setState(bs_skip, RESULT_OK);
} }
@@ -647,9 +642,9 @@ result_t BusHandler::handleSymbol()
m_nextSendPos++; m_nextSendPos++;
if (m_nextSendPos >= m_currentRequest->m_master.size()) { if (m_nextSendPos >= m_currentRequest->m_master.size()) {
// master data completely sent // master data completely sent
if (m_currentRequest->m_master[1] == BROADCAST) if (m_currentRequest->m_master[1] == BROADCAST) {
return setState(bs_sendSyn, RESULT_OK); return setState(bs_sendSyn, RESULT_OK);
}
m_commandCrcValid = true; m_commandCrcValid = true;
return setState(bs_recvCmdAck, RESULT_OK); return setState(bs_recvCmdAck, RESULT_OK);
} }
@@ -695,20 +690,22 @@ result_t BusHandler::handleSymbol()
message = m_messages->find(m_command); message = m_messages->find(m_command);
if (message == NULL) { if (message == NULL) {
message = m_messages->find(m_command, true); message = m_messages->find(m_command, true);
if (message!=NULL && message->getSrcAddress()!=SYN) if (message != NULL && message->getSrcAddress() != SYN) {
message = NULL; message = NULL;
}
} }
if (message == NULL || message->isWrite()) if (message == NULL || message->isWrite()) {
return setState(bs_skip, RESULT_ERR_INVALID_ARG); // don't know this request or definition has wrong direction, deny return setState(bs_skip, RESULT_ERR_INVALID_ARG); // don't know this request or definition has wrong direction, deny
}
if (message == m_messages->getScanMessage(m_ownSlaveAddress)) { if (message == m_messages->getScanMessage(m_ownSlaveAddress)) {
input.str(SCAN_ANSWER); input.str(SCAN_ANSWER);
} }
// build response and store in m_response for sending back to requesting master // build response and store in m_response for sending back to requesting master
m_response.clear(true); // escape while sending response m_response.clear(true); // escape while sending response
result = message->prepareSlave(input, m_response); result = message->prepareSlave(input, m_response);
if (result != RESULT_OK) if (result != RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
}
return setState(bs_sendRes, RESULT_OK); return setState(bs_sendRes, RESULT_OK);
} }
return setState(bs_skip, RESULT_ERR_INVALID_ARG); return setState(bs_skip, RESULT_ERR_INVALID_ARG);
@@ -733,12 +730,10 @@ result_t BusHandler::handleSymbol()
return setState(bs_skip, RESULT_ERR_INVALID_ARG); return setState(bs_skip, RESULT_ERR_INVALID_ARG);
} }
return RESULT_OK; return RESULT_OK;
} }
result_t BusHandler::setState(BusState state, result_t result, bool firstRepetition) result_t BusHandler::setState(BusState state, result_t result, bool firstRepetition) {
{
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
if (result == RESULT_ERR_BUS_LOST && m_currentRequest->m_busLostRetries < m_busLostRetries) { if (result == RESULT_ERR_BUS_LOST && m_currentRequest->m_busLostRetries < m_busLostRetries) {
logDebug(lf_bus, "%s during %s, retry", getResultCode(result), getStateCode(m_state)); logDebug(lf_bus, "%s during %s, retry", getResultCode(result), getStateCode(m_state));
@@ -808,13 +803,12 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
return result; return result;
} }
void BusHandler::addSeenAddress(unsigned char address) void BusHandler::addSeenAddress(unsigned char address) {
{
if (!isValidAddress(address, false)) { if (!isValidAddress(address, false)) {
return; return;
} }
if (!isMaster(address)) { if (!isMaster(address)) {
if (!m_device->isReadOnly() && address==m_ownSlaveAddress) { if (!m_device->isReadOnly() && address == m_ownSlaveAddress) {
if (!m_addressConflict) { if (!m_addressConflict) {
m_addressConflict = true; m_addressConflict = true;
logError(lf_bus, "own slave address %2.2x is used by another participant", address); logError(lf_bus, "own slave address %2.2x is used by another participant", address);
@@ -822,19 +816,19 @@ void BusHandler::addSeenAddress(unsigned char address)
} }
m_seenAddresses[address] |= SEEN; m_seenAddresses[address] |= SEEN;
address = getMasterAddress(address); address = getMasterAddress(address);
if (address==SYN) { if (address == SYN) {
return; return;
} }
} }
if ((m_seenAddresses[address]&SEEN)==0) { if ((m_seenAddresses[address]&SEEN) == 0) {
if (!m_device->isReadOnly() && address==m_ownMasterAddress) { if (!m_device->isReadOnly() && address == m_ownMasterAddress) {
if (!m_addressConflict) { if (!m_addressConflict) {
m_addressConflict = true; m_addressConflict = true;
logError(lf_bus, "own master address %2.2x is used by another participant", address); logError(lf_bus, "own master address %2.2x is used by another participant", address);
} }
} else { } else {
m_masterCount++; m_masterCount++;
if (m_autoLockCount && m_masterCount>m_lockCount) { if (m_autoLockCount && m_masterCount > m_lockCount) {
m_lockCount = m_masterCount; m_lockCount = m_masterCount;
} }
logNotice(lf_bus, "new master %2.2x, master count %d", address, m_masterCount); logNotice(lf_bus, "new master %2.2x, master count %d", address, m_masterCount);
@@ -843,8 +837,7 @@ void BusHandler::addSeenAddress(unsigned char address)
} }
} }
void BusHandler::receiveCompleted() void BusHandler::receiveCompleted() {
{
unsigned char srcAddress = m_command[0], dstAddress = m_command[1]; unsigned char srcAddress = m_command[0], dstAddress = m_command[1];
if (srcAddress == dstAddress) { if (srcAddress == dstAddress) {
logError(lf_bus, "invalid self-addressed message from %2.2x", srcAddress); logError(lf_bus, "invalid self-addressed message from %2.2x", srcAddress);
@@ -856,17 +849,17 @@ void BusHandler::receiveCompleted()
bool master = isMaster(dstAddress); bool master = isMaster(dstAddress);
if (dstAddress == BROADCAST) { if (dstAddress == BROADCAST) {
logInfo(lf_update, "update BC cmd: %s", m_command.getDataStr().c_str()); logInfo(lf_update, "update BC cmd: %s", m_command.getDataStr().c_str());
if (m_command.size()>=5+9 && m_command[2]==0x07 && m_command[3]==0x04) { if (m_command.size() >= 5+9 && m_command[2] == 0x07 && m_command[3] == 0x04) {
unsigned char slaveAddress = (unsigned char)((srcAddress+5)&0xff); unsigned char slaveAddress = (unsigned char)((srcAddress+5)&0xff);
addSeenAddress(slaveAddress); addSeenAddress(slaveAddress);
Message* message = m_messages->getScanMessage(slaveAddress); Message* message = m_messages->getScanMessage(slaveAddress);
if (message && (message->getLastUpdateTime()==0 || message->getLastSlaveData().size()<10)) { if (message && (message->getLastUpdateTime() == 0 || message->getLastSlaveData().size() < 10)) {
// e.g. 10fe07040a b5564149303001248901 // e.g. 10fe07040a b5564149303001248901
m_seenAddresses[slaveAddress] |= SCAN_INIT; m_seenAddresses[slaveAddress] |= SCAN_INIT;
SymbolString idData; SymbolString idData;
istringstream input; istringstream input;
result_t result = message->prepareMaster(m_ownMasterAddress, idData, input); result_t result = message->prepareMaster(m_ownMasterAddress, idData, input);
if (result==RESULT_OK) { if (result == RESULT_OK) {
idData.clear(); idData.clear();
idData.push_back(9); idData.push_back(9);
for (size_t i = 5; i <= 5+9; i++) { for (size_t i = 5; i <= 5+9; i++) {
@@ -874,7 +867,7 @@ void BusHandler::receiveCompleted()
} }
result = message->storeLastData(pt_slaveData, idData, 0); result = message->storeLastData(pt_slaveData, idData, 0);
} }
if (result==RESULT_OK) { if (result == RESULT_OK) {
m_seenAddresses[slaveAddress] |= SCAN_DONE; m_seenAddresses[slaveAddress] |= SCAN_DONE;
} }
logNotice(lf_update, "store BC ident: %s", getResultCode(result)); logNotice(lf_update, "store BC ident: %s", getResultCode(result));
@@ -909,7 +902,7 @@ void BusHandler::receiveCompleted()
string name = message->getName(); string name = message->getName();
result_t result = message->storeLastData(m_command, m_response); result_t result = message->storeLastData(m_command, m_response);
ostringstream output; ostringstream output;
if (result==RESULT_OK) { if (result == RESULT_OK) {
result = message->decodeLastData(output); result = message->decodeLastData(output);
} }
if (result < RESULT_OK) { if (result < RESULT_OK) {
@@ -933,29 +926,31 @@ void BusHandler::receiveCompleted()
} }
} }
result_t BusHandler::startScan(bool full) result_t BusHandler::startScan(bool full) {
{
deque<Message*> messages = m_messages->findAll("scan", "", true); deque<Message*> messages = m_messages->findAll("scan", "", true);
for (deque<Message*>::iterator it = messages.begin(); it < messages.end(); it++) { for (deque<Message*>::iterator it = messages.begin(); it < messages.end(); it++) {
Message* message = *it; Message* message = *it;
if (message->getPrimaryCommand() == 0x07 && message->getSecondaryCommand() == 0x04) if (message->getPrimaryCommand() == 0x07 && message->getSecondaryCommand() == 0x04) {
messages.erase(it--); // query pb 0x07 / sb 0x04 only once messages.erase(it--); // query pb 0x07 / sb 0x04 only once
}
} }
Message* scanMessage = m_messages->getScanMessage(); Message* scanMessage = m_messages->getScanMessage();
if (scanMessage==NULL) if (scanMessage == NULL) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
}
m_scanResults.clear(); m_scanResults.clear();
deque<unsigned char> slaves; deque<unsigned char> slaves;
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (!isValidAddress(slave, false) || isMaster(slave)) if (!isValidAddress(slave, false) || isMaster(slave)) {
continue; continue;
if (!full && (m_seenAddresses[slave]&SEEN)==0) { }
if (!full && (m_seenAddresses[slave]&SEEN) == 0) {
unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already unsigned char master = getMasterAddress(slave); // check if we saw the corresponding master already
if (master == SYN || (m_seenAddresses[master]&SEEN)==0) if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
continue; continue;
}
} }
slaves.push_back(slave); slaves.push_back(slave);
} }
@@ -964,55 +959,55 @@ result_t BusHandler::startScan(bool full)
result_t result = request->prepare(m_ownMasterAddress); result_t result = request->prepare(m_ownMasterAddress);
if (result < RESULT_OK) { if (result < RESULT_OK) {
delete request; delete request;
return result==RESULT_ERR_EOF ? RESULT_EMPTY : result; return result == RESULT_ERR_EOF ? RESULT_EMPTY : result;
} }
m_runningScans++; m_runningScans++;
m_nextRequests.push(request); m_nextRequests.push(request);
return RESULT_OK; return RESULT_OK;
} }
void BusHandler::setScanResult(unsigned char dstAddress, string str) void BusHandler::setScanResult(unsigned char dstAddress, string str) {
{
m_seenAddresses[dstAddress] |= SCAN_INIT; m_seenAddresses[dstAddress] |= SCAN_INIT;
if (str.length()>0) { if (str.length() > 0) {
m_seenAddresses[dstAddress] |= SCAN_DONE; m_seenAddresses[dstAddress] |= SCAN_DONE;
m_scanResults[dstAddress] = str; m_scanResults[dstAddress] = str;
logNotice(lf_bus, "scan %2.2x: %s", dstAddress, str.c_str()); logNotice(lf_bus, "scan %2.2x: %s", dstAddress, str.c_str());
} }
} }
void BusHandler::setScanFinished() void BusHandler::setScanFinished() {
{ if (m_runningScans > 0) {
if (m_runningScans>0)
m_runningScans--; m_runningScans--;
}
} }
void BusHandler::formatScanResult(ostringstream& output) void BusHandler::formatScanResult(ostringstream& output) {
{ if (m_runningScans > 0) {
if (m_runningScans>0) {
output << static_cast<unsigned>(m_runningScans) << " scan(s) still running" << endl; output << static_cast<unsigned>(m_runningScans) << " scan(s) still running" << endl;
} }
bool first = true; bool first = true;
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
map<unsigned char, string>::iterator it = m_scanResults.find(slave); map<unsigned char, string>::iterator it = m_scanResults.find(slave);
if (it != m_scanResults.end()) { if (it != m_scanResults.end()) {
if (first) if (first) {
first = false; first = false;
else } else {
output << endl; output << endl;
}
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave) << it->second; output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave) << it->second;
} }
} }
if (first) { if (first) {
// fallback to autoscan results // fallback to autoscan results
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (isValidAddress(slave, false) && !isMaster(slave) && (m_seenAddresses[slave]&SCAN_DONE)!=0) { if (isValidAddress(slave, false) && !isMaster(slave) && (m_seenAddresses[slave]&SCAN_DONE) != 0) {
Message* message = m_messages->getScanMessage(slave); Message* message = m_messages->getScanMessage(slave);
if (message!=NULL && message->getLastUpdateTime()>0) { if (message != NULL && message->getLastUpdateTime() > 0) {
if (first) if (first) {
first = false; first = false;
else } else {
output << endl; output << endl;
}
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave); output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave);
message->decodeLastData(output, 0, true); message->decodeLastData(output, 0, true);
} }
@@ -1021,12 +1016,11 @@ void BusHandler::formatScanResult(ostringstream& output)
} }
} }
void BusHandler::formatSeenInfo(ostringstream& output) void BusHandler::formatSeenInfo(ostringstream& output) {
{
unsigned char address = 0; unsigned char address = 0;
for (int index=0; index<256; index++, address++) { for (int index = 0; index < 256; index++, address++) {
if (isValidAddress(address, false) if (isValidAddress(address, false)
&& ((m_seenAddresses[address]&SEEN)!=0 || (!m_device->isReadOnly() && (address==m_ownMasterAddress || address==m_ownSlaveAddress)))) { && ((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); output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address);
unsigned char master; unsigned char master;
if (isMaster(address)) { if (isMaster(address)) {
@@ -1036,25 +1030,26 @@ void BusHandler::formatSeenInfo(ostringstream& output)
output << ": slave"; output << ": slave";
master = getMasterAddress(address); master = getMasterAddress(address);
} }
if (master != SYN) if (master != SYN) {
output << " #" << setw(0) << dec << static_cast<unsigned>(getMasterNumber(master)); output << " #" << setw(0) << dec << static_cast<unsigned>(getMasterNumber(master));
if (!m_device->isReadOnly() && (address==m_ownMasterAddress || address==m_ownSlaveAddress)) { }
if (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)) {
output << ", ebusd"; output << ", ebusd";
if (m_answer) { if (m_answer) {
output << " (answering)"; output << " (answering)";
} }
if (m_addressConflict && (m_seenAddresses[address]&SEEN)!=0) { if (m_addressConflict && (m_seenAddresses[address]&SEEN) != 0) {
output << ", conflict"; output << ", conflict";
} }
} }
if ((m_seenAddresses[address]&SCAN_DONE)!=0) { if ((m_seenAddresses[address]&SCAN_DONE) != 0) {
output << ", scanned"; output << ", scanned";
Message* message = m_messages->getScanMessage(address); Message* message = m_messages->getScanMessage(address);
if (message!=NULL && message->getLastUpdateTime()>0) { if (message != NULL && message->getLastUpdateTime() > 0) {
// add detailed scan info: Manufacturer ID SW HW // add detailed scan info: Manufacturer ID SW HW
output << " \""; output << " \"";
result_t result = message->decodeLastData(output, OF_NAMES); result_t result = message->decodeLastData(output, OF_NAMES);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
output << "\" error: " << getResultCode(result); output << "\" error: " << getResultCode(result);
} else { } else {
output << "\""; output << "\"";
@@ -1062,45 +1057,46 @@ void BusHandler::formatSeenInfo(ostringstream& output)
} }
} }
string loadedFiles = m_messages->getLoadedFiles(address); string loadedFiles = m_messages->getLoadedFiles(address);
if (!loadedFiles.empty()) if (!loadedFiles.empty()) {
output << ", loaded " << loadedFiles; output << ", loaded " << loadedFiles;
}
} }
} }
} }
result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave) result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave) {
{ if (!isValidAddress(dstAddress) || isMaster(dstAddress)) {
if (!isValidAddress(dstAddress) || isMaster(dstAddress))
return RESULT_ERR_INVALID_ADDR; return RESULT_ERR_INVALID_ADDR;
}
m_seenAddresses[dstAddress] |= SCAN_INIT; m_seenAddresses[dstAddress] |= SCAN_INIT;
Message* scanMessage = m_messages->getScanMessage(); Message* scanMessage = m_messages->getScanMessage();
if (scanMessage==NULL) { if (scanMessage == NULL) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
istringstream input; istringstream input;
SymbolString master; SymbolString master;
result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress); result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress);
if (result==RESULT_OK) { if (result == RESULT_OK) {
result = sendAndWait(master, slave); result = sendAndWait(master, slave);
if (result==RESULT_OK) { if (result == RESULT_OK) {
Message* message = m_messages->getScanMessage(dstAddress); Message* message = m_messages->getScanMessage(dstAddress);
if (message!=NULL && message!=scanMessage) { if (message != NULL && message != scanMessage) {
scanMessage = message; scanMessage = message;
scanMessage->storeLastData(pt_masterData, master, 0); // update the cache, expected to work since this is a clone scanMessage->storeLastData(pt_masterData, master, 0); // update the cache, expected to work since this is a clone
} }
} }
if (result!=RESULT_ERR_NO_SIGNAL) if (result != RESULT_ERR_NO_SIGNAL) {
m_seenAddresses[dstAddress] |= SCAN_DONE; m_seenAddresses[dstAddress] |= SCAN_DONE;
}
} }
if (result != RESULT_OK || slave.size() == 0) // avoid "invalid position" during decode if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
return result; return result;
}
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
} }
bool BusHandler::enableGrab(bool enable) bool BusHandler::enableGrab(bool enable) {
{ if (enable == m_grabMessages) {
if (enable==m_grabMessages) {
return false; return false;
} }
if (!enable) { if (!enable) {
@@ -1110,8 +1106,7 @@ bool BusHandler::enableGrab(bool enable)
return true; return true;
} }
void BusHandler::formatGrabResult(const bool unknown, ostringstream& output) void BusHandler::formatGrabResult(const bool unknown, ostringstream& output) {
{
if (!m_grabMessages) { if (!m_grabMessages) {
output << "grab disabled"; output << "grab disabled";
} else { } else {
@@ -1125,18 +1120,20 @@ void BusHandler::formatGrabResult(const bool unknown, ostringstream& output)
} }
unsigned char BusHandler::getNextScanAddress(unsigned char lastAddress, bool& scanned) { unsigned char BusHandler::getNextScanAddress(unsigned char lastAddress, bool& scanned) {
if (lastAddress==SYN) if (lastAddress == SYN) {
return SYN; return SYN;
while (++lastAddress!=0) { // 0 is known to be a master }
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) while (++lastAddress != 0) { // 0 is known to be a master
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) {
continue; continue;
if ((m_seenAddresses[lastAddress]&(SEEN|LOAD_INIT))==SEEN) { }
scanned = (m_seenAddresses[lastAddress]&SCAN_INIT)!=0; if ((m_seenAddresses[lastAddress]&(SEEN|LOAD_INIT)) == SEEN) {
scanned = (m_seenAddresses[lastAddress]&SCAN_INIT) != 0;
return lastAddress; return lastAddress;
} }
unsigned char master = getMasterAddress(lastAddress); unsigned char master = getMasterAddress(lastAddress);
if (master!=SYN && (m_seenAddresses[master]&SEEN)!=0 && (m_seenAddresses[lastAddress]&LOAD_INIT)==0) { if (master != SYN && (m_seenAddresses[master]&SEEN) != 0 && (m_seenAddresses[lastAddress]&LOAD_INIT) == 0) {
scanned = (m_seenAddresses[lastAddress]&SCAN_INIT)!=0; scanned = (m_seenAddresses[lastAddress]&SCAN_INIT) != 0;
return lastAddress; return lastAddress;
} }
} }
+16 -15
View File
@@ -16,9 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef BUSHANDLER_H_ #ifndef EBUSD_BUSHANDLER_H_
#define BUSHANDLER_H_ #define EBUSD_BUSHANDLER_H_
#include <pthread.h>
#include <string>
#include <vector>
#include <map>
#include <deque>
#include "message.h" #include "message.h"
#include "data.h" #include "data.h"
#include "symbol.h" #include "symbol.h"
@@ -26,10 +31,6 @@
#include "device.h" #include "device.h"
#include "queue.h" #include "queue.h"
#include "thread.h" #include "thread.h"
#include <string>
#include <vector>
#include <map>
#include <pthread.h>
/** @file bushandler.h /** @file bushandler.h
* Classes, functions, and constants related to handling of symbols on the eBUS. * Classes, functions, and constants related to handling of symbols on the eBUS.
@@ -367,7 +368,7 @@ public:
m_answer(answer), m_addressConflict(false), m_answer(answer), m_addressConflict(false),
m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries), m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries),
m_transferLatency(transferLatency), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout), m_transferLatency(transferLatency), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout),
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount==0), m_lockCount(lockCount<=3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount), m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0), m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
m_generateSynInterval(generateSyn ? SYN_TIMEOUT*getMasterNumber(ownAddress)+SYMBOL_DURATION : 0), m_generateSynInterval(generateSyn ? SYN_TIMEOUT*getMasterNumber(ownAddress)+SYMBOL_DURATION : 0),
m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0), m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0),
m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0), m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0),
@@ -386,15 +387,15 @@ public:
stop(); stop();
join(); join();
BusRequest* req; BusRequest* req;
while ((req = m_finishedRequests.pop())!=NULL) { while ((req = m_finishedRequests.pop()) != NULL) {
delete req; delete req;
} }
while ((req = m_nextRequests.pop())!=NULL) { while ((req = m_nextRequests.pop()) != NULL) {
if (req->m_deleteOnFinish) { if (req->m_deleteOnFinish) {
delete req; delete req;
} }
} }
if (m_currentRequest!=NULL) { if (m_currentRequest != NULL) {
delete m_currentRequest; delete m_currentRequest;
m_currentRequest = NULL; m_currentRequest = NULL;
} }
@@ -420,7 +421,7 @@ public:
* @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction. * @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction.
* @return the result code. * @return the result code.
*/ */
result_t readFromBus(Message* message, string inputStr, const unsigned char dstAddress=SYN); result_t readFromBus(Message* message, string inputStr, const unsigned char dstAddress = SYN);
/** /**
* Main thread entry. * Main thread entry.
@@ -432,7 +433,7 @@ public:
* @param full true for a full scan (all slaves), false for scanning only already seen slaves. * @param full true for a full scan (all slaves), false for scanning only already seen slaves.
* @return the result code. * @return the result code.
*/ */
result_t startScan(bool full=false); result_t startScan(bool full = false);
/** /**
* Set the scan result @a string for a scanned slave address. * Set the scan result @a string for a scanned slave address.
@@ -471,7 +472,7 @@ public:
* @param enable true to enable grabbing, false to disable it. * @param enable true to enable grabbing, false to disable it.
* @return true when the grabbing was changed. * @return true when the grabbing was changed.
*/ */
bool enableGrab(bool enable=true); bool enableGrab(bool enable = true);
/** /**
* Format the grabbed messages to the @a ostringstream. * Format the grabbed messages to the @a ostringstream.
@@ -539,7 +540,7 @@ private:
* @param firstRepetition true if the first repetition of a message part is being started. * @param firstRepetition true if the first repetition of a message part is being started.
* @return the result code. * @return the result code.
*/ */
result_t setState(BusState state, result_t result, bool firstRepetition=false); result_t setState(BusState state, result_t result, bool firstRepetition = false);
/** /**
* Add a seen bus address. * Add a seen bus address.
@@ -666,4 +667,4 @@ private:
}; };
#endif // BUSHANDLER_H_ #endif // EBUSD_BUSHANDLER_H_
+7 -9
View File
@@ -16,11 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "datahandler.h"
#include <list>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
#include "datahandler.h"
#include <list>
#ifdef HAVE_MQTT #ifdef HAVE_MQTT
# include "mqtthandler.h" # include "mqtthandler.h"
#endif #endif
@@ -38,21 +39,19 @@ static struct argp_child g_argp_children[
+1 +1
]; ];
const struct argp_child* datahandler_getargs() const struct argp_child* datahandler_getargs() {
{
size_t count = 0; size_t count = 0;
#ifdef HAVE_MQTT #ifdef HAVE_MQTT
g_argp_children[count++] = *mqtthandler_getargs(); g_argp_children[count++] = *mqtthandler_getargs();
#endif #endif
if (count>0) { if (count > 0) {
g_argp_children[count] = g_last_argp_child; g_argp_children[count] = g_last_argp_child;
return g_argp_children; return g_argp_children;
} }
return NULL; return NULL;
} }
bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<DataHandler*>& handlers) bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<DataHandler*>& handlers) {
{
bool success = true; bool success = true;
#ifdef HAVE_MQTT #ifdef HAVE_MQTT
DataHandler* handler = mqtthandler_register(busHandler, messages); DataHandler* handler = mqtthandler_register(busHandler, messages);
@@ -65,7 +64,6 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
return success; return success;
} }
void DataSink::notifyUpdate(Message* message) void DataSink::notifyUpdate(Message* message) {
{
m_updatedMessages[message]++; m_updatedMessages[message]++;
} }
+6 -4
View File
@@ -16,12 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef DATAHANDLER_H_ #ifndef EBUSD_DATAHANDLER_H_
#define DATAHANDLER_H_ #define EBUSD_DATAHANDLER_H_
#include <argp.h>
#include <map>
#include <list>
#include "bushandler.h" #include "bushandler.h"
#include "message.h" #include "message.h"
#include <argp.h>
/** @file datahandler.h /** @file datahandler.h
* Classes and functions for implementing and registering generic data sinks * Classes and functions for implementing and registering generic data sinks
@@ -148,4 +150,4 @@ protected:
}; };
#endif // DATAHANDLER_H_ #endif // EBUSD_DATAHANDLER_H_
+88 -90
View File
@@ -21,19 +21,22 @@
#endif #endif
#include "main.h" #include "main.h"
#include "mainloop.h" #include <dirent.h>
#include "bushandler.h" #include <sys/types.h>
#include "log.h" #include <sys/stat.h>
#include "rotatefile.h"
#include <stdlib.h> #include <stdlib.h>
#include <argp.h> #include <argp.h>
#include <csignal> #include <csignal>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <dirent.h> #include <map>
#include <sys/types.h> #include <string>
#include <sys/stat.h> #include <vector>
#include "mainloop.h"
#include "bushandler.h"
#include "log.h"
#include "rotatefile.h"
/** the path and name of the PID file. */ /** the path and name of the PID file. */
#ifdef PACKAGE_PIDFILE #ifdef PACKAGE_PIDFILE
@@ -207,8 +210,7 @@ static map<string, DataFieldTemplates*> s_templatesByPath;
* @param arg the option argument, or NULL. * @param arg the option argument, or NULL.
* @param state the parsing state. * @param state the parsing state.
*/ */
error_t parse_opt(int key, char *arg, struct argp_state *state) error_t parse_opt(int key, char *arg, struct argp_state *state) {
{
struct options *opt = (struct options*)state->input; struct options *opt = (struct options*)state->input;
result_t result = RESULT_OK; result_t result = RESULT_OK;
@@ -278,8 +280,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
} }
break; break;
case O_CHKCFG: // --checkconfig case O_CHKCFG: // --checkconfig
if (opt->checkConfig==0) if (opt->checkConfig == 0) {
opt->checkConfig = 1; opt->checkConfig = 1;
}
break; break;
case O_DMPCFG: // --dumpconfig case O_DMPCFG: // --dumpconfig
opt->checkConfig = 2; opt->checkConfig = 2;
@@ -466,8 +469,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
return 0; return 0;
} }
void daemonize() void daemonize() {
{
// fork off the parent process // fork off the parent process
pid_t pid = fork(); pid_t pid = fork();
@@ -477,9 +479,9 @@ void daemonize()
} }
// If we got a good PID, then we can exit the parent process // If we got a good PID, then we can exit the parent process
if (pid > 0) if (pid > 0) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
}
// At this point we are executing as the child process // At this point we are executing as the child process
// Create a new SID for the child process and // Create a new SID for the child process and
@@ -509,7 +511,7 @@ void daemonize()
if (pidFile != NULL) { if (pidFile != NULL) {
setbuf(pidFile, NULL); // disable buffering setbuf(pidFile, NULL); // disable buffering
if (lockf(fileno(pidFile), F_TLOCK, 0) < 0 if (lockf(fileno(pidFile), F_TLOCK, 0) < 0
|| fprintf(pidFile, "%d\n", getpid()) <=0) { || fprintf(pidFile, "%d\n", getpid()) <= 0) {
fclose(pidFile); fclose(pidFile);
pidFile = NULL; pidFile = NULL;
} }
@@ -522,12 +524,11 @@ void daemonize()
isDaemon = true; isDaemon = true;
} }
void closePidFile() void closePidFile() {
{
if (pidFile != NULL) { if (pidFile != NULL) {
if (fclose(pidFile) != 0) if (fclose(pidFile) != 0) {
return; return;
}
remove(opt.pidFile); remove(opt.pidFile);
} }
} }
@@ -535,20 +536,19 @@ void closePidFile()
/** /**
* Helper method performing shutdown. * Helper method performing shutdown.
*/ */
void shutdown() void shutdown() {
{
// stop main loop and all dependent components // stop main loop and all dependent components
if (s_mainLoop != NULL) { if (s_mainLoop != NULL) {
delete s_mainLoop; delete s_mainLoop;
s_mainLoop = NULL; s_mainLoop = NULL;
} }
if (s_messageMap!=NULL) { if (s_messageMap != NULL) {
delete s_messageMap; delete s_messageMap;
s_messageMap = NULL; s_messageMap = NULL;
} }
// free templates // free templates
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) { for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) {
if (it->second!=&s_globalTemplates) { if (it->second != &s_globalTemplates) {
delete it->second; delete it->second;
} }
it->second = NULL; it->second = NULL;
@@ -573,8 +573,7 @@ void shutdown()
* The signal handling function. * The signal handling function.
* @param sig the received signal. * @param sig the received signal.
*/ */
void signalHandler(int sig) void signalHandler(int sig) {
{
switch (sig) { switch (sig) {
case SIGHUP: case SIGHUP:
logNotice(lf_main, "SIGHUP received"); logNotice(lf_main, "SIGHUP received");
@@ -604,37 +603,36 @@ void signalHandler(int sig)
* @return the result code. * @return the result code.
*/ */
static result_t collectConfigFiles(const string path, const string prefix, const string extension, static result_t collectConfigFiles(const string path, const string prefix, const string extension,
vector<string>& files, vector<string>* dirs=NULL, bool* hasTemplates=NULL) vector<string>& files, vector<string>* dirs = NULL, bool* hasTemplates = NULL) {
{
DIR* dir = opendir(path.c_str()); DIR* dir = opendir(path.c_str());
if (dir == NULL) if (dir == NULL) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
}
dirent* d; dirent* d;
while ((d = readdir(dir)) != NULL) { while ((d = readdir(dir)) != NULL) {
string name = d->d_name; string name = d->d_name;
if (name == "." || name == "..") if (name == "." || name == "..") {
continue; continue;
}
const string p = path + "/" + name; const string p = path + "/" + name;
struct stat stat_buf; struct stat stat_buf;
if (stat(p.c_str(), &stat_buf) != 0) if (stat(p.c_str(), &stat_buf) != 0) {
continue; continue;
}
if (S_ISDIR(stat_buf.st_mode)) { if (S_ISDIR(stat_buf.st_mode)) {
if (dirs!=NULL) if (dirs != NULL) {
dirs->push_back(p); dirs->push_back(p);
} else if (S_ISREG(stat_buf.st_mode) && name.length()>=extension.length() }
&& name.substr(name.length()-extension.length())==extension) { } else if (S_ISREG(stat_buf.st_mode) && name.length() >= extension.length()
if (name=="_templates"+extension) { && name.substr(name.length()-extension.length()) == extension) {
if (name == "_templates"+extension) {
if (hasTemplates) { if (hasTemplates) {
*hasTemplates = true; *hasTemplates = true;
} }
} else if (prefix.length()==0 || (name.length()>=prefix.length() && name.substr(0, prefix.length())==prefix)) { } else if (prefix.length() == 0 || (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
files.push_back(p); files.push_back(p);
} }
} }
@@ -647,11 +645,11 @@ static result_t collectConfigFiles(const string path, const string prefix, const
DataFieldTemplates* getTemplates(const string filename) { DataFieldTemplates* getTemplates(const string filename) {
string path; string path;
size_t pos = filename.find_last_of('/'); size_t pos = filename.find_last_of('/');
if (pos!=string::npos) { if (pos != string::npos) {
path = filename.substr(0, pos); path = filename.substr(0, pos);
} }
map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.find(path); map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.find(path);
if (it!=s_templatesByPath.end()) { if (it != s_templatesByPath.end()) {
return it->second; return it->second;
} }
return &s_globalTemplates; return &s_globalTemplates;
@@ -666,13 +664,13 @@ DataFieldTemplates* getTemplates(const string filename) {
* @return false when the templates for the path were already loaded before, true when the templates for the path were added (independent from @a available). * @return false when the templates for the path were already loaded before, true when the templates for the path were added (independent from @a available).
* @return the @a DataFieldTemplates. * @return the @a DataFieldTemplates.
*/ */
static bool readTemplates(const string path, const string extension, bool available, bool verbose=false) { static bool readTemplates(const string path, const string extension, bool available, bool verbose = false) {
map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.find(path); map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.find(path);
if (it!=s_templatesByPath.end()) { if (it != s_templatesByPath.end()) {
return false; return false;
} }
DataFieldTemplates* templates; DataFieldTemplates* templates;
if (path==opt.configPath || !available) { if (path == opt.configPath || !available) {
templates = &s_globalTemplates; templates = &s_globalTemplates;
} else { } else {
templates = new DataFieldTemplates(s_globalTemplates); templates = new DataFieldTemplates(s_globalTemplates);
@@ -700,40 +698,40 @@ static bool readTemplates(const string path, const string extension, bool availa
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @return the result code. * @return the result code.
*/ */
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose) static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose) {
{
vector<string> files, dirs; vector<string> files, dirs;
bool hasTemplates = false; bool hasTemplates = false;
result_t result = collectConfigFiles(path, "", extension, files, &dirs, &hasTemplates); result_t result = collectConfigFiles(path, "", extension, files, &dirs, &hasTemplates);
if (result!=RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
readTemplates(path, extension, hasTemplates, verbose); readTemplates(path, extension, hasTemplates, verbose);
for (vector<string>::iterator it = files.begin(); it != files.end(); it++) { for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
string name = *it; string name = *it;
logInfo(lf_main, "reading file %s", name.c_str()); logInfo(lf_main, "reading file %s", name.c_str());
result_t result = messages->readFromFile(name, verbose); result_t result = messages->readFromFile(name, verbose);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
} }
if (recursive) { if (recursive) {
for (vector<string>::iterator it = dirs.begin(); it != dirs.end(); it++) { for (vector<string>::iterator it = dirs.begin(); it != dirs.end(); it++) {
string name = *it; string name = *it;
logInfo(lf_main, "reading dir %s", name.c_str()); logInfo(lf_main, "reading dir %s", name.c_str());
result_t result = readConfigFiles(name, extension, messages, true, verbose); result_t result = readConfigFiles(name, extension, messages, true, verbose);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
} }
} }
return RESULT_OK; return RESULT_OK;
}; }
/** /**
* Helper method for immediate reading of a @a Message from the bus. * Helper method for immediate reading of a @a Message from the bus.
* @param message the @a Message to read. * @param message the @a Message to read.
*/ */
void readMessage(Message* message) void readMessage(Message* message) {
{
if (!s_mainLoop || !message) { if (!s_mainLoop || !message) {
return; return;
} }
@@ -749,8 +747,7 @@ void readMessage(Message* message)
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
* @param verbose whether to verbosely log all problems. * @param verbose whether to verbosely log all problems.
*/ */
void executeInstructions(MessageMap* messages, bool verbose) void executeInstructions(MessageMap* messages, bool verbose) {
{
result_t result = messages->resolveConditions(verbose); result_t result = messages->resolveConditions(verbose);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), messages->getLastError().c_str()); logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), messages->getLastError().c_str());
@@ -765,13 +762,12 @@ void executeInstructions(MessageMap* messages, bool verbose)
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive()); logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
} }
result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) {
{
logInfo(lf_main, "loading configuration files from %s", opt.configPath); logInfo(lf_main, "loading configuration files from %s", opt.configPath);
messages->clear(); messages->clear();
s_globalTemplates.clear(); s_globalTemplates.clear();
for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) { for (map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.begin(); it != s_templatesByPath.end(); it++) {
if (it->second!=&s_globalTemplates) { if (it->second != &s_globalTemplates) {
delete it->second; delete it->second;
} }
it->second = NULL; it->second = NULL;
@@ -788,19 +784,18 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
return RESULT_OK; return RESULT_OK;
} }
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose) result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose) {
{
PartType partType; PartType partType;
if (isMaster(address)) { if (isMaster(address)) {
address = (unsigned char)(data[0]+5); // slave address of sending master address = (unsigned char)(data[0]+5); // slave address of sending master
partType = pt_masterData; partType = pt_masterData;
if (data.size()<5+1+5+2+2) { // skip QQ ZZ PB SB NN if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
logError(lf_main, "unable to load scan config %2.2x: master part too short", address); logError(lf_main, "unable to load scan config %2.2x: master part too short", address);
return RESULT_EMPTY; return RESULT_EMPTY;
} }
} else { } else {
partType = pt_slaveData; partType = pt_slaveData;
if (data.size()<1+1+5+2+2) { // skip NN if (data.size() < 1+1+5+2+2) { // skip NN
logError(lf_main, "unable to load scan config %2.2x: slave part too short", address); logError(lf_main, "unable to load scan config %2.2x: slave part too short", address);
return RESULT_EMPTY; return RESULT_EMPTY;
} }
@@ -812,9 +807,10 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
unsigned char offset = 0; unsigned char offset = 0;
size_t field = 0; size_t field = 0;
result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
if (result==RESULT_ERR_NOTFOUND) if (result == RESULT_ERR_NOTFOUND) {
result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
if (result==RESULT_OK) { }
if (result == RESULT_OK) {
path = out.str(); path = out.str();
transform(path.begin(), path.end(), path.begin(), ::tolower); transform(path.begin(), path.end(), path.begin(), ::tolower);
path = string(opt.configPath) + "/" + path; path = string(opt.configPath) + "/" + path;
@@ -826,17 +822,17 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType)); offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
} }
if (result==RESULT_OK) { if (result == RESULT_OK) {
ident = out.str(); ident = out.str();
out.str(""); out.str("");
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType)); offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
} }
if (result==RESULT_OK) { if (result == RESULT_OK) {
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType)); offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
} }
if (result!=RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result)); logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result));
return result; return result;
} }
@@ -844,7 +840,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
bool hasTemplates = false; bool hasTemplates = false;
// find files matching MANUFACTURER/ZZ.*csv in cfgpath // find files matching MANUFACTURER/ZZ.*csv in cfgpath
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates); result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), getResultCode(result)); logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), getResultCode(result));
return result; return result;
} }
@@ -853,7 +849,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result)); logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
for (string::iterator it = ident.begin(); it!=ident.end(); it++) { for (string::iterator it = ident.begin(); it != ident.end(); it++) {
if (::isspace(*it)) { if (::isspace(*it)) {
ident.erase(it--); ident.erase(it--);
} else { } else {
@@ -863,7 +859,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
// complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.circuit][.suffix][.*][.SWxxxx][.HWxxxx][.*].csv // complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.circuit][.suffix][.*][.SWxxxx][.HWxxxx][.*].csv
size_t bestMatch = 0; size_t bestMatch = 0;
string best; string best;
for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) { for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
string name = *it; string name = *it;
unsigned char checkDest; unsigned char checkDest;
string checkIdent, useCircuit, useSuffix; string checkIdent, useCircuit, useSuffix;
@@ -871,20 +867,21 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) { if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
continue; continue;
} }
if (address!=checkDest || (checkSw!=UINT_MAX && sw!=checkSw) || (checkHw!=UINT_MAX && hw!=checkHw)) { if (address != checkDest || (checkSw != UINT_MAX && sw != checkSw) || (checkHw != UINT_MAX && hw != checkHw)) {
continue; continue;
} }
size_t match = 1; size_t match = 1;
if (!checkIdent.empty()) { if (!checkIdent.empty()) {
string remain = ident; string remain = ident;
bool matches = false; bool matches = false;
while (remain.length()>0 && remain.length()>=checkIdent.length()) { while (remain.length() > 0 && remain.length() >= checkIdent.length()) {
if (checkIdent==remain) { if (checkIdent == remain) {
matches = true; matches = true;
break; break;
} }
if (remain[remain.length()-1]<'0' || remain[remain.length()-1]>'9') if (remain[remain.length()-1] < '0' || remain[remain.length()-1] > '9') {
break; break;
}
remain.erase(remain.length()-1); // remove trailing digit remain.erase(remain.length()-1); // remove trailing digit
} }
if (!matches) { if (!matches) {
@@ -892,7 +889,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
} }
match += remain.length(); match += remain.length();
} }
if (match>=bestMatch) { if (match >= bestMatch) {
bestMatch = match; bestMatch = match;
best = name; best = name;
} }
@@ -908,25 +905,27 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
bool readCommon = readTemplates(path, ".csv", hasTemplates, opt.checkConfig); bool readCommon = readTemplates(path, ".csv", hasTemplates, opt.checkConfig);
if (readCommon) { if (readCommon) {
result = collectConfigFiles(path, "", ".csv", files); result = collectConfigFiles(path, "", ".csv", files);
if (result==RESULT_OK && !files.empty()) { if (result == RESULT_OK && !files.empty()) {
for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) { for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
string name = *it; string name = *it;
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *. name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
if (name=="_templates.") // skip templates if (name == "_templates.") { // skip templates
continue; continue;
if (name.length()<3 || name.find_first_of('.')!=2) { // different from the scheme "ZZ." }
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
name = *it; name = *it;
result = messages->readFromFile(name, opt.checkConfig); result = messages->readFromFile(name, opt.checkConfig);
if (result==RESULT_OK) if (result == RESULT_OK) {
logNotice(lf_main, "read common config file %s", name.c_str()); logNotice(lf_main, "read common config file %s", name.c_str());
else } else {
logError(lf_main, "error reading common config file %s: %s", name.c_str(), getResultCode(result)); logError(lf_main, "error reading common config file %s: %s", name.c_str(), getResultCode(result));
}
} }
} }
} }
} }
result = messages->readFromFile(best, opt.checkConfig, "", ident); result = messages->readFromFile(best, opt.checkConfig, "", ident);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), ident.c_str(), sw, hw, getResultCode(result)); logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), ident.c_str(), sw, hw, getResultCode(result));
return result; return result;
} }
@@ -943,8 +942,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
* @param argc the number of command line arguments. * @param argc the number of command line arguments.
* @param argv the command line arguments. * @param argv the command line arguments.
*/ */
int main(int argc, char* argv[]) int main(int argc, char* argv[]) {
{
struct argp aargp = { argpoptions, parse_opt, NULL, argpdoc, datahandler_getargs(), NULL, NULL }; struct argp aargp = { argpoptions, parse_opt, NULL, argpdoc, datahandler_getargs(), NULL, NULL };
int arg_index = -1; int arg_index = -1;
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0); setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
@@ -963,20 +961,20 @@ int main(int argc, char* argv[])
// check scan config for each passed ident message // check scan config for each passed ident message
string arg = argv[arg_index++]; string arg = argv[arg_index++];
size_t pos = arg.find_first_of('/'); size_t pos = arg.find_first_of('/');
if (pos==string::npos) { if (pos == string::npos) {
logError(lf_main, "invalid scan message %s: missing \"/\"", arg.c_str()); logError(lf_main, "invalid scan message %s: missing \"/\"", arg.c_str());
continue; continue;
} }
SymbolString master(false), slave(false); SymbolString master(false), slave(false);
result_t res = master.parseHex(arg.substr(0, pos)); result_t res = master.parseHex(arg.substr(0, pos));
if (res==RESULT_OK) { if (res == RESULT_OK) {
res = slave.parseHex(arg.substr(pos+1)); res = slave.parseHex(arg.substr(pos+1));
} }
if (res!=RESULT_OK) { if (res != RESULT_OK) {
logError(lf_main, "invalid scan message %s: %s", arg.c_str(), getResultCode(res)); logError(lf_main, "invalid scan message %s: %s", arg.c_str(), getResultCode(res));
continue; continue;
} }
if (master.size()<5) { // skip QQ ZZ PB SB NN if (master.size() < 5) { // skip QQ ZZ PB SB NN
logError(lf_main, "invalid scan message %s: master part too short", arg.c_str()); logError(lf_main, "invalid scan message %s: master part too short", arg.c_str());
continue; continue;
} }
@@ -988,7 +986,7 @@ int main(int argc, char* argv[])
message->storeLastData(master, slave); message->storeLastData(master, slave);
string file; string file;
res = loadScanConfigFile(s_messageMap, address, slave, file, true); res = loadScanConfigFile(s_messageMap, address, slave, file, true);
if (res==RESULT_OK) { if (res == RESULT_OK) {
logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str()); logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str());
} }
} }
@@ -1027,7 +1025,7 @@ int main(int argc, char* argv[])
// load configuration files // load configuration files
loadConfigFiles(s_messageMap); loadConfigFiles(s_messageMap);
if (s_messageMap->sizeConditions()>0 && opt.pollInterval==0) { if (s_messageMap->sizeConditions() > 0 && opt.pollInterval == 0) {
logError(lf_main, "conditions require a poll interval > 0"); logError(lf_main, "conditions require a poll interval > 0");
} }
// wait for end of MainLoop // wait for end of MainLoop
+10 -10
View File
@@ -16,19 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef MAIN_H_ #ifndef EBUSD_MAIN_H_
#define MAIN_H_ #define EBUSD_MAIN_H_
#include "result.h" #include <stdint.h>
#include <string>
#include "data.h" #include "data.h"
#include "message.h" #include "message.h"
#include <stdint.h> #include "result.h"
/** \file main.h */ /** \file main.h */
/** A structure holding all program options. */ /** A structure holding all program options. */
struct options struct options {
{
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0] const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
bool noDeviceCheck; //!< skip serial eBUS device test bool noDeviceCheck; //!< skip serial eBUS device test
bool readOnly; //!< read-only access to the device bool readOnly; //!< read-only access to the device
@@ -38,7 +38,7 @@ struct options
const char* configPath; //!< path to CSV configuration files [/etc/ebusd] const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
bool scanConfig; //!< pick configuration files matching initial scan bool scanConfig; //!< pick configuration files matching initial scan
unsigned char initialScan; //!< the initial address to scan for scanconfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address) 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 checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
int pollInterval; //!< poll interval in seconds, 0 to disable [5] int pollInterval; //!< poll interval in seconds, 0 to disable [5]
unsigned char address; //!< own bus address [31] unsigned char address; //!< own bus address [31]
@@ -83,7 +83,7 @@ DataFieldTemplates* getTemplates(const string filename);
* @param denyRecursive whether to avoid loading all files recursively (e.g. for scan config check). * @param denyRecursive whether to avoid loading all files recursively (e.g. for scan config check).
* @return the result code. * @return the result code.
*/ */
result_t loadConfigFiles(MessageMap* messages, bool verbose=false, bool denyRecursive=false); result_t loadConfigFiles(MessageMap* messages, bool verbose = false, bool denyRecursive = false);
/** /**
* Load the message definitions from a configuration file matching the scan result. * Load the message definitions from a configuration file matching the scan result.
@@ -94,6 +94,6 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose=false, bool denyRecu
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @return the result code. * @return the result code.
*/ */
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose=false); result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose = false);
#endif // MAIN_H_ #endif // EBUSD_MAIN_H_
+244 -208
View File
File diff suppressed because it is too large Load Diff
+12 -15
View File
@@ -16,17 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef MAINLOOP_H_ #ifndef EBUSD_MAINLOOP_H_
#define MAINLOOP_H_ #define EBUSD_MAINLOOP_H_
#include "message.h" #include <string>
#include "network.h" #include <list>
#include <vector>
#include "bushandler.h" #include "bushandler.h"
#include "datahandler.h" #include "datahandler.h"
#include "network.h"
#include "message.h"
#include "rotatefile.h" #include "rotatefile.h"
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
/** \file mainloop.h */ /** \file mainloop.h */
@@ -35,10 +35,8 @@ using namespace std;
/** /**
* The main loop handling requests from connected clients. * The main loop handling requests from connected clients.
*/ */
class MainLoop : public Thread, DeviceListener class MainLoop : public Thread, DeviceListener {
{ public:
public:
/** /**
* Construct the main loop and create network and bus handling components. * Construct the main loop and create network and bus handling components.
* @param opt the program options. * @param opt the program options.
@@ -67,13 +65,13 @@ public:
// @copydoc // @copydoc
virtual void notifyDeviceData(const unsigned char byte, bool received); virtual void notifyDeviceData(const unsigned char byte, bool received);
protected:
protected:
// @copydoc // @copydoc
virtual void run(); virtual void run();
private:
private:
/** /**
* Decode and execute client message. * Decode and execute client message.
* @param data the data string to decode (may be empty). * @param data the data string to decode (may be empty).
@@ -252,7 +250,6 @@ private:
/** the registered @a DataHandler instances. */ /** the registered @a DataHandler instances. */
list<DataHandler*> m_dataHandlers; list<DataHandler*> m_dataHandlers;
}; };
#endif // MAINLOOP_H_ #endif // EBUSD_MAINLOOP_H_
+56 -68
View File
@@ -16,12 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mqtthandler.h"
#include "log.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
#include "mqtthandler.h"
#include "log.h"
using namespace std; using namespace std;
/** the definition of the MQTT arguments. */ /** the definition of the MQTT arguments. */
@@ -43,8 +44,7 @@ static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without
* @param arg the option argument, or NULL. * @param arg the option argument, or NULL.
* @param state the parsing state. * @param state the parsing state.
*/ */
static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
{
result_t result = RESULT_OK; result_t result = RESULT_OK;
switch (key) { switch (key) {
@@ -57,7 +57,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state)
break; break;
case 2: // --mqtttopic=ebusd case 2: // --mqtttopic=ebusd
if (arg == NULL || arg[0] == 0 || arg[0]=='/' || arg[strlen(arg)-1]=='/') { if (arg == NULL || arg[0] == 0 || arg[0] == '/' || arg[strlen(arg)-1] == '/') {
argp_error(state, "invalid mqtttopic"); argp_error(state, "invalid mqtttopic");
return EINVAL; return EINVAL;
} }
@@ -72,13 +72,11 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state)
static const struct argp g_mqtt_argp = { g_mqtt_argp_options, mqtt_parse_opt, NULL, NULL, NULL, NULL, NULL }; static const struct argp g_mqtt_argp = { g_mqtt_argp_options, mqtt_parse_opt, NULL, NULL, NULL, NULL, NULL };
static const struct argp_child g_mqtt_argp_child = {&g_mqtt_argp, 0, "", 1}; static const struct argp_child g_mqtt_argp_child = {&g_mqtt_argp, 0, "", 1};
const struct argp_child* mqtthandler_getargs() const struct argp_child* mqtthandler_getargs() {
{
return &g_mqtt_argp_child; return &g_mqtt_argp_child;
} }
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) {
{
return new MqttHandler(busHandler, messages); return new MqttHandler(busHandler, messages);
} }
@@ -111,21 +109,21 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
size_t lastpos = 0; size_t lastpos = 0;
size_t end = topic.length(); size_t end = topic.length();
vector<string> columns; vector<string> columns;
for (size_t pos=topic.find('%', lastpos); pos!=string::npos; ) { for (size_t pos=topic.find('%', lastpos); pos != string::npos; ) {
size_t col = columnCount; size_t col = columnCount;
size_t len = 0; size_t len = 0;
for (size_t i = 0; i < columnCount; i++) { for (size_t i = 0; i < columnCount; i++) {
len = strlen(columnNames[i]); len = strlen(columnNames[i]);
if (topic.substr(pos+1, len)==columnNames[i]) { if (topic.substr(pos+1, len) == columnNames[i]) {
col = columnIds[i]; col = columnIds[i];
break; break;
} }
} }
if (col==columnCount) { if (col == columnCount) {
return false; return false;
} }
for (vector<size_t>::iterator it=cols.begin(); it!=cols.end(); it++) { for (vector<size_t>::iterator it=cols.begin(); it != cols.end(); it++) {
if (*it==col) { if (*it == col) {
return false; // duplicate column return false; // duplicate column
} }
} }
@@ -134,7 +132,7 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
lastpos = pos+1+len; lastpos = pos+1+len;
pos = topic.find('%', lastpos); pos = topic.find('%', lastpos);
} }
if (lastpos<end) { if (lastpos < end) {
strs.push_back(topic.substr(lastpos, end-lastpos)); strs.push_back(topic.substr(lastpos, end-lastpos));
} }
return true; return true;
@@ -142,9 +140,8 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages) MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
: DataSink(), DataSource(busHandler), Thread(), m_messages(messages) : DataSink(), DataSource(busHandler), Thread(), m_messages(messages) {
{ bool enabled = g_port != 0;
bool enabled = g_port!=0;
m_publishByField = false; m_publishByField = false;
m_mosquitto = NULL; m_mosquitto = NULL;
if (enabled && !parseTopic(g_topic, m_topicStrs, m_topicCols)) { if (enabled && !parseTopic(g_topic, m_topicStrs, m_topicCols)) {
@@ -156,7 +153,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
} }
int major = -1; int major = -1;
mosquitto_lib_version(&major, NULL, NULL); mosquitto_lib_version(&major, NULL, NULL);
if (major!=LIBMOSQUITTO_MAJOR) { if (major != LIBMOSQUITTO_MAJOR) {
logOtherError("mqtt", "invalid mosquitto version %d instead of %d", major, LIBMOSQUITTO_MAJOR); logOtherError("mqtt", "invalid mosquitto version %d instead of %d", major, LIBMOSQUITTO_MAJOR);
return; return;
} }
@@ -165,7 +162,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
m_topicStrs.push_back(""); m_topicStrs.push_back("");
} else { } else {
string str = m_topicStrs[0]; string str = m_topicStrs[0];
if (str.empty() || str[str.length()-1]!='/') { if (str.empty() || str[str.length()-1] != '/') {
m_topicStrs[0] = str+"/"; m_topicStrs[0] = str+"/";
} }
} }
@@ -173,8 +170,8 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
m_topicStrs.push_back("/"); m_topicStrs.push_back("/");
m_topicCols.push_back(COLUMN_NAME); // name m_topicCols.push_back(COLUMN_NAME); // name
} else { } else {
for (size_t i=0; i<m_topicCols.size(); i++) { for (size_t i = 0; i < m_topicCols.size(); i++) {
if (m_topicCols[i]==COLUMN_FIELDS) { // fields if (m_topicCols[i] == COLUMN_FIELDS) { // fields
m_publishByField = true; m_publishByField = true;
break; break;
} }
@@ -182,13 +179,13 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
} }
m_globalTopic = getTopic(NULL)+"global/"; m_globalTopic = getTopic(NULL)+"global/";
m_mosquitto = NULL; m_mosquitto = NULL;
if (mosquitto_lib_init()!=MOSQ_ERR_SUCCESS) { if (mosquitto_lib_init() != MOSQ_ERR_SUCCESS) {
logOtherError("mqtt", "unable to initialize"); logOtherError("mqtt", "unable to initialize");
} else { } else {
string clientId = PACKAGE_STRING; string clientId = PACKAGE_STRING;
clientId += " "+static_cast<unsigned>(getpid()); clientId += " "+static_cast<unsigned>(getpid());
m_mosquitto = mosquitto_new(clientId.c_str(), m_mosquitto = mosquitto_new(clientId.c_str(),
#if (LIBMOSQUITTO_MAJOR>=1) #if (LIBMOSQUITTO_MAJOR >= 1)
true, true,
#endif #endif
this); this);
@@ -203,15 +200,15 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
string willData = "false"; string willData = "false";
size_t len = willData.length(); size_t len = willData.length();
mosquitto_will_set(m_mosquitto, mosquitto_will_set(m_mosquitto,
#if (LIBMOSQUITTO_MAJOR<1) #if (LIBMOSQUITTO_MAJOR < 1)
true, true,
#endif #endif
willTopic.c_str(), (uint32_t)len, (uint8_t*)(willData.c_str()), 0, true); willTopic.c_str(), (uint32_t)len, (uint8_t*)(willData.c_str()), 0, true);
if (mosquitto_connect(m_mosquitto, "localhost", g_port, 60 if (mosquitto_connect(m_mosquitto, "localhost", g_port, 60
#if (LIBMOSQUITTO_MAJOR<1) #if (LIBMOSQUITTO_MAJOR < 1)
, true , true
#endif #endif
)!=MOSQ_ERR_SUCCESS) { ) != MOSQ_ERR_SUCCESS) {
logOtherError("mqtt", "unable to connect"); logOtherError("mqtt", "unable to connect");
mosquitto_destroy(m_mosquitto); mosquitto_destroy(m_mosquitto);
m_mosquitto = NULL; m_mosquitto = NULL;
@@ -221,8 +218,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
} }
} }
MqttHandler::~MqttHandler() MqttHandler::~MqttHandler() {
{
join(); join();
if (m_mosquitto) { if (m_mosquitto) {
mosquitto_destroy(m_mosquitto); mosquitto_destroy(m_mosquitto);
@@ -231,32 +227,29 @@ MqttHandler::~MqttHandler()
mosquitto_lib_cleanup(); mosquitto_lib_cleanup();
} }
void MqttHandler::start() void MqttHandler::start() {
{
if (m_mosquitto) { if (m_mosquitto) {
Thread::start("MQTT"); Thread::start("MQTT");
} }
} }
void on_message( void on_message(
#if (LIBMOSQUITTO_MAJOR>=1) #if (LIBMOSQUITTO_MAJOR >= 1)
struct mosquitto *mosq, struct mosquitto *mosq,
#endif #endif
void *obj, const struct mosquitto_message *message) void *obj, const struct mosquitto_message *message) {
{
MqttHandler* handler = (MqttHandler*)obj; MqttHandler* handler = (MqttHandler*)obj;
if (!handler || !message || !handler->isRunning()) { if (!handler || !message || !handler->isRunning()) {
return; return;
} }
string topic(message->topic); string topic(message->topic);
string data(message->payloadlen>0 ? (char*)message->payload : ""); string data(message->payloadlen > 0 ? (char*)message->payload : "");
handler->notifyTopic(topic, data); handler->notifyTopic(topic, data);
} }
void MqttHandler::notifyTopic(string topic, string data) void MqttHandler::notifyTopic(string topic, string data) {
{
size_t pos = topic.rfind('/'); size_t pos = topic.rfind('/');
if (pos==string::npos) { if (pos == string::npos) {
return; return;
} }
string suffix = topic.substr(pos+1); string suffix = topic.substr(pos+1);
@@ -265,8 +258,8 @@ void MqttHandler::notifyTopic(string topic, string data)
return; return;
} }
string direction = suffix.substr(0, 3); string direction = suffix.substr(0, 3);
isWrite = direction=="set"; isWrite = direction == "set";
if (!isWrite && direction!="get") { if (!isWrite && direction != "get") {
return; return;
} }
suffix = suffix.substr(3); // security level suffix = suffix.substr(3); // security level
@@ -275,26 +268,26 @@ void MqttHandler::notifyTopic(string topic, string data)
size_t last = 0; size_t last = 0;
string circuit, name; string circuit, name;
size_t idx; size_t idx;
for (idx=0; idx<m_topicStrs.size()+1; idx++) { for (idx = 0; idx < m_topicStrs.size()+1; idx++) {
string field; string field;
string chk; string chk;
if (idx<m_topicStrs.size()) { if (idx < m_topicStrs.size()) {
chk = m_topicStrs[idx]; chk = m_topicStrs[idx];
pos = remain.find(chk, last); pos = remain.find(chk, last);
if (pos==string::npos) { if (pos == string::npos) {
return; return;
} }
} else if (idx-1<m_topicCols.size()) { } else if (idx-1 < m_topicCols.size()) {
pos = remain.size(); pos = remain.size();
} else if (last<remain.size()) { } else if (last < remain.size()) {
return; return;
} else { } else {
break; break;
} }
field = remain.substr(last, pos-last); field = remain.substr(last, pos-last);
last = pos+chk.size(); last = pos+chk.size();
if (idx==0) { if (idx == 0) {
if (pos>0) { if (pos > 0) {
return; return;
} }
} else { } else {
@@ -320,20 +313,20 @@ void MqttHandler::notifyTopic(string topic, string data)
return; return;
} }
logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str()); logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str());
if (suffix.length()>0) { if (suffix.length() > 0) {
circuit += "#"+suffix; circuit += "#"+suffix;
} }
Message* message = m_messages->find(circuit, name, isWrite); Message* message = m_messages->find(circuit, name, isWrite);
if (message==NULL) { if (message == NULL) {
message = m_messages->find(circuit, name, isWrite, true); message = m_messages->find(circuit, name, isWrite, true);
} }
if (message==NULL) { if (message == NULL) {
logOtherError("mqtt", "%s message %s %s not found", isWrite?"write":"read", circuit.c_str(), name.c_str()); logOtherError("mqtt", "%s message %s %s not found", isWrite?"write":"read", circuit.c_str(), name.c_str());
return; return;
} }
if (!message->isPassive()) { if (!message->isPassive()) {
result_t result = m_busHandler->readFromBus(message, data); result_t result = m_busHandler->readFromBus(message, data);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), getResultCode(result)); logOtherError("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), getResultCode(result));
return; return;
} }
@@ -343,8 +336,7 @@ void MqttHandler::notifyTopic(string topic, string data)
publishMessage(message, ostream); publishMessage(message, ostream);
} }
void MqttHandler::run() void MqttHandler::run() {
{
time_t lastTaskRun, now, start, lastSignal = 0; time_t lastTaskRun, now, start, lastSignal = 0;
bool signal = false; bool signal = false;
string signalTopic = m_globalTopic+"signal"; string signalTopic = m_globalTopic+"signal";
@@ -362,9 +354,9 @@ void MqttHandler::run()
while (isRunning()) { while (isRunning()) {
handleTraffic(); handleTraffic();
time(&now); time(&now);
if (now<start) { if (now < start) {
// clock skew // clock skew
if (now<lastSignal) { if (now < lastSignal) {
lastSignal -= lastTaskRun-now; lastSignal -= lastTaskRun-now;
} }
lastTaskRun = now; lastTaskRun = now;
@@ -401,27 +393,25 @@ void MqttHandler::run()
} }
} }
void MqttHandler::handleTraffic() void MqttHandler::handleTraffic() {
{
if (m_mosquitto) { if (m_mosquitto) {
mosquitto_loop(m_mosquitto, -1 mosquitto_loop(m_mosquitto, -1
#if (LIBMOSQUITTO_MAJOR>=1) #if (LIBMOSQUITTO_MAJOR >= 1)
,1 ,1
#endif #endif
); );
} }
} }
string MqttHandler::getTopic(Message* message, signed char fieldIndex) string MqttHandler::getTopic(Message* message, signed char fieldIndex) {
{
ostringstream ret; ostringstream ret;
for (size_t i=0; i<m_topicStrs.size(); i++) { for (size_t i = 0; i < m_topicStrs.size(); i++) {
ret << m_topicStrs[i]; ret << m_topicStrs[i];
if (!message) { if (!message) {
break; break;
} }
if (i<m_topicCols.size()) { if (i < m_topicCols.size()) {
if (m_topicCols[i]==COLUMN_FIELDS && fieldIndex>=0) { if (m_topicCols[i] == COLUMN_FIELDS && fieldIndex >= 0) {
ret << message->getFieldName(fieldIndex); ret << message->getFieldName(fieldIndex);
} else { } else {
message->dumpColumn(ret, m_topicCols[i]); message->dumpColumn(ret, m_topicCols[i]);
@@ -431,10 +421,9 @@ string MqttHandler::getTopic(Message* message, signed char fieldIndex)
return ret.str(); return ret.str();
} }
void MqttHandler::publishMessage(Message* message, ostringstream& updates) void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
{
result_t result = message->decodeLastData(updates); result_t result = message->decodeLastData(updates);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result)); logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result));
return; return;
} }
@@ -452,8 +441,7 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates)
} }
} }
void MqttHandler::publishTopic(string topic, string data, bool retain) void MqttHandler::publishTopic(string topic, string data, bool retain) {
{
logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str()); logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str());
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), (uint8_t*)(data.c_str()), 0, retain); mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), (uint8_t*)(data.c_str()), 0, retain);
} }
+9 -6
View File
@@ -16,13 +16,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef MQTTHANDLER_H_ #ifndef EBUSD_MQTTHANDLER_H_
#define MQTTHANDLER_H_ #define EBUSD_MQTTHANDLER_H_
#include <mosquitto.h>
#include <string>
#include <vector>
#include <map>
#include "datahandler.h" #include "datahandler.h"
#include "bushandler.h" #include "bushandler.h"
#include "message.h" #include "message.h"
#include <mosquitto.h>
/** @file mqtthandler.h /** @file mqtthandler.h
* A data handler enabling MQTT support via mosquitto. * A data handler enabling MQTT support via mosquitto.
@@ -91,7 +94,7 @@ private:
* @param fieldIndex the optional field index for the field column, or -1. * @param fieldIndex the optional field index for the field column, or -1.
* @return the topic string. * @return the topic string.
*/ */
string getTopic(Message* message, signed char fieldIndex=-1); string getTopic(Message* message, signed char fieldIndex = -1);
/** /**
* Prepare a @a Message and publish as topic. * Prepare a @a Message and publish as topic.
@@ -106,7 +109,7 @@ private:
* @param data the data string. * @param data the data string.
* @param retain whether the topic shall be retained. * @param retain whether the topic shall be retained.
*/ */
void publishTopic(string topic, string data, bool retain=true); void publishTopic(string topic, string data, bool retain = true);
/** the @a MessageMap instance. */ /** the @a MessageMap instance. */
MessageMap* m_messages; MessageMap* m_messages;
@@ -128,4 +131,4 @@ private:
}; };
#endif // DATAHANDLER_H_ #endif // EBUSD_DATAHANDLER_H_
+9 -15
View File
@@ -21,19 +21,17 @@
#endif #endif
#include "network.h" #include "network.h"
#include "log.h"
#include <cstring>
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
# include <poll.h> # include <poll.h>
#endif #endif
#include <cstring>
#include "log.h"
using namespace std; using namespace std;
int Connection::m_ids = 0; int Connection::m_ids = 0;
void Connection::run() void Connection::run() {
{
int ret; int ret;
struct timespec tdiff; struct timespec tdiff;
@@ -153,14 +151,13 @@ void Connection::run()
Network::Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<NetMessage*>* netQueue) Network::Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<NetMessage*>* netQueue)
: Thread(), m_netQueue(netQueue), m_listening(false) : Thread(), m_netQueue(netQueue), m_listening(false) {
{
m_tcpServer = new TCPServer(port, local ? "127.0.0.1" : "0.0.0.0"); m_tcpServer = new TCPServer(port, local ? "127.0.0.1" : "0.0.0.0");
if (m_tcpServer != NULL && m_tcpServer->start() == 0) { if (m_tcpServer != NULL && m_tcpServer->start() == 0) {
m_listening = true; m_listening = true;
} }
if (httpPort>0) { if (httpPort > 0) {
m_httpServer = new TCPServer(httpPort, "0.0.0.0"); m_httpServer = new TCPServer(httpPort, "0.0.0.0");
m_httpServer->start(); m_httpServer->start();
} else { } else {
@@ -168,8 +165,7 @@ Network::Network(const bool local, const uint16_t port, const uint16_t httpPort,
} }
} }
Network::~Network() Network::~Network() {
{
stop(); stop();
while (!m_connections.empty()) { while (!m_connections.empty()) {
Connection* connection = m_connections.back(); Connection* connection = m_connections.back();
@@ -188,8 +184,7 @@ Network::~Network()
join(); join();
} }
void Network::run() void Network::run() {
{
if (!m_listening) { if (!m_listening) {
return; return;
} }
@@ -230,7 +225,7 @@ void Network::run()
maxfd = (m_notify.notifyFD() > m_tcpServer->getFD()) ? maxfd = (m_notify.notifyFD() > m_tcpServer->getFD()) ?
m_notify.notifyFD() : m_tcpServer->getFD(); m_notify.notifyFD() : m_tcpServer->getFD();
if (m_httpServer && m_httpServer->getFD()>maxfd) { if (m_httpServer && m_httpServer->getFD() > maxfd) {
maxfd = m_httpServer->getFD(); maxfd = m_httpServer->getFD();
} }
#endif #endif
@@ -294,8 +289,7 @@ void Network::run()
} }
} }
void Network::cleanConnections() void Network::cleanConnections() {
{
list<Connection*>::iterator c_it; list<Connection*>::iterator c_it;
for (c_it = m_connections.begin(); c_it != m_connections.end(); c_it++) { for (c_it = m_connections.begin(); c_it != m_connections.end(); c_it++) {
if (!(*c_it)->isRunning()) { if (!(*c_it)->isRunning()) {
+17 -15
View File
@@ -16,16 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef NETWORK_H_ #ifndef EBUSD_NETWORK_H_
#define NETWORK_H_ #define EBUSD_NETWORK_H_
#include <string>
#include <cstdio>
#include <algorithm>
#include <list>
#include "tcpsocket.h" #include "tcpsocket.h"
#include "queue.h" #include "queue.h"
#include "notify.h" #include "notify.h"
#include "thread.h" #include "thread.h"
#include <string>
#include <cstdio>
#include <algorithm>
/** \file network.h */ /** \file network.h */
@@ -77,34 +78,35 @@ public:
*/ */
bool add(string request) bool add(string request)
{ {
if (request.length()>0) { if (request.length() > 0) {
request.erase(remove(request.begin(), request.end(), '\r'), request.end()); request.erase(remove(request.begin(), request.end(), '\r'), request.end());
m_request.append(request); m_request.append(request);
} }
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n"); size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
if (pos!=string::npos) { if (pos != string::npos) {
if (m_isHttp) { if (m_isHttp) {
pos = m_request.find("\n"); pos = m_request.find("\n");
m_request.resize(pos); // reduce to first line m_request.resize(pos); // reduce to first line
// typical first line: GET /ehp/outsidetemp HTTP/1.1 // typical first line: GET /ehp/outsidetemp HTTP/1.1
pos = m_request.rfind(" HTTP/"); pos = m_request.rfind(" HTTP/");
if (pos!=string::npos) { if (pos != string::npos) {
m_request.resize(pos); // remove "HTTP/x.x" suffix m_request.resize(pos); // remove "HTTP/x.x" suffix
} }
pos = 0; pos = 0;
while ((pos=m_request.find('%', pos))!=string::npos && pos+2<=m_request.length()) { while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
unsigned int value1, value2; unsigned int value1, value2;
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2)<2) if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2) < 2) {
break; break;
m_request[pos] = (char)(((value1&0x0f)<<4)|(value2&0x0f)); }
m_request[pos] = (char)(((value1&0x0f)<<4) | (value2&0x0f));
m_request.erase(pos+1, 2); m_request.erase(pos+1, 2);
} }
} else if (pos+1==m_request.length()) { } else if (pos+1 == m_request.length()) {
m_request.resize(pos); // reduce to complete lines m_request.resize(pos); // reduce to complete lines
} }
return true; return true;
} }
return m_request.length()==0 && m_listening; return m_request.length() == 0 && m_listening;
} }
/** /**
@@ -163,7 +165,7 @@ public:
* @param listenSince set to the start time from which to add updates (inclusive). * @param listenSince set to the start time from which to add updates (inclusive).
* @return whether the client is in listening mode. * @return whether the client is in listening mode.
*/ */
bool isListening(time_t* listenSince=NULL) { if (listenSince) *listenSince = m_listenSince; return m_listening; } bool isListening(time_t* listenSince=NULL) { if (listenSince) { *listenSince = m_listenSince; } return m_listening; }
/** /**
* Return whether the client shall be disconnected. * Return whether the client shall be disconnected.
@@ -313,5 +315,5 @@ private:
}; };
#endif // NETWORK_H_ #endif // EBUSD_NETWORK_H_
+1
View File
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "contrib.h"
#include "tem.h" #include "tem.h"
using namespace std; using namespace std;
+3 -3
View File
@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_CONTRIB_H_ #ifndef LIB_EBUS_CONTRIB_H_
#define LIBEBUS_CONTRIB_H_ #define LIB_EBUS_CONTRIB_H_
/** @file contrib.h /** @file contrib.h
* Contributed sources that may be excluded from regular builds. * Contributed sources that may be excluded from regular builds.
@@ -32,4 +32,4 @@ using namespace std;
*/ */
bool libebus_contrib_register(); bool libebus_contrib_register();
#endif // LIBEBUS_CONTRIB_H_ #endif // LIB_EBUS_CONTRIB_H_
+5 -8
View File
@@ -20,14 +20,14 @@
# include <config.h> # include <config.h>
#endif #endif
#include "datatype.h"
#include "tem.h" #include "tem.h"
#include <math.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <math.h> #include "datatype.h"
using namespace std; using namespace std;
@@ -35,8 +35,7 @@ void contrib_tem_register() {
DataTypeList::getInstance()->add(new TemParamDataType("TEM_P")); DataTypeList::getInstance()->add(new TemParamDataType("TEM_P"));
} }
result_t TemParamDataType::derive(int divisor, unsigned char bitCount, NumberDataType* &derived) result_t TemParamDataType::derive(int divisor, unsigned char bitCount, NumberDataType* &derived) {
{
if (divisor == 0) { if (divisor == 0) {
divisor = 1; divisor = 1;
} }
@@ -52,8 +51,7 @@ result_t TemParamDataType::derive(int divisor, unsigned char bitCount, NumberDat
result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster, result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset, const unsigned char length, const unsigned char offset, const unsigned char length,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
unsigned int value = 0; unsigned int value = 0;
result_t result = readRawValue(input, offset, length, value); result_t result = readRawValue(input, offset, length, value);
@@ -90,8 +88,7 @@ result_t TemParamDataType::readSymbols(SymbolString& input, const bool isMaster,
result_t TemParamDataType::writeSymbols(istringstream& input, result_t TemParamDataType::writeSymbols(istringstream& input,
const unsigned char offset, const unsigned char length, const unsigned char offset, const unsigned char length,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
unsigned int value; unsigned int value;
int grp, num; int grp, num;
string token; string token;
+6 -6
View File
@@ -16,12 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_CONTRIB_TEM_H_ #ifndef LIB_EBUS_CONTRIB_TEM_H_
#define LIBEBUS_CONTRIB_TEM_H_ #define LIB_EBUS_CONTRIB_TEM_H_
#include "symbol.h"
#include "result.h"
#include "datatype.h"
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -29,6 +26,9 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <map> #include <map>
#include "symbol.h"
#include "result.h"
#include "datatype.h"
/** @file tem.h /** @file tem.h
* Contributed data types for TEM devices not part of regular releases. * Contributed data types for TEM devices not part of regular releases.
@@ -71,4 +71,4 @@ public:
*/ */
void contrib_tem_register(); void contrib_tem_register();
#endif // LIBEBUS_CONTRIB_TEM_H_ #endif // LIB_EBUS_CONTRIB_TEM_H_
+13 -15
View File
@@ -16,18 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "tem.h"
#include "data.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <string>
#include <vector>
#include "tem.h"
#include "data.h"
using namespace std; using namespace std;
static bool error = false; static bool error = false;
void verify(bool expectFailMatch, string type, string input, void verify(bool expectFailMatch, string type, string input,
bool match, string expectStr, string gotStr) bool match, string expectStr, string gotStr) {
{
match = match && expectStr == gotStr; match = match && expectStr == gotStr;
if (expectFailMatch) { if (expectFailMatch) {
if (match) { if (match) {
@@ -46,8 +47,7 @@ void verify(bool expectFailMatch, string type, string input,
} }
} }
int main() int main() {
{
DataType* type = DataTypeList::getInstance()->get("TEM_P"); DataType* type = DataTypeList::getInstance()->get("TEM_P");
if (type == NULL) { if (type == NULL) {
cout << "datatype not registered" << endl; cout << "datatype not registered" << endl;
@@ -108,7 +108,7 @@ int main()
fields = NULL; fields = NULL;
} }
vector<string>::iterator it = entries.begin(); vector<string>::iterator it = entries.begin();
result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1]==BROADCAST || isMaster(mstr[1]))); result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1] == BROADCAST || isMaster(mstr[1])));
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl;
error = true; error = true;
@@ -145,7 +145,7 @@ int main()
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->read(pt_slaveData, sstr, 0, output, 0, -1, !output.str().empty()); result = fields->read(pt_slaveData, sstr, 0, output, 0, -1, !output.str().empty());
} }
if (failedRead) if (failedRead) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
@@ -154,20 +154,20 @@ int main()
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< OK" << endl; << "< OK" << endl;
} }
else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} } else {
else {
bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0; bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0;
verify(failedReadMatch, "read", check[2], match, expectStr, output.str()); verify(failedReadMatch, "read", check[2], match, expectStr, output.str());
} }
istringstream input(expectStr); istringstream input(expectStr);
result = fields->write(input, pt_masterData, writeMstr, 0); result = fields->write(input, pt_masterData, writeMstr, 0);
if (result >= RESULT_OK) if (result >= RESULT_OK) {
result = fields->write(input, pt_slaveData, writeSstr, 0); result = fields->write(input, pt_slaveData, writeSstr, 0);
}
if (failedWrite) { if (failedWrite) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName() << " >"
@@ -177,8 +177,7 @@ int main()
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName() << " >"
<< expectStr << "< OK" << endl; << expectStr << "< OK" << endl;
} }
} } else if (result < RESULT_OK) {
else if (result < RESULT_OK) {
cout << " write " << fields->getName() << " >" << expectStr cout << " write " << fields->getName() << " >" << expectStr
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
@@ -191,6 +190,5 @@ int main()
} }
delete templates; delete templates;
return error ? 1 : 0; return error ? 1 : 0;
} }
+189 -199
View File
@@ -21,12 +21,13 @@
#endif #endif
#include "data.h" #include "data.h"
#include <math.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <math.h> #include <algorithm>
using namespace std; using namespace std;
@@ -39,14 +40,13 @@ result_t DataField::create(vector<string>::iterator& it,
DataFieldTemplates* templates, DataField*& returnField, DataFieldTemplates* templates, DataField*& returnField,
const bool isWriteMessage, const bool isWriteMessage,
const bool isTemplate, const bool isBroadcastOrMasterDestination, const bool isTemplate, const bool isBroadcastOrMasterDestination,
const unsigned char maxFieldLength) const unsigned char maxFieldLength) {
{
vector<SingleDataField*> fields; vector<SingleDataField*> fields;
string firstName, firstComment; string firstName, firstComment;
result_t result = RESULT_OK; result_t result = RESULT_OK;
if (it == end) if (it == end) {
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
}
while (it != end && result == RESULT_OK) { while (it != end && result == RESULT_OK) {
string unit, comment; string unit, comment;
PartType partType; PartType partType;
@@ -58,8 +58,9 @@ result_t DataField::create(vector<string>::iterator& it,
// std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]] // std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
const string name = *it++; // name const string name = *it++; // name
if (it == end) { if (it == end) {
if (!name.empty()) if (!name.empty()) {
result = RESULT_ERR_MISSING_TYPE; result = RESULT_ERR_MISSING_TYPE;
}
break; break;
} }
@@ -69,8 +70,9 @@ result_t DataField::create(vector<string>::iterator& it,
const char* partStr = (*it++).c_str(); // part const char* partStr = (*it++).c_str(); // part
hasPartStr = partStr[0] != 0; hasPartStr = partStr[0] != 0;
if (it == end) { if (it == end) {
if (!name.empty() || hasPartStr) if (!name.empty() || hasPartStr) {
result = RESULT_ERR_MISSING_TYPE; result = RESULT_ERR_MISSING_TYPE;
}
break; break;
} }
if (isBroadcastOrMasterDestination if (isBroadcastOrMasterDestination
@@ -110,7 +112,7 @@ result_t DataField::create(vector<string>::iterator& it,
if (equalPos == string::npos) { if (equalPos == string::npos) {
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result); divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
} else if (equalPos == 0 && divisorStr.length() > 1) { } else if (equalPos == 0 && divisorStr.length() > 1) {
verifyValue = divisorStr[1]=='='; // == forced verification of constant value verifyValue = divisorStr[1] == '='; // == forced verification of constant value
if (verifyValue && divisorStr.length() == 1) { if (verifyValue && divisorStr.length() == 1) {
result = RESULT_ERR_INVALID_LIST; result = RESULT_ERR_INVALID_LIST;
break; break;
@@ -188,7 +190,7 @@ result_t DataField::create(vector<string>::iterator& it,
length = 0; // no length specified length = 0; // no length specified
typeName = token; typeName = token;
} else { } else {
if (pos+2==token.length() && token[pos+1]=='*') { if (pos+2 == token.length() && token[pos+1] == '*') {
length = REMAIN_LEN; length = REMAIN_LEN;
} else { } else {
length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, maxFieldLength, result); length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, maxFieldLength, result);
@@ -245,8 +247,7 @@ result_t DataField::create(vector<string>::iterator& it,
return RESULT_OK; return RESULT_OK;
} }
void DataField::dumpString(ostream& output, const string str, const bool prependFieldSeparator) void DataField::dumpString(ostream& output, const string str, const bool prependFieldSeparator) {
{
if (prependFieldSeparator) { if (prependFieldSeparator) {
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
} }
@@ -260,9 +261,8 @@ void DataField::dumpString(ostream& output, const string str, const bool prepend
result_t SingleDataField::create(const string id, const unsigned char length, result_t SingleDataField::create(const string id, const unsigned char length,
const string name, const string comment, const string unit, const string name, const string comment, const string unit,
const PartType partType, int divisor, map<unsigned int, string> values, const PartType partType, int divisor, map<unsigned int, string> values,
const string constantValue, const bool verifyValue, SingleDataField* &returnField) const string constantValue, const bool verifyValue, SingleDataField* &returnField) {
{ DataType* dataType = DataTypeList::getInstance()->get(id, length == REMAIN_LEN ? (unsigned char)0 : length);
DataType* dataType = DataTypeList::getInstance()->get(id, length==REMAIN_LEN ? (unsigned char)0 : length);
if (!dataType) { if (!dataType) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
@@ -298,7 +298,7 @@ result_t SingleDataField::create(const string id, const unsigned char length,
values[numType->getMinValue() + i] = dayNames[i]; values[numType->getMinValue() + i] = dayNames[i];
} }
result_t result = numType->derive(divisor, bitCount, numType); result_t result = numType->derive(divisor, bitCount, numType);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
if (values.empty()) { if (values.empty()) {
@@ -318,15 +318,15 @@ result_t SingleDataField::create(const string id, const unsigned char length,
return RESULT_OK; return RESULT_OK;
} }
void SingleDataField::dump(ostream& output) void SingleDataField::dump(ostream& output) {
{
output << setw(0) << dec; // initialize formatting output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false); dumpString(output, m_name, false);
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) if (m_partType == pt_masterData) {
output << "m"; output << "m";
else if (m_partType == pt_slaveData) } else if (m_partType == pt_slaveData) {
output << "s"; output << "s";
}
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
m_dataType->dump(output, m_length); m_dataType->dump(output, m_length);
dumpString(output, m_unit); dumpString(output, m_unit);
@@ -336,11 +336,10 @@ void SingleDataField::dump(ostream& output)
result_t SingleDataField::read(const PartType partType, result_t SingleDataField::read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
unsigned int& output, const char* fieldName, signed char fieldIndex) unsigned int& output, const char* fieldName, signed char fieldIndex) {
{ if (partType != m_partType) {
if (partType != m_partType)
return RESULT_EMPTY; return RESULT_EMPTY;
}
switch (m_partType) switch (m_partType)
{ {
case pt_masterData: case pt_masterData:
@@ -352,7 +351,7 @@ result_t SingleDataField::read(const PartType partType,
default: default:
return RESULT_ERR_INVALID_PART; return RESULT_ERR_INVALID_PART;
} }
bool remainder = m_length==REMAIN_LEN && m_dataType->isAdjustableLength(); bool remainder = m_length == REMAIN_LEN && m_dataType->isAdjustableLength();
if (offset + (remainder?1:m_length) > data.size()) { if (offset + (remainder?1:m_length) > data.size()) {
return RESULT_ERR_INVALID_POS; return RESULT_ERR_INVALID_POS;
} }
@@ -365,8 +364,7 @@ result_t SingleDataField::read(const PartType partType,
result_t SingleDataField::read(const PartType partType, result_t SingleDataField::read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex, ostringstream& output, OutputFormat outputFormat, signed char outputIndex,
bool leadingSeparator, const char* fieldName, signed char fieldIndex) bool leadingSeparator, const char* fieldName, signed char fieldIndex) {
{
if (partType != m_partType) { if (partType != m_partType) {
return RESULT_OK; return RESULT_OK;
} }
@@ -381,7 +379,7 @@ result_t SingleDataField::read(const PartType partType,
default: default:
return RESULT_ERR_INVALID_PART; return RESULT_ERR_INVALID_PART;
} }
bool remainder = m_length==REMAIN_LEN && m_dataType->isAdjustableLength(); bool remainder = m_length == REMAIN_LEN && m_dataType->isAdjustableLength();
if (offset + (remainder?1:m_length) > data.size()) { if (offset + (remainder?1:m_length) > data.size()) {
return RESULT_ERR_INVALID_POS; return RESULT_ERR_INVALID_POS;
} }
@@ -393,8 +391,8 @@ result_t SingleDataField::read(const PartType partType,
if (leadingSeparator) { if (leadingSeparator) {
output << ","; output << ",";
} }
if (outputIndex>=0 || m_name.empty() || !(outputFormat & OF_NAMES)) { if (outputIndex >= 0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
output << "\n \"" << static_cast<signed int>(outputIndex<0?0:outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": "; output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
} else { } else {
output << "\n \"" << m_name << "\": {\"value\": "; output << "\n \"" << m_name << "\": {\"value\": ";
} }
@@ -407,7 +405,7 @@ result_t SingleDataField::read(const PartType partType,
} }
} }
result_t result = readSymbols(data, m_partType==pt_masterData, offset, output, outputFormat); result_t result = readSymbols(data, m_partType == pt_masterData, offset, output, outputFormat);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -433,8 +431,7 @@ result_t SingleDataField::read(const PartType partType,
result_t SingleDataField::write(istringstream& input, result_t SingleDataField::write(istringstream& input,
const PartType partType, SymbolString& data, const PartType partType, SymbolString& data,
unsigned char offset, char separator, unsigned char* length) unsigned char offset, char separator, unsigned char* length) {
{
if (partType != m_partType) { if (partType != m_partType) {
return RESULT_OK; return RESULT_OK;
} }
@@ -449,50 +446,52 @@ result_t SingleDataField::write(istringstream& input,
default: default:
return RESULT_ERR_INVALID_PART; return RESULT_ERR_INVALID_PART;
} }
return writeSymbols(input, (const unsigned char)offset, data, m_partType==pt_masterData, length); return writeSymbols(input, (const unsigned char)offset, data, m_partType == pt_masterData, length);
} }
result_t SingleDataField::readSymbols(SymbolString& input, const bool isMaster, result_t SingleDataField::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset, const unsigned char offset,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
return m_dataType->readSymbols(input, isMaster, offset, m_length, output, outputFormat); return m_dataType->readSymbols(input, isMaster, offset, m_length, output, outputFormat);
} }
result_t SingleDataField::writeSymbols(istringstream& input, result_t SingleDataField::writeSymbols(istringstream& input,
const unsigned char offset, const unsigned char offset,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
return m_dataType->writeSymbols(input, offset, m_length, output, isMaster, usedLength); return m_dataType->writeSymbols(input, offset, m_length, output, isMaster, usedLength);
} }
SingleDataField* SingleDataField::clone() SingleDataField* SingleDataField::clone() {
{
return new SingleDataField(*this); return new SingleDataField(*this);
} }
result_t SingleDataField::derive(string name, string comment, result_t SingleDataField::derive(string name, string comment,
string unit, const PartType partType, string unit, const PartType partType,
int divisor, map<unsigned int, string> values, int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) vector<SingleDataField*>& fields) {
{ if (m_partType != pt_any && partType == pt_any) {
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
}
bool numeric = m_dataType->isNumeric(); bool numeric = m_dataType->isNumeric();
if (!numeric && (divisor != 0 || !values.empty())) if (!numeric && (divisor != 0 || !values.empty())) {
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field
if (name.empty()) }
if (name.empty()) {
name = m_name; name = m_name;
if (comment.empty()) }
if (comment.empty()) {
comment = m_comment; comment = m_comment;
if (unit.empty()) }
if (unit.empty()) {
unit = m_unit; unit = m_unit;
}
DataType* dataType = m_dataType; DataType* dataType = m_dataType;
if (numeric) { if (numeric) {
NumberDataType* numType = (NumberDataType*)m_dataType; NumberDataType* numType = (NumberDataType*)m_dataType;
result_t result = numType->derive(divisor, 0, numType); result_t result = numType->derive(divisor, 0, numType);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
dataType = numType; dataType = numType;
} }
if (values.empty()) { if (values.empty()) {
@@ -503,23 +502,20 @@ result_t SingleDataField::derive(string name, string comment,
return RESULT_OK; return RESULT_OK;
} }
bool SingleDataField::hasField(const char* fieldName, bool numeric) bool SingleDataField::hasField(const char* fieldName, bool numeric) {
{
bool numericType = m_dataType->isNumeric(); bool numericType = m_dataType->isNumeric();
return numeric==numericType && (fieldName==NULL || fieldName==m_name); return numeric == numericType && (fieldName == NULL || fieldName == m_name);
} }
unsigned char SingleDataField::getLength(PartType partType, unsigned char maxLength) unsigned char SingleDataField::getLength(PartType partType, unsigned char maxLength) {
{
if (partType != m_partType) { if (partType != m_partType) {
return (unsigned char)0; return (unsigned char)0;
} }
bool remainder = m_length==REMAIN_LEN && m_dataType->isAdjustableLength(); bool remainder = m_length == REMAIN_LEN && m_dataType->isAdjustableLength();
return remainder ? maxLength : m_length; return remainder ? maxLength : m_length;
} }
bool SingleDataField::hasFullByteOffset(bool after) bool SingleDataField::hasFullByteOffset(bool after) {
{
if (m_length > 1 || !m_dataType->isNumeric()) { if (m_length > 1 || !m_dataType->isNumeric()) {
return true; return true;
} }
@@ -529,49 +525,50 @@ bool SingleDataField::hasFullByteOffset(bool after)
} }
ValueListDataField* ValueListDataField::clone() ValueListDataField* ValueListDataField::clone() {
{
return new ValueListDataField(*this); return new ValueListDataField(*this);
} }
result_t ValueListDataField::derive(string name, string comment, result_t ValueListDataField::derive(string name, string comment,
string unit, const PartType partType, string unit, const PartType partType,
int divisor, map<unsigned int, string> values, int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) vector<SingleDataField*>& fields) {
{ if (m_partType != pt_any && partType == pt_any) {
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty()) }
if (name.empty()) {
name = m_name; name = m_name;
if (comment.empty()) }
if (comment.empty()) {
comment = m_comment; comment = m_comment;
if (unit.empty()) }
if (unit.empty()) {
unit = m_unit; unit = m_unit;
if (divisor != 0 && divisor != 1) }
if (divisor != 0 && divisor != 1) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
}
if (!values.empty()) { if (!values.empty()) {
NumberDataType* num = (NumberDataType*)m_dataType; NumberDataType* num = (NumberDataType*)m_dataType;
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
} }
else } else {
values = m_values; values = m_values;
}
fields.push_back(new ValueListDataField(name, comment, unit, (NumberDataType*)m_dataType, partType, m_length, values)); fields.push_back(new ValueListDataField(name, comment, unit, (NumberDataType*)m_dataType, partType, m_length, values));
return RESULT_OK; return RESULT_OK;
} }
void ValueListDataField::dump(ostream& output) void ValueListDataField::dump(ostream& output) {
{
output << setw(0) << dec; // initialize formatting output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false); dumpString(output, m_name, false);
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) if (m_partType == pt_masterData) {
output << "m"; output << "m";
else if (m_partType == pt_slaveData) } else if (m_partType == pt_slaveData) {
output << "s"; output << "s";
}
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
if (!m_dataType->dump(output, m_length)) { // no divisor appended if (!m_dataType->dump(output, m_length)) { // no divisor appended
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) { for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
@@ -587,13 +584,13 @@ void ValueListDataField::dump(ostream& output)
result_t ValueListDataField::readSymbols(SymbolString& input, const bool isMaster, result_t ValueListDataField::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset, const unsigned char offset,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
unsigned int value = 0; unsigned int value = 0;
result_t result = m_dataType->readRawValue(input, offset, m_length, value); result_t result = m_dataType->readRawValue(input, offset, m_length, value);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
map<unsigned int, string>::iterator it = m_values.find(value); map<unsigned int, string>::iterator it = m_values.find(value);
if (it == m_values.end() && value != m_dataType->getReplacement()) { if (it == m_values.end() && value != m_dataType->getReplacement()) {
// fall back to raw value in input // fall back to raw value in input
@@ -601,85 +598,90 @@ result_t ValueListDataField::readSymbols(SymbolString& input, const bool isMaste
return RESULT_OK; return RESULT_OK;
} }
if (it == m_values.end()) { if (it == m_values.end()) {
if (outputFormat & OF_JSON) if (outputFormat & OF_JSON) {
output << "null"; output << "null";
else if (value == m_dataType->getReplacement()) } else if (value == m_dataType->getReplacement()) {
output << NULL_VALUE; output << NULL_VALUE;
} else if (outputFormat & OF_NUMERIC) }
} else if (outputFormat & OF_NUMERIC) {
output << setw(0) << dec << static_cast<unsigned>(value); output << setw(0) << dec << static_cast<unsigned>(value);
else if (outputFormat & OF_JSON) } else if (outputFormat & OF_JSON) {
output << '"' << it->second << '"'; output << '"' << it->second << '"';
else } else {
output << it->second; output << it->second;
}
return RESULT_OK; return RESULT_OK;
} }
result_t ValueListDataField::writeSymbols(istringstream& input, result_t ValueListDataField::writeSymbols(istringstream& input,
const unsigned char offset, const unsigned char offset,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
NumberDataType* numType = (NumberDataType*)m_dataType; NumberDataType* numType = (NumberDataType*)m_dataType;
if (isIgnored()) if (isIgnored()) {
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
}
const char* str = input.str().c_str(); const char* str = input.str().c_str();
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
if (it->second.compare(str) == 0) if (it->second.compare(str) == 0) {
return numType->writeRawValue(it->first, offset, m_length, output, usedLength); return numType->writeRawValue(it->first, offset, m_length, output, usedLength);
}
if (strcasecmp(str, NULL_VALUE) == 0) }
if (strcasecmp(str, NULL_VALUE) == 0) {
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
}
char* strEnd = NULL; // fall back to raw value in input char* strEnd = NULL; // fall back to raw value in input
unsigned int value; unsigned int value;
value = (unsigned int)strtoul(str, &strEnd, 10); value = (unsigned int)strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
return RESULT_ERR_INVALID_NUM; // invalid value return RESULT_ERR_INVALID_NUM; // invalid value
if (m_values.find(value) != m_values.end()) }
if (m_values.find(value) != m_values.end()) {
return numType->writeRawValue(value, offset, m_length, output, usedLength); return numType->writeRawValue(value, offset, m_length, output, usedLength);
}
return RESULT_ERR_NOTFOUND; // value assignment not found return RESULT_ERR_NOTFOUND; // value assignment not found
} }
ConstantDataField* ConstantDataField::clone() ConstantDataField* ConstantDataField::clone() {
{
return new ConstantDataField(*this); return new ConstantDataField(*this);
} }
result_t ConstantDataField::derive(string name, string comment, result_t ConstantDataField::derive(string name, string comment,
string unit, const PartType partType, string unit, const PartType partType,
int divisor, map<unsigned int, string> values, int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) vector<SingleDataField*>& fields) {
{ if (m_partType != pt_any && partType == pt_any) {
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty()) }
if (name.empty()) {
name = m_name; name = m_name;
if (comment.empty()) }
if (comment.empty()) {
comment = m_comment; comment = m_comment;
if (unit.empty()) }
if (unit.empty()) {
unit = m_unit; unit = m_unit;
if (divisor != 0) }
if (divisor != 0) {
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
}
if (!values.empty()) { if (!values.empty()) {
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
} }
fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify)); fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify));
return RESULT_OK; return RESULT_OK;
} }
void ConstantDataField::dump(ostream& output) void ConstantDataField::dump(ostream& output) {
{
output << setw(0) << dec; // initialize formatting output << setw(0) << dec; // initialize formatting
dumpString(output, m_name, false); dumpString(output, m_name, false);
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
if (m_partType == pt_masterData) if (m_partType == pt_masterData) {
output << "m"; output << "m";
else if (m_partType == pt_slaveData) } else if (m_partType == pt_slaveData) {
output << "s"; output << "s";
}
output << FIELD_SEPARATOR; output << FIELD_SEPARATOR;
if (!m_dataType->dump(output, m_length)) { // no divisor appended if (!m_dataType->dump(output, m_length)) { // no divisor appended
output << (m_verify?"==":"=") << m_value; output << (m_verify?"==":"=") << m_value;
@@ -690,8 +692,7 @@ void ConstantDataField::dump(ostream& output)
result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster, result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char offset, const unsigned char offset,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
ostringstream coutput; ostringstream coutput;
result_t result = SingleDataField::readSymbols(input, isMaster, offset, coutput, 0); result_t result = SingleDataField::readSymbols(input, isMaster, offset, coutput, 0);
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -700,7 +701,7 @@ result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster
if (m_verify) { if (m_verify) {
string value = coutput.str(); string value = coutput.str();
FileReader::trim(value); FileReader::trim(value);
if (value!=m_value) { if (value != m_value) {
return RESULT_ERR_OUT_OF_RANGE; return RESULT_ERR_OUT_OF_RANGE;
} }
} }
@@ -709,8 +710,7 @@ result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster
result_t ConstantDataField::writeSymbols(istringstream& input, result_t ConstantDataField::writeSymbols(istringstream& input,
const unsigned char offset, const unsigned char offset,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
istringstream cinput(m_value); istringstream cinput(m_value);
return SingleDataField::writeSymbols(cinput, offset, output, isMaster, usedLength); return SingleDataField::writeSymbols(cinput, offset, output, isMaster, usedLength);
} }
@@ -718,9 +718,8 @@ result_t ConstantDataField::writeSymbols(istringstream& input,
DataFieldSet* DataFieldSet::s_identFields = NULL; DataFieldSet* DataFieldSet::s_identFields = NULL;
DataFieldSet* DataFieldSet::getIdentFields() DataFieldSet* DataFieldSet::getIdentFields() {
{ if (s_identFields == NULL) {
if (s_identFields==NULL) {
NumberDataType* uchDataType = (NumberDataType*)DataTypeList::getInstance()->get("UCH"); NumberDataType* uchDataType = (NumberDataType*)DataTypeList::getInstance()->get("UCH");
StringDataType* stringDataType = (StringDataType*)DataTypeList::getInstance()->get("STR"); StringDataType* stringDataType = (StringDataType*)DataTypeList::getInstance()->get("STR");
NumberDataType* pinDataType = (NumberDataType*)DataTypeList::getInstance()->get("PIN"); NumberDataType* pinDataType = (NumberDataType*)DataTypeList::getInstance()->get("PIN");
@@ -760,16 +759,14 @@ DataFieldSet* DataFieldSet::getIdentFields()
return s_identFields; return s_identFields;
} }
DataFieldSet::~DataFieldSet() DataFieldSet::~DataFieldSet() {
{
while (!m_fields.empty()) { while (!m_fields.empty()) {
delete m_fields.back(); delete m_fields.back();
m_fields.pop_back(); m_fields.pop_back();
} }
} }
DataFieldSet* DataFieldSet::clone() DataFieldSet* DataFieldSet::clone() {
{
vector<SingleDataField*> fields; vector<SingleDataField*> fields;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
fields.push_back((*it)->clone()); fields.push_back((*it)->clone());
@@ -777,23 +774,22 @@ DataFieldSet* DataFieldSet::clone()
return new DataFieldSet(m_name, m_comment, fields); return new DataFieldSet(m_name, m_comment, fields);
} }
unsigned char DataFieldSet::getLength(PartType partType, unsigned char maxLength) unsigned char DataFieldSet::getLength(PartType partType, unsigned char maxLength) {
{
unsigned char length = 0; unsigned char length = 0;
bool previousFullByteOffset[] = { true, true, true, true }; bool previousFullByteOffset[] = { true, true, true, true };
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (field->getPartType() == partType) { if (field->getPartType() == partType) {
if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) {
length--; length--;
}
unsigned char fieldLength = field->getLength(partType, maxLength); unsigned char fieldLength = field->getLength(partType, maxLength);
if (fieldLength>=maxLength) if (fieldLength >= maxLength) {
maxLength = 0; maxLength = 0;
else } else {
maxLength = (unsigned char)(maxLength-fieldLength); maxLength = (unsigned char)(maxLength-fieldLength);
}
length = (unsigned char)(length + fieldLength); length = (unsigned char)(length + fieldLength);
previousFullByteOffset[partType] = field->hasFullByteOffset(true); previousFullByteOffset[partType] = field->hasFullByteOffset(true);
@@ -803,12 +799,11 @@ unsigned char DataFieldSet::getLength(PartType partType, unsigned char maxLength
return length; return length;
} }
string DataFieldSet::getName(signed char fieldIndex) string DataFieldSet::getName(signed char fieldIndex) {
{ if (fieldIndex < 0) {
if (fieldIndex<0) {
return m_name; return m_name;
} }
if ((unsigned char)fieldIndex>=m_fields.size()) { if ((unsigned char)fieldIndex >= m_fields.size()) {
return ""; return "";
} }
if (m_uniqueNames) { if (m_uniqueNames) {
@@ -822,33 +817,33 @@ string DataFieldSet::getName(signed char fieldIndex)
result_t DataFieldSet::derive(string name, string comment, result_t DataFieldSet::derive(string name, string comment,
string unit, const PartType partType, string unit, const PartType partType,
int divisor, map<unsigned int, string> values, int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) vector<SingleDataField*>& fields) {
{ if (!values.empty()) {
if (!values.empty())
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
}
bool first = true; bool first = true;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
result_t result = (*it)->derive("", first?comment:"", first?unit:"", partType, divisor, values, fields); result_t result = (*it)->derive("", first?comment:"", first?unit:"", partType, divisor, values, fields);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
first = false; first = false;
} }
return RESULT_OK; return RESULT_OK;
} }
bool DataFieldSet::hasField(const char* fieldName, bool numeric) bool DataFieldSet::hasField(const char* fieldName, bool numeric) {
{
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (field->hasField(fieldName, numeric)==0) if (field->hasField(fieldName, numeric) == 0) {
return true; return true;
}
} }
return false; return false;
} }
void DataFieldSet::dump(ostream& output) void DataFieldSet::dump(ostream& output) {
{
bool first = true; bool first = true;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
if (first) { if (first) {
@@ -862,22 +857,20 @@ void DataFieldSet::dump(ostream& output)
result_t DataFieldSet::read(const PartType partType, result_t DataFieldSet::read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
unsigned int& output, const char* fieldName, signed char fieldIndex) unsigned int& output, const char* fieldName, signed char fieldIndex) {
{
bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0; bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (partType != pt_any && field->getPartType() != partType) if (partType != pt_any && field->getPartType() != partType) {
continue; continue;
}
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
offset--; offset--;
}
result_t result = field->read(partType, data, offset, output, fieldName, fieldIndex); result_t result = field->read(partType, data, offset, output, fieldName, fieldIndex);
if (result < RESULT_OK) {
if (result < RESULT_OK)
return result; return result;
}
offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset))); offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
previousFullByteOffset = field->hasFullByteOffset(true); previousFullByteOffset = field->hasFullByteOffset(true);
if (result != RESULT_EMPTY) { if (result != RESULT_EMPTY) {
@@ -885,8 +878,9 @@ result_t DataFieldSet::read(const PartType partType,
} }
if (findFieldIndex && fieldName == field->getName()) { if (findFieldIndex && fieldName == field->getName()) {
if (fieldIndex == 0) { if (fieldIndex == 0) {
if (!found) if (!found) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
}
break; break;
} }
fieldIndex--; fieldIndex--;
@@ -903,26 +897,26 @@ result_t DataFieldSet::read(const PartType partType,
result_t DataFieldSet::read(const PartType partType, result_t DataFieldSet::read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex, ostringstream& output, OutputFormat outputFormat, signed char outputIndex,
bool leadingSeparator, const char* fieldName, signed char fieldIndex) bool leadingSeparator, const char* fieldName, signed char fieldIndex) {
{
bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0; bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0;
if (!m_uniqueNames && outputIndex<0) if (!m_uniqueNames && outputIndex < 0) {
outputIndex = 0; outputIndex = 0;
}
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (partType != pt_any && field->getPartType() != partType) { if (partType != pt_any && field->getPartType() != partType) {
if (outputIndex>=0 && !field->isIgnored()) if (outputIndex >= 0 && !field->isIgnored()) {
outputIndex++; outputIndex++;
}
continue; continue;
} }
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
offset--; offset--;
}
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex); result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex);
if (result < RESULT_OK) {
if (result < RESULT_OK)
return result; return result;
}
offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset))); offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
previousFullByteOffset = field->hasFullByteOffset(true); previousFullByteOffset = field->hasFullByteOffset(true);
if (result != RESULT_EMPTY) { if (result != RESULT_EMPTY) {
@@ -931,14 +925,16 @@ result_t DataFieldSet::read(const PartType partType,
} }
if (findFieldIndex && fieldName == field->getName()) { if (findFieldIndex && fieldName == field->getName()) {
if (fieldIndex == 0) { if (fieldIndex == 0) {
if (!found) if (!found) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
}
break; break;
} }
fieldIndex--; fieldIndex--;
} }
if (outputIndex>=0 && !field->isIgnored()) if (outputIndex >= 0 && !field->isIgnored()) {
outputIndex++; outputIndex++;
}
} }
if (!found) { if (!found) {
@@ -957,57 +953,54 @@ result_t DataFieldSet::read(const PartType partType,
result_t DataFieldSet::write(istringstream& input, result_t DataFieldSet::write(istringstream& input,
const PartType partType, SymbolString& data, const PartType partType, SymbolString& data,
unsigned char offset, char separator, unsigned char* length) unsigned char offset, char separator, unsigned char* length) {
{
string token; string token;
bool previousFullByteOffset = true; bool previousFullByteOffset = true;
unsigned char baseOffset = offset; unsigned char baseOffset = offset;
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) { for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (partType != pt_any && field->getPartType() != partType) if (partType != pt_any && field->getPartType() != partType) {
continue; continue;
}
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
offset--; offset--;
}
result_t result; result_t result;
unsigned char fieldLength; unsigned char fieldLength;
if (m_fields.size() > 1) { if (m_fields.size() > 1) {
if (field->isIgnored()) if (field->isIgnored()) {
token.clear(); token.clear();
else if (!getline(input, token, separator)) } else if (!getline(input, token, separator)) {
token.clear(); token.clear();
}
istringstream single(token); istringstream single(token);
result = (*it)->write(single, partType, data, offset, separator, &fieldLength); result = (*it)->write(single, partType, data, offset, separator, &fieldLength);
} } else {
else
result = (*it)->write(input, partType, data, offset, separator, &fieldLength); result = (*it)->write(input, partType, data, offset, separator, &fieldLength);
}
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
offset = (unsigned char)(offset+fieldLength); offset = (unsigned char)(offset+fieldLength);
previousFullByteOffset = field->hasFullByteOffset(true); previousFullByteOffset = field->hasFullByteOffset(true);
} }
if (length!=NULL) if (length != NULL) {
*length = (unsigned char)(offset-baseOffset); *length = (unsigned char)(offset-baseOffset);
}
return RESULT_OK; return RESULT_OK;
} }
DataFieldTemplates::DataFieldTemplates(DataFieldTemplates& other) DataFieldTemplates::DataFieldTemplates(DataFieldTemplates& other)
: FileReader::FileReader(false) : FileReader::FileReader(false) {
{
for (map<string, DataField*>::iterator it = other.m_fieldsByName.begin(); it != other.m_fieldsByName.end(); it++) { for (map<string, DataField*>::iterator it = other.m_fieldsByName.begin(); it != other.m_fieldsByName.end(); it++) {
m_fieldsByName[it->first] = it->second->clone(); m_fieldsByName[it->first] = it->second->clone();
} }
} }
void DataFieldTemplates::clear() void DataFieldTemplates::clear() {
{
for (map<string, DataField*>::iterator it = m_fieldsByName.begin(); it != m_fieldsByName.end(); it++) { for (map<string, DataField*>::iterator it = m_fieldsByName.begin(); it != m_fieldsByName.end(); it++) {
delete it->second; delete it->second;
it->second = NULL; it->second = NULL;
@@ -1015,58 +1008,55 @@ void DataFieldTemplates::clear()
m_fieldsByName.clear(); m_fieldsByName.clear();
} }
result_t DataFieldTemplates::add(DataField* field, string name, bool replace) result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
{ if (name.length() == 0) {
if (name.length() == 0)
name = field->getName(); name = field->getName();
}
map<string, DataField*>::iterator it = m_fieldsByName.find(name); map<string, DataField*>::iterator it = m_fieldsByName.find(name);
if (it != m_fieldsByName.end()) { if (it != m_fieldsByName.end()) {
if (!replace) if (!replace) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
delete it->second; delete it->second;
it->second = field; it->second = field;
return RESULT_OK; return RESULT_OK;
} }
m_fieldsByName[name] = field; m_fieldsByName[name] = field;
return RESULT_OK; return RESULT_OK;
} }
result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end, result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix, vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo) const string& filename, unsigned int lineNo) {
{
vector<string>::iterator restart = begin; vector<string>::iterator restart = begin;
DataField* field = NULL; DataField* field = NULL;
string name; string name;
if (begin != end) { if (begin != end) {
size_t colon = begin->find(':'); size_t colon = begin->find(':');
if (colon!=string::npos) { if (colon != string::npos) {
name = begin->substr(0, colon); name = begin->substr(0, colon);
begin->erase(0, colon+1); begin->erase(0, colon+1);
} }
} }
result_t result = DataField::create(begin, end, this, field, false, true, false); result_t result = DataField::create(begin, end, this, field, false, true, false);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; return result;
}
result = add(field, name, true); result = add(field, name, true);
if (result==RESULT_ERR_DUPLICATE_NAME) if (result == RESULT_ERR_DUPLICATE_NAME) {
begin = restart+1; // mark name as invalid begin = restart+1; // mark name as invalid
if (result != RESULT_OK) }
if (result != RESULT_OK) {
delete field; delete field;
}
return result; return result;
} }
DataField* DataFieldTemplates::get(const string name) DataField* DataFieldTemplates::get(const string name) {
{
map<string, DataField*>::const_iterator ref = m_fieldsByName.find(name); map<string, DataField*>::const_iterator ref = m_fieldsByName.find(name);
if (ref == m_fieldsByName.end()) if (ref == m_fieldsByName.end()) {
return NULL; return NULL;
}
return ref->second; return ref->second;
} }
+34 -32
View File
@@ -16,19 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_DATA_H_ #ifndef LIB_EBUS_DATA_H_
#define LIBEBUS_DATA_H_ #define LIB_EBUS_DATA_H_
#include "symbol.h"
#include "result.h"
#include "filereader.h"
#include "datatype.h"
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <map> #include <map>
#include "symbol.h"
#include "result.h"
#include "filereader.h"
#include "datatype.h"
/** @file data.h /** @file data.h
* Classes related to defining fields based on data types in symbols on the * Classes related to defining fields based on data types in symbols on the
@@ -93,7 +93,7 @@ public:
DataFieldTemplates* templates, DataField*& returnField, DataFieldTemplates* templates, DataField*& returnField,
const bool isWriteMessage, const bool isWriteMessage,
const bool isTemplate, const bool isBroadcastOrMasterDestination, const bool isTemplate, const bool isBroadcastOrMasterDestination,
const unsigned char maxFieldLength=MAX_POS); const unsigned char maxFieldLength = MAX_POS);
/** /**
* Dump the @a string optionally embedded in @a TEXT_SEPARATOR to the output. * Dump the @a string optionally embedded in @a TEXT_SEPARATOR to the output.
@@ -101,7 +101,7 @@ public:
* @param str the @a string to dump. * @param str the @a string to dump.
* @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR.
*/ */
static void dumpString(ostream& output, const string str, const bool prependFieldSeparator=true); static void dumpString(ostream& output, const string str, const bool prependFieldSeparator = true);
/** /**
* Returns the length of this field (or contained fields) in bytes. * Returns the length of this field (or contained fields) in bytes.
@@ -109,7 +109,7 @@ public:
* @param maxLength the maximum length for calculating remainder of input. * @param maxLength the maximum length for calculating remainder of input.
* @return the length of this field (or contained fields) in bytes. * @return the length of this field (or contained fields) in bytes.
*/ */
virtual unsigned char getLength(PartType partType, unsigned char maxLength=MAX_LEN) = 0; virtual unsigned char getLength(PartType partType, unsigned char maxLength = MAX_LEN) = 0;
/** /**
* Derive a new @a DataField from this field. * Derive a new @a DataField from this field.
@@ -132,7 +132,7 @@ public:
* @param fieldIndex the index of the field, or -1 for this. * @param fieldIndex the index of the field, or -1 for this.
* @return the field name, or the index as string if not unique or not available. * @return the field name, or the index as string if not unique or not available.
*/ */
virtual string getName(signed char fieldIndex=-1) { return m_name; } virtual string getName(signed char fieldIndex = -1) { return m_name; }
/** /**
* Get the field comment. * Get the field comment.
@@ -169,7 +169,7 @@ public:
*/ */
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
unsigned int& output, const char* fieldName=NULL, signed char fieldIndex=-1) = 0; unsigned int& output, const char* fieldName = NULL, signed char fieldIndex = -1) = 0;
/** /**
* Reads the value from the @a SymbolString. * Reads the value from the @a SymbolString.
@@ -188,8 +188,8 @@ public:
*/ */
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1, ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1) = 0; bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1) = 0;
/** /**
* Writes the value to the master or slave @a SymbolString. * Writes the value to the master or slave @a SymbolString.
@@ -203,7 +203,7 @@ public:
*/ */
virtual result_t write(istringstream& input, virtual result_t write(istringstream& input,
const PartType partType, SymbolString& data, const PartType partType, SymbolString& data,
unsigned char offset, char separator=UI_FIELD_SEPARATOR, unsigned char* length=NULL) = 0; unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL) = 0;
protected: protected:
@@ -287,7 +287,7 @@ public:
PartType getPartType() const { return m_partType; } PartType getPartType() const { return m_partType; }
// @copydoc // @copydoc
virtual unsigned char getLength(PartType partType, unsigned char maxLength=MAX_LEN); virtual unsigned char getLength(PartType partType, unsigned char maxLength = MAX_LEN);
// @copydoc // @copydoc
virtual result_t derive(string name, string comment, virtual result_t derive(string name, string comment,
@@ -312,18 +312,18 @@ public:
// @copydoc // @copydoc
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
unsigned int& output, const char* fieldName=NULL, signed char fieldIndex=-1); unsigned int& output, const char* fieldName = NULL, signed char fieldIndex = -1);
// @copydoc // @copydoc
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1, ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1); bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
// @copydoc // @copydoc
virtual result_t write(istringstream& input, virtual result_t write(istringstream& input,
const PartType partType, SymbolString& data, const PartType partType, SymbolString& data,
unsigned char offset, char separator=UI_FIELD_SEPARATOR, unsigned char* length=NULL); unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
protected: protected:
@@ -526,11 +526,13 @@ public:
{ {
bool uniqueNames = true; bool uniqueNames = true;
map<string, string> names; map<string, string> names;
for (vector<SingleDataField*>::const_iterator it=fields.begin(); it!=fields.end(); it++) { for (vector<SingleDataField*>::const_iterator it = fields.begin(); it != fields.end(); it++) {
SingleDataField* field = *it; SingleDataField* field = *it;
if (field->isIgnored()) continue; if (field->isIgnored()) {
continue;
}
string name = field->getName(); string name = field->getName();
if (name.empty() || names.find(name)!=names.end()) { if (name.empty() || names.find(name) != names.end()) {
uniqueNames = false; uniqueNames = false;
break; break;
} }
@@ -548,10 +550,10 @@ public:
virtual DataFieldSet* clone(); virtual DataFieldSet* clone();
// @copydoc // @copydoc
virtual unsigned char getLength(PartType partType, unsigned char maxLength=MAX_LEN); virtual unsigned char getLength(PartType partType, unsigned char maxLength = MAX_LEN);
// @copydoc // @copydoc
virtual string getName(signed char fieldIndex=-1); virtual string getName(signed char fieldIndex = -1);
// @copydoc // @copydoc
virtual result_t derive(string name, string comment, virtual result_t derive(string name, string comment,
@@ -564,14 +566,14 @@ public:
* @param index the index of the @a SingleDataField to return. * @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL. * @return the @a SingleDataField at the specified index, or NULL.
*/ */
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) return NULL; return m_fields[index]; } SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
/** /**
* Returns the @a SingleDataField at the specified index. * Returns the @a SingleDataField at the specified index.
* @param index the index of the @a SingleDataField to return. * @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL. * @return the @a SingleDataField at the specified index, or NULL.
*/ */
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) return NULL; return m_fields[index]; } const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
/** /**
* Returns the number of @a SingleDataFields instances in this set. * Returns the number of @a SingleDataFields instances in this set.
@@ -588,18 +590,18 @@ public:
// @copydoc // @copydoc
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
unsigned int& output, const char* fieldName=NULL, signed char fieldIndex=-1); unsigned int& output, const char* fieldName = NULL, signed char fieldIndex = -1);
// @copydoc // @copydoc
virtual result_t read(const PartType partType, virtual result_t read(const PartType partType,
SymbolString& data, unsigned char offset, SymbolString& data, unsigned char offset,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1, ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1); bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
// @copydoc // @copydoc
virtual result_t write(istringstream& input, virtual result_t write(istringstream& input,
const PartType partType, SymbolString& data, const PartType partType, SymbolString& data,
unsigned char offset, char separator=UI_FIELD_SEPARATOR, unsigned char* length=NULL); unsigned char offset, char separator = UI_FIELD_SEPARATOR, unsigned char* length = NULL);
private: private:
@@ -653,7 +655,7 @@ public:
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success. * Note: the caller may not free the added instance on success.
*/ */
result_t add(DataField* field, string name="", bool replace=false); result_t add(DataField* field, string name = "", bool replace = false);
// @copydoc // @copydoc
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end, virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
@@ -675,4 +677,4 @@ private:
}; };
#endif // LIBEBUS_DATA_H_ #endif // LIB_EBUS_DATA_H_
+53 -66
View File
@@ -21,13 +21,12 @@
#endif #endif
#include "datatype.h" #include "datatype.h"
#include <math.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <math.h>
#ifdef HAVE_CONTRIB #ifdef HAVE_CONTRIB
# include "contrib/contrib.h" # include "contrib/contrib.h"
#endif #endif
@@ -76,8 +75,7 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
return (int)ret; return (int)ret;
} }
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result) void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
{
if (pos > begin) { if (pos > begin) {
pos--; pos--;
} }
@@ -105,7 +103,7 @@ void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<st
} else { } else {
i = item.find(FIELD_SEPARATOR); i = item.find(FIELD_SEPARATOR);
} }
if (i!=string::npos) { if (i != string::npos) {
out << TEXT_SEPARATOR << item << TEXT_SEPARATOR; out << TEXT_SEPARATOR << item << TEXT_SEPARATOR;
if (begin < pos) { if (begin < pos) {
cnt += 2; cnt += 2;
@@ -129,7 +127,7 @@ bool DataType::dump(ostream& output, const unsigned char length) const
{ {
output << m_id; output << m_id;
if (isAdjustableLength()) { if (isAdjustableLength()) {
if (length==REMAIN_LEN) { if (length == REMAIN_LEN) {
output << ":*"; output << ":*";
} else { } else {
output << ":" << static_cast<unsigned>(length); output << ":" << static_cast<unsigned>(length);
@@ -141,20 +139,18 @@ bool DataType::dump(ostream& output, const unsigned char length) const
result_t StringDataType::readRawValue(SymbolString& input, const unsigned char offset, result_t StringDataType::readRawValue(SymbolString& input, const unsigned char offset,
const unsigned char length, unsigned int& value) const unsigned char length, unsigned int& value) {
{
return RESULT_EMPTY; return RESULT_EMPTY;
} }
result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster, result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char baseOffset, const unsigned char length, const unsigned char baseOffset, const unsigned char length,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
unsigned char ch; unsigned char ch;
bool terminated = false; bool terminated = false;
if (count==REMAIN_LEN && input.size()>baseOffset) { if (count == REMAIN_LEN && input.size() > baseOffset) {
count = input.size()-baseOffset; count = input.size()-baseOffset;
} else if (baseOffset + count > input.size()) { } else if (baseOffset + count > input.size()) {
return RESULT_ERR_INVALID_POS; return RESULT_ERR_INVALID_POS;
@@ -200,10 +196,9 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
result_t StringDataType::writeSymbols(istringstream& input, result_t StringDataType::writeSymbols(istringstream& input,
unsigned char baseOffset, const unsigned char length, unsigned char baseOffset, const unsigned char length,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
bool remainder = count==REMAIN_LEN && hasFlag(ADJ); bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
int incr = 1; int incr = 1;
unsigned int value = 0; unsigned int value = 0;
string token; string token;
@@ -219,7 +214,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
for (size_t offset = start, i = 0; i < count; offset += incr, i++) { for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
} }
if (usedLength!=NULL) { if (usedLength != NULL) {
*usedLength = (unsigned char)count; *usedLength = (unsigned char)count;
} }
return RESULT_OK; return RESULT_OK;
@@ -244,16 +239,18 @@ result_t StringDataType::writeSymbols(istringstream& input,
return RESULT_ERR_INVALID_NUM; // too short hex value return RESULT_ERR_INVALID_NUM; // too short hex value
} }
value = parseInt(token.c_str(), 16, 0, 0xff, result); value = parseInt(token.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK) if (result != RESULT_OK) {
return result; // invalid hex value return result; // invalid hex value
}
} }
} else { } else {
if (input.eof()) { if (input.eof()) {
value = m_replacement; value = m_replacement;
} else { } else {
value = input.get(); value = input.get();
if (input.eof() || value < 0x20) if (input.eof() || value < 0x20) {
value = m_replacement; value = m_replacement;
}
} }
} }
if (remainder && input.eof() && i > 0) { if (remainder && input.eof() && i > 0) {
@@ -272,7 +269,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
if (!remainder && i < count) { if (!remainder && i < count) {
return RESULT_ERR_EOF; // input too short return RESULT_ERR_EOF; // input too short
} }
if (usedLength!=NULL) { if (usedLength != NULL) {
*usedLength = (unsigned char)((offset-start)*incr); *usedLength = (unsigned char)((offset-start)*incr);
} }
return RESULT_OK; return RESULT_OK;
@@ -280,19 +277,17 @@ result_t StringDataType::writeSymbols(istringstream& input,
result_t DateTimeDataType::readRawValue(SymbolString& input, const unsigned char offset, result_t DateTimeDataType::readRawValue(SymbolString& input, const unsigned char offset,
const unsigned char length, unsigned int& value) const unsigned char length, unsigned int& value) {
{
return RESULT_EMPTY; return RESULT_EMPTY;
} }
result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster, result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char baseOffset, const unsigned char length, const unsigned char baseOffset, const unsigned char length,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
unsigned char ch, last = 0, hour = 0; unsigned char ch, last = 0, hour = 0;
if (count==REMAIN_LEN && input.size()>baseOffset) { if (count == REMAIN_LEN && input.size() > baseOffset) {
count = input.size()-baseOffset; count = input.size()-baseOffset;
} else if (baseOffset + count > input.size()) { } else if (baseOffset + count > input.size()) {
return RESULT_ERR_INVALID_POS; return RESULT_ERR_INVALID_POS;
@@ -341,7 +336,7 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
int m = (int)((mjd-14956.1-(int)(y*365.25))/30.6001); int m = (int)((mjd-14956.1-(int)(y*365.25))/30.6001);
int d = mjd-14956-(int)(y*365.25)-(int)(m*30.6001); int d = mjd-14956-(int)(y*365.25)-(int)(m*30.6001);
m--; m--;
if (m>=13) { if (m >= 13) {
y++; y++;
m -= 12; m -= 12;
} }
@@ -402,8 +397,9 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
} else if (ch > 59 || (hour == 24 && ch > 0)) { } else if (ch > 59 || (hour == 24 && ch > 0)) {
return RESULT_ERR_OUT_OF_RANGE; // invalid time return RESULT_ERR_OUT_OF_RANGE; // invalid time
} }
if (i > 0) if (i > 0) {
output << ":"; output << ":";
}
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch); output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch);
break; break;
} }
@@ -417,10 +413,9 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
result_t DateTimeDataType::writeSymbols(istringstream& input, result_t DateTimeDataType::writeSymbols(istringstream& input,
unsigned char baseOffset, const unsigned char length, unsigned char baseOffset, const unsigned char length,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
bool remainder = count==REMAIN_LEN && hasFlag(ADJ); bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
int incr = 1; int incr = 1;
unsigned int value = 0, last = 0, lastLast = 0; unsigned int value = 0, last = 0, lastLast = 0;
string token; string token;
@@ -436,7 +431,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
for (size_t offset = start, i = 0; i < count; offset += incr, i++) { for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
} }
if (usedLength!=NULL) { if (usedLength != NULL) {
*usedLength = (unsigned char)count; *usedLength = (unsigned char)count;
} }
return RESULT_OK; return RESULT_OK;
@@ -450,8 +445,9 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
switch (type) switch (type)
{ {
case 2: // date only case 2: // date only
if (length == 4 && i == 2) if (length == 4 && i == 2) {
continue; // skip weekday in between continue; // skip weekday in between
}
if (input.eof() || !getline(input, token, '.')) { if (input.eof() || !getline(input, token, '.')) {
return RESULT_ERR_EOF; // incomplete return RESULT_ERR_EOF; // incomplete
} }
@@ -469,11 +465,11 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
count++; count++;
} else if (i + 1 == count) { } else if (i + 1 == count) {
int y = (value < 100 ? value + 2000 : value) - 1900; int y = (value < 100 ? value + 2000 : value) - 1900;
int l = last<=2 ? 1 : 0; int l = last <= 2 ? 1 : 0;
int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001); int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001);
value = mjd - 15020; // 01.01.1900 value = mjd - 15020; // 01.01.1900
output[baseOffset + offset] = (unsigned char)(value&0xff); output[baseOffset + offset] = (unsigned char)(value&0xff);
value >>= 8; value >>= 8;
offset += incr; offset += incr;
skip = false; skip = false;
break; break;
@@ -483,13 +479,13 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (length == 4) { if (length == 4) {
// calculate local week day // calculate local week day
int y = (value < 100 ? value + 2000 : value) - 1900; int y = (value < 100 ? value + 2000 : value) - 1900;
int l = last<=2 ? 1 : 0; int l = last <= 2 ? 1 : 0;
int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001); int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001);
int daysSinceSunday = (mjd+3) % 7; // Sun=0 int daysSinceSunday = (mjd+3) % 7; // Sun=0
if (hasFlag(BCD)) { if (hasFlag(BCD)) {
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06 output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
} else { } else {
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday==0 ? 7 : daysSinceSunday); // Sun=0x07 output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday == 0 ? 7 : daysSinceSunday); // Sun=0x07
} }
} }
if (value >= 2000) { if (value >= 2000) {
@@ -535,7 +531,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
} }
value += last*60; value += last*60;
output[baseOffset + offset] = (unsigned char)(value&0xff); output[baseOffset + offset] = (unsigned char)(value&0xff);
value >>= 8; value >>= 8;
offset += incr; offset += incr;
} else if (length == 1) { // truncated time } else if (length == 1) { // truncated time
if (i == 0) { if (i == 0) {
@@ -569,7 +565,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (!remainder && i < count) { if (!remainder && i < count) {
return RESULT_ERR_EOF; // input too short return RESULT_ERR_EOF; // input too short
} }
if (usedLength!=NULL) { if (usedLength != NULL) {
*usedLength = (unsigned char)((offset-start)*incr); *usedLength = (unsigned char)((offset-start)*incr);
} }
return RESULT_OK; return RESULT_OK;
@@ -600,15 +596,14 @@ bool NumberDataType::dump(ostream& output, unsigned char length) const
output << static_cast<int>(m_divisor / m_baseType->m_divisor); output << static_cast<int>(m_divisor / m_baseType->m_divisor);
return true; return true;
} }
} else if (m_divisor!=1) { } else if (m_divisor != 1) {
output << static_cast<int>(m_divisor); output << static_cast<int>(m_divisor);
return true; return true;
} }
return false; return false;
} }
result_t NumberDataType::derive(int divisor, unsigned char bitCount, NumberDataType* &derived) result_t NumberDataType::derive(int divisor, unsigned char bitCount, NumberDataType* &derived) {
{
if (divisor == 0) { if (divisor == 0) {
divisor = 1; divisor = 1;
} }
@@ -663,8 +658,7 @@ result_t NumberDataType::derive(int divisor, unsigned char bitCount, NumberDataT
result_t NumberDataType::readRawValue(SymbolString& input, result_t NumberDataType::readRawValue(SymbolString& input,
unsigned char baseOffset, const unsigned char length, unsigned char baseOffset, const unsigned char length,
unsigned int& value) unsigned int& value) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
unsigned char ch; unsigned char ch;
@@ -687,21 +681,22 @@ result_t NumberDataType::readRawValue(SymbolString& input,
return RESULT_OK; return RESULT_OK;
} }
if (!hasFlag(HCD)) { if (!hasFlag(HCD)) {
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09) {
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
}
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f)); ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
} else if (ch > 0x63) } else if (ch > 0x63) {
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
}
value += ch * exp; value += ch * exp;
exp *= 100; exp *= 100;
} else { } else {
value |= ch * exp; value |= ch * exp;
exp <<= 8; exp <<= 8;
} }
} }
if (m_firstBit > 0) { if (m_firstBit > 0) {
value >>= m_firstBit; value >>= m_firstBit;
} }
if (m_bitCount < 8) { if (m_bitCount < 8) {
value &= (1 << m_bitCount) - 1; value &= (1 << m_bitCount) - 1;
@@ -711,8 +706,7 @@ result_t NumberDataType::readRawValue(SymbolString& input,
result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster, result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
const unsigned char baseOffset, const unsigned char length, const unsigned char baseOffset, const unsigned char length,
ostringstream& output, OutputFormat outputFormat) ostringstream& output, OutputFormat outputFormat) {
{
unsigned int value = 0; unsigned int value = 0;
int signedValue; int signedValue;
@@ -810,8 +804,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
result_t NumberDataType::writeRawValue(unsigned int value, result_t NumberDataType::writeRawValue(unsigned int value,
const unsigned char baseOffset, const unsigned char length, const unsigned char baseOffset, const unsigned char length,
SymbolString& output, unsigned char* usedLength) SymbolString& output, unsigned char* usedLength) {
{
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
unsigned char ch; unsigned char ch;
@@ -820,7 +813,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
return RESULT_ERR_OUT_OF_RANGE; return RESULT_ERR_OUT_OF_RANGE;
} }
if (m_firstBit > 0) { if (m_firstBit > 0) {
value <<= m_firstBit; value <<= m_firstBit;
} }
if (hasFlag(REV)) { // reverted binary representation (most significant byte first) if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
@@ -841,7 +834,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
exp *= 100; exp *= 100;
} else { } else {
ch = (value / exp) & 0xff; ch = (value / exp) & 0xff;
exp <<= 8; exp <<= 8;
} }
if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size()) { if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size()) {
output[baseOffset + offset] |= ch; output[baseOffset + offset] |= ch;
@@ -849,7 +842,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
output[baseOffset + offset] = ch; output[baseOffset + offset] = ch;
} }
} }
if (usedLength!=NULL) { if (usedLength != NULL) {
*usedLength = length; *usedLength = length;
} }
return RESULT_OK; return RESULT_OK;
@@ -857,8 +850,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
result_t NumberDataType::writeSymbols(istringstream& input, result_t NumberDataType::writeSymbols(istringstream& input,
const unsigned char baseOffset, const unsigned char length, const unsigned char baseOffset, const unsigned char length,
SymbolString& output, const bool isMaster, unsigned char* usedLength) SymbolString& output, const bool isMaster, unsigned char* usedLength) {
{
unsigned int value; unsigned int value;
const char* str = input.str().c_str(); const char* str = input.str().c_str();
@@ -972,8 +964,7 @@ bool DataTypeList::s_contrib_initialized = libebus_contrib_register();
#endif #endif
DataTypeList::DataTypeList() DataTypeList::DataTypeList() {
{
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1)); // unsigned decimal in BCD, 0000 - 9999 (fixed length) 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 NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
@@ -1036,13 +1027,11 @@ DataTypeList::DataTypeList()
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7 add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
} }
DataTypeList* DataTypeList::getInstance() DataTypeList* DataTypeList::getInstance() {
{
return &s_instance; return &s_instance;
} }
void DataTypeList::clear() void DataTypeList::clear() {
{
for (list<DataType*>::iterator it = m_cleanupTypes.begin(); it != m_cleanupTypes.end(); it++) { for (list<DataType*>::iterator it = m_cleanupTypes.begin(); it != m_cleanupTypes.end(); it++) {
delete *it; delete *it;
} }
@@ -1051,12 +1040,11 @@ void DataTypeList::clear()
m_typesById.clear(); m_typesById.clear();
} }
result_t DataTypeList::add(DataType* dataType) result_t DataTypeList::add(DataType* dataType) {
{
if (!dataType->isAdjustableLength()) { if (!dataType->isAdjustableLength()) {
ostringstream str; ostringstream str;
unsigned char bitCount = dataType->getBitCount(); unsigned char bitCount = dataType->getBitCount();
str << dataType->getId() << LENGTH_SEPARATOR << static_cast<unsigned>(bitCount>=8?bitCount/8:bitCount); str << dataType->getId() << LENGTH_SEPARATOR << static_cast<unsigned>(bitCount >= 8?bitCount/8:bitCount);
map<string, DataType*>::iterator it = m_typesByIdLength.find(str.str()); map<string, DataType*>::iterator it = m_typesByIdLength.find(str.str());
if (it != m_typesByIdLength.end()) { if (it != m_typesByIdLength.end()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key return RESULT_ERR_DUPLICATE_NAME; // duplicate key
@@ -1074,8 +1062,7 @@ result_t DataTypeList::add(DataType* dataType)
return RESULT_OK; return RESULT_OK;
} }
DataType* DataTypeList::get(const string id, const unsigned char length) DataType* DataTypeList::get(const string id, const unsigned char length) {
{
DataType* dataType = NULL; DataType* dataType = NULL;
if (length > 0) { if (length > 0) {
ostringstream str; ostringstream str;
+11 -11
View File
@@ -16,12 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_DATATYPE_H_ #ifndef LIB_EBUS_DATATYPE_H_
#define LIBEBUS_DATATYPE_H_ #define LIB_EBUS_DATATYPE_H_
#include "symbol.h"
#include "result.h"
#include "filereader.h"
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -29,6 +26,9 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <map> #include <map>
#include "symbol.h"
#include "result.h"
#include "filereader.h"
/** @file datatype.h /** @file datatype.h
* Classes, functions, and constants related to decoding/encoding of symbols * Classes, functions, and constants related to decoding/encoding of symbols
@@ -116,7 +116,7 @@ static const unsigned int CON = 0x1000; //!< marker for a constant value
* @param length the optional variable in which to store the number of read characters. * @param length the optional variable in which to store the number of read characters.
* @return the parsed value. * @return the parsed value.
*/ */
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL); unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length = NULL);
/** /**
* Parse a signed int value. * Parse a signed int value.
@@ -128,7 +128,7 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
* @param length the optional variable in which to store the number of read characters. * @param length the optional variable in which to store the number of read characters.
* @return the parsed value. * @return the parsed value.
*/ */
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length=NULL); int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length = NULL);
/** /**
* Print the error position of the iterator. * Print the error position of the iterator.
@@ -284,7 +284,7 @@ public:
* @param isHex true for hex digits instead of characters. * @param isHex true for hex digits instead of characters.
*/ */
StringDataType(const string id, const unsigned char bitCount, const unsigned short flags, StringDataType(const string id, const unsigned char bitCount, const unsigned short flags,
const unsigned int replacement, bool isHex=false) const unsigned int replacement, bool isHex = false)
: DataType(id, bitCount, flags, replacement), m_isHex(isHex) {} : DataType(id, bitCount, flags, replacement), m_isHex(isHex) {}
/** /**
@@ -494,7 +494,7 @@ public:
*/ */
virtual result_t writeRawValue(unsigned int value, virtual result_t writeRawValue(unsigned int value,
const unsigned char offset, const unsigned char length, const unsigned char offset, const unsigned char length,
SymbolString& output, unsigned char* usedLength=NULL); SymbolString& output, unsigned char* usedLength = NULL);
// @copydoc // @copydoc
virtual result_t writeSymbols(istringstream& input, virtual result_t writeSymbols(istringstream& input,
@@ -575,7 +575,7 @@ public:
* @return the @a DataType instance, or NULL if not available. * @return the @a DataType instance, or NULL if not available.
* Note: the caller may not free the instance. * Note: the caller may not free the instance.
*/ */
DataType* get(const string id, const unsigned char length=0); DataType* get(const string id, const unsigned char length = 0);
private: private:
@@ -599,4 +599,4 @@ private:
}; };
#endif // LIBEBUS_DATATYPE_H_ #endif // LIB_EBUS_DATATYPE_H_
+26 -41
View File
@@ -21,47 +21,44 @@
#endif #endif
#include "device.h" #include "device.h"
#include "data.h"
#include <cstdlib>
#include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <fstream>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <errno.h> #include <errno.h>
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
# include <poll.h> # include <poll.h>
#endif #endif
#include <cstdlib>
#include <cstring>
#include <fstream>
#include "data.h"
using namespace std; using namespace std;
Device::~Device() Device::~Device() {
{
close(); close();
} }
Device* Device::create(const char* name, const bool checkDevice, const bool readOnly, const bool initialSend) Device* Device::create(const char* name, const bool checkDevice, const bool readOnly, const bool initialSend) {
{
if (strchr(name, '/') == NULL && strchr(name, ':') != NULL) { if (strchr(name, '/') == NULL && strchr(name, ':') != NULL) {
char* in = strdup(name); char* in = strdup(name);
bool udp = false; bool udp = false;
char* addrpos = in; char* addrpos = in;
char* portpos = strchr(addrpos, ':'); char* portpos = strchr(addrpos, ':');
if (portpos==addrpos+3 && (strncmp(addrpos, "tcp", 3)==0 || (udp=(strncmp(addrpos, "udp", 3)==0)))) { if (portpos == addrpos+3 && (strncmp(addrpos, "tcp", 3) == 0 || (udp=(strncmp(addrpos, "udp", 3) == 0)))) {
addrpos += 4; addrpos += 4;
portpos = strchr(addrpos, ':'); portpos = strchr(addrpos, ':');
} }
if (portpos==NULL) { if (portpos == NULL) {
free(in); free(in);
return NULL; // invalid protocol or missing port return NULL; // invalid protocol or missing port
} }
result_t result = RESULT_OK; result_t result = RESULT_OK;
unsigned int port = parseInt(portpos+1, 10, 1, 65535, result); unsigned int port = parseInt(portpos+1, 10, 1, 65535, result);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
free(in); free(in);
return NULL; // invalid port return NULL; // invalid port
} }
@@ -84,16 +81,14 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
return new SerialDevice(name, checkDevice, readOnly, initialSend); return new SerialDevice(name, checkDevice, readOnly, initialSend);
} }
void Device::close() void Device::close() {
{
if (m_fd != -1) { if (m_fd != -1) {
::close(m_fd); ::close(m_fd);
m_fd = -1; m_fd = -1;
} }
} }
bool Device::isValid() bool Device::isValid() {
{
if (m_fd == -1) { if (m_fd == -1) {
return false; return false;
} }
@@ -103,8 +98,7 @@ bool Device::isValid()
return m_fd != -1; return m_fd != -1;
} }
result_t Device::send(const unsigned char value) result_t Device::send(const unsigned char value) {
{
if (!isValid()) { if (!isValid()) {
return RESULT_ERR_DEVICE; return RESULT_ERR_DEVICE;
} }
@@ -117,8 +111,7 @@ result_t Device::send(const unsigned char value)
return RESULT_OK; return RESULT_OK;
} }
result_t Device::recv(const long timeout, unsigned char& value) result_t Device::recv(const long timeout, unsigned char& value) {
{
if (!isValid()) { if (!isValid()) {
return RESULT_ERR_DEVICE; return RESULT_ERR_DEVICE;
} }
@@ -175,8 +168,7 @@ result_t Device::recv(const long timeout, unsigned char& value)
} }
result_t SerialDevice::open() result_t SerialDevice::open() {
{
if (m_fd != -1) { if (m_fd != -1) {
close(); close();
} }
@@ -228,8 +220,7 @@ result_t SerialDevice::open()
return RESULT_OK; return RESULT_OK;
} }
void SerialDevice::close() void SerialDevice::close() {
{
if (m_fd != -1) { if (m_fd != -1) {
// empty device buffer // empty device buffer
tcflush(m_fd, TCIOFLUSH); tcflush(m_fd, TCIOFLUSH);
@@ -240,8 +231,7 @@ void SerialDevice::close()
Device::close(); Device::close();
} }
void SerialDevice::checkDevice() void SerialDevice::checkDevice() {
{
int port; int port;
if (ioctl(m_fd, TIOCMGET, &port) == -1) { if (ioctl(m_fd, TIOCMGET, &port) == -1) {
close(); close();
@@ -249,8 +239,7 @@ void SerialDevice::checkDevice()
} }
result_t NetworkDevice::open() result_t NetworkDevice::open() {
{
if (m_fd != -1) { if (m_fd != -1) {
close(); close();
} }
@@ -269,7 +258,7 @@ result_t NetworkDevice::open()
value = 1; value = 1;
setsockopt(m_fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&value, sizeof(value)); setsockopt(m_fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&value, sizeof(value));
} }
if (ret==0) { if (ret == 0) {
ret = connect(m_fd, (struct sockaddr*)&m_address, sizeof(m_address)); ret = connect(m_fd, (struct sockaddr*)&m_address, sizeof(m_address));
} }
if (ret < 0) { if (ret < 0) {
@@ -282,7 +271,7 @@ result_t NetworkDevice::open()
unsigned char buf[256]; unsigned char buf[256];
while (::read(m_fd, &buf, 256) > 0); while (::read(m_fd, &buf, 256) > 0);
} }
if (m_bufSize==0) { if (m_bufSize == 0) {
m_bufSize = MAX_LEN+1; m_bufSize = MAX_LEN+1;
m_buffer = (unsigned char*)malloc(m_bufSize); m_buffer = (unsigned char*)malloc(m_bufSize);
if (!m_buffer) { if (!m_buffer) {
@@ -296,8 +285,7 @@ result_t NetworkDevice::open()
return RESULT_OK; return RESULT_OK;
} }
void NetworkDevice::checkDevice() void NetworkDevice::checkDevice() {
{
unsigned char value; unsigned char value;
ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT); ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT);
if (c == 0 || (c < 0 && errno != EAGAIN)) { if (c == 0 || (c < 0 && errno != EAGAIN)) {
@@ -306,28 +294,25 @@ void NetworkDevice::checkDevice()
} }
} }
bool NetworkDevice::available() bool NetworkDevice::available() {
{ return m_buffer && m_bufLen > 0;
return m_buffer && m_bufLen>0;
} }
ssize_t NetworkDevice::write(const unsigned char value) ssize_t NetworkDevice::write(const unsigned char value) {
{
m_bufLen = 0; // flush read buffer m_bufLen = 0; // flush read buffer
return Device::write(value); return Device::write(value);
} }
ssize_t NetworkDevice::read(unsigned char& value) ssize_t NetworkDevice::read(unsigned char& value) {
{
if (available()) { if (available()) {
value = m_buffer[m_bufPos]; value = m_buffer[m_bufPos];
m_bufPos = (unsigned char)((m_bufPos+1)%m_bufSize); m_bufPos = (unsigned char)((m_bufPos+1)%m_bufSize);
m_bufLen--; m_bufLen--;
return 1; return 1;
} }
if (m_bufSize>0) { if (m_bufSize > 0) {
ssize_t size = ::read(m_fd, m_buffer, m_bufSize); ssize_t size = ::read(m_fd, m_buffer, m_bufSize);
if (size<=0) { if (size <= 0) {
return size; return size;
} }
value = m_buffer[0]; value = m_buffer[0];
+6 -6
View File
@@ -16,15 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_DEVICE_H_ #ifndef LIB_EBUS_DEVICE_H_
#define LIBEBUS_DEVICE_H_ #define LIB_EBUS_DEVICE_H_
#include <unistd.h> #include <unistd.h>
#include <termios.h> #include <termios.h>
#include <iostream>
#include <fstream>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <iostream>
#include <fstream>
#include "result.h" #include "result.h"
/** @file device.h /** @file device.h
@@ -92,7 +92,7 @@ public:
* @return the new @a Device, or NULL on error. * @return the new @a Device, or NULL on error.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static Device* create(const char* name, const bool checkDevice=true, const bool readOnly=false, const bool initialSend=false); static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, const bool initialSend = false);
/** /**
* Get the transfer latency of this device. * Get the transfer latency of this device.
@@ -290,4 +290,4 @@ private:
}; };
#endif // LIBEBUS_DEVICE_H_ #endif // LIB_EBUS_DEVICE_H_
+40 -37
View File
@@ -16,11 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_FILEREADER_H_ #ifndef LIB_EBUS_FILEREADER_H_
#define LIBEBUS_FILEREADER_H_ #define LIB_EBUS_FILEREADER_H_
#include "symbol.h"
#include "result.h"
#include <climits> #include <climits>
#include <string> #include <string>
#include <iostream> #include <iostream>
@@ -28,6 +26,8 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include "symbol.h"
#include "result.h"
/** @file filereader.h /** @file filereader.h
* Helper class and constants for reading configuration files. * Helper class and constants for reading configuration files.
@@ -84,7 +84,7 @@ public:
* @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.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readFromFile(const string filename, bool verbose=false, virtual result_t readFromFile(const string filename, bool verbose = false,
string defaultDest = "", string defaultCircuit = "", string defaultSuffix = "") string defaultDest = "", string defaultCircuit = "", string defaultSuffix = "")
{ {
ifstream ifs; ifstream ifs;
@@ -94,7 +94,7 @@ public:
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
size_t lastSep = filename.find_last_of('/'); size_t lastSep = filename.find_last_of('/');
if (lastSep!=string::npos) { // potential destination address, matches "^ZZ." if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
// extract defaultDest, defaultCircuit, defaultSuffix from filename: // extract defaultDest, defaultCircuit, defaultSuffix from filename:
// ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv // ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv
unsigned char checkDest; unsigned char checkDest;
@@ -114,9 +114,9 @@ public:
vector<string> row; vector<string> row;
vector< vector<string> > defaults; vector< vector<string> > defaults;
while (splitFields(ifs, row, lineNo)) { while (splitFields(ifs, row, lineNo)) {
if (row.empty()) if (row.empty()) {
continue; continue;
}
result_t result; result_t result;
vector<string>::iterator it = row.begin(); vector<string>::iterator it = row.begin();
const vector<string>::iterator end = row.end(); const vector<string>::iterator end = row.end();
@@ -124,31 +124,33 @@ public:
if (row[0][0] == '*') { if (row[0][0] == '*') {
row[0] = row[0].substr(1); row[0] = row[0].substr(1);
result = addDefaultFromFile(defaults, row, it, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo); result = addDefaultFromFile(defaults, row, it, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
if (result == RESULT_OK) if (result == RESULT_OK) {
continue; continue;
} else }
} else {
result = addFromFile(it, end, &defaults, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo); result = addFromFile(it, end, &defaults, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
} }
else } else {
result = addFromFile(it, end, NULL, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo); result = addFromFile(it, end, NULL, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
}
if (result != RESULT_OK) { if (result != RESULT_OK) {
if (!verbose) { if (!verbose) {
ifs.close(); ifs.close();
ostringstream error; ostringstream error;
error << filename << ":" << static_cast<unsigned>(lineNo); error << filename << ":" << static_cast<unsigned>(lineNo);
if (m_lastError.length()>0) { if (m_lastError.length() > 0) {
error << ": " << m_lastError; error << ": " << m_lastError;
} }
m_lastError = error.str(); m_lastError = error.str();
return result; return result;
} }
if (m_lastError.length()>0) { if (m_lastError.length() > 0) {
cout << m_lastError << endl; cout << m_lastError << endl;
} }
printErrorPos(cout, row.begin(), end, it, filename, lineNo, result); printErrorPos(cout, row.begin(), end, it, filename, lineNo, result);
} else if (!verbose) } else if (!verbose) {
m_lastError = ""; m_lastError = "";
}
} }
ifs.close(); ifs.close();
@@ -205,11 +207,11 @@ public:
static void trim(string& str) static void trim(string& str)
{ {
size_t pos = str.find_first_not_of(" \t"); size_t pos = str.find_first_not_of(" \t");
if (pos!=string::npos) { if (pos != string::npos) {
str.erase(0, pos); str.erase(0, pos);
} }
pos = str.find_last_not_of(" \t"); pos = str.find_last_not_of(" \t");
if (pos!=string::npos) { if (pos != string::npos) {
str.erase(pos+1); str.erase(pos+1);
} }
} }
@@ -244,9 +246,9 @@ public:
trim(line); trim(line);
size_t length = line.length(); size_t length = line.length();
if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) {
continue; // skip empty lines and comments continue; // skip empty lines and comments
}
for (size_t pos = 0; pos < length; pos++) { for (size_t pos = 0; pos < length; pos++) {
char ch = line[pos]; char ch = line[pos];
switch (ch) switch (ch)
@@ -278,10 +280,10 @@ public:
case '\r': case '\r':
break; break;
default: default:
if (prev==TEXT_SEPARATOR && !quotedText && wasQuoted) { if (prev == TEXT_SEPARATOR && !quotedText && wasQuoted) {
field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text field << TEXT_SEPARATOR; // single dquote in the middle of formerly quoted text
quotedText = true; quotedText = true;
} else if (quotedText && pos==0 && field.tellp()>0 && *(field.str().end()-1)!=VALUE_SEPARATOR) { } else if (quotedText && pos == 0 && field.tellp() > 0 && *(field.str().end()-1) != VALUE_SEPARATOR) {
field << VALUE_SEPARATOR; field << VALUE_SEPARATOR;
} }
field << ch; field << ch;
@@ -289,8 +291,9 @@ public:
} }
prev = ch; prev = ch;
} }
if (!quotedText) if (!quotedText) {
break; break;
}
} }
string str = field.str(); string str = field.str();
trim(str); trim(str);
@@ -318,51 +321,51 @@ public:
{ {
ident = circuit = suffix = ""; ident = circuit = suffix = "";
software = hardware = UINT_MAX; software = hardware = UINT_MAX;
if (name.length()>4 && name.substr(name.length()-4)==".csv") { if (name.length() > 4 && name.substr(name.length()-4) == ".csv") {
name = name.substr(0, name.length()-3); // including trailing "." name = name.substr(0, name.length()-3); // including trailing "."
} }
size_t pos = name.find('.'); size_t pos = name.find('.');
if (pos!=2) { if (pos != 2) {
return false; // missing "ZZ." return false; // missing "ZZ."
} }
result_t result = RESULT_OK; result_t result = RESULT_OK;
dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL); dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL);
if (result!=RESULT_OK || !isValidAddress(dest)) { if (result != RESULT_OK || !isValidAddress(dest)) {
return false; // invalid "ZZ" return false; // invalid "ZZ"
} }
name.erase(0, pos); name.erase(0, pos);
if (name.length()>1) { if (name.length() > 1) {
pos = name.rfind(".SW"); // check for ".SWxxxx." pos = name.rfind(".SW"); // check for ".SWxxxx."
if (pos!=string::npos && name.find(".", pos+1)==pos+7) { if (pos != string::npos && name.find(".", pos+1) == pos+7) {
software = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL); software = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
return false; // invalid "SWxxxx" return false; // invalid "SWxxxx"
} }
name.erase(pos, 7); name.erase(pos, 7);
} }
} }
if (name.length()>1) { if (name.length() > 1) {
pos = name.rfind(".HW"); // check for ".HWxxxx." pos = name.rfind(".HW"); // check for ".HWxxxx."
if (pos!=string::npos && name.find(".", pos+1)==pos+7) { if (pos != string::npos && name.find(".", pos+1) == pos+7) {
hardware = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL); hardware = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
if (result!=RESULT_OK) { if (result != RESULT_OK) {
return false; // invalid "HWxxxx" return false; // invalid "HWxxxx"
} }
name.erase(pos, 7); name.erase(pos, 7);
} }
} }
if (name.length()>1) { if (name.length() > 1) {
pos = name.find('.', 1); // check for ".IDENT." pos = name.find('.', 1); // check for ".IDENT."
if (pos!=string::npos && pos>=1 && pos<=6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".." if (pos != string::npos && pos >= 1 && pos <= 6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".."
ident = circuit = name.substr(1, pos-1); ident = circuit = name.substr(1, pos-1);
name.erase(0, pos); name.erase(0, pos);
pos = name.find('.', 1); // check for ".CIRCUIT." pos = name.find('.', 1); // check for ".CIRCUIT."
if (pos!=string::npos && (pos>2 || name[1]<'0' || name[1]>'9')) { if (pos != string::npos && (pos>2 || name[1]<'0' || name[1]>'9')) {
circuit = name.substr(1, pos-1); circuit = name.substr(1, pos-1);
name.erase(0, pos); name.erase(0, pos);
pos = name.find('.', 1); // check for ".SUFFIX." pos = name.find('.', 1); // check for ".SUFFIX."
} }
if (pos!=string::npos && pos==2 && name[1]>='0' && name[1]<='9') { if (pos != string::npos && pos == 2 && name[1] >= '0' && name[1] <= '9') {
suffix = name.substr(0, 2); suffix = name.substr(0, 2);
name.erase(0, pos); name.erase(0, pos);
} }
@@ -383,4 +386,4 @@ protected:
}; };
#endif // LIBEBUS_FILEREADER_H_ #endif // LIB_EBUS_FILEREADER_H_
+466 -437
View File
File diff suppressed because it is too large Load Diff
+52 -50
View File
@@ -16,16 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_MESSAGE_H_ #ifndef LIB_EBUS_MESSAGE_H_
#define LIBEBUS_MESSAGE_H_ #define LIB_EBUS_MESSAGE_H_
#include "data.h"
#include "result.h"
#include "symbol.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <map> #include <map>
#include <queue>
#include <functional>
#include "data.h"
#include "result.h"
#include "symbol.h"
/** @file message.h /** @file message.h
* Classes and functions for decoding and encoding of complete messages on the * Classes and functions for decoding and encoding of complete messages on the
@@ -117,8 +119,8 @@ public:
const unsigned char srcAddress, const unsigned char dstAddress, const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, const vector<unsigned char> id,
DataField* data, const bool deleteData, DataField* data, const bool deleteData,
const unsigned char pollPriority=0, const unsigned char pollPriority = 0,
Condition* condition=NULL); Condition* condition = NULL);
private: private:
/** /**
@@ -142,7 +144,7 @@ public:
/** /**
* Destructor. * Destructor.
*/ */
virtual ~Message() { if (m_deleteData) delete m_data; } virtual ~Message() { if (m_deleteData) { delete m_data; } }
/** /**
* Calculate the key for the ID. * Calculate the key for the ID.
@@ -166,7 +168,7 @@ public:
* @return the key for the ID, or -1LL if the data is invalid. * @return the key for the ID, or -1LL if the data is invalid.
*/ */
static unsigned long long createKey(SymbolString& master, static unsigned long long createKey(SymbolString& master,
unsigned char maxIdLength, bool anyDestination=false); unsigned char maxIdLength, bool anyDestination = false);
/** /**
* Get the length field from the key. * Get the length field from the key.
@@ -222,7 +224,7 @@ public:
* @param circuit the new circuit name, or empty to use the current circuit name. * @param circuit the new circuit name, or empty to use the current circuit name.
* @return the derived @a Message instance. * @return the derived @a Message instance.
*/ */
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress=SYN, const string circuit=""); virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
/** /**
* Derive a new @a Message from this message. * Derive a new @a Message from this message.
@@ -313,7 +315,7 @@ public:
* @param index the variable in which to store the message part index, or NULL to ignore. * @param index the variable in which to store the message part index, or NULL to ignore.
* @return true if the ID matches, false otherwise. * @return true if the ID matches, false otherwise.
*/ */
virtual bool checkId(SymbolString& master, unsigned char* index=NULL); virtual bool checkId(SymbolString& master, unsigned char* index = NULL);
/** /**
* Check the ID against the other @a Message. * Check the ID against the other @a Message.
@@ -357,7 +359,7 @@ public:
* Return whether this @a Message depends on a @a Condition. * Return whether this @a Message depends on a @a Condition.
* @return true when this @a Message depends on a @a Condition. * @return true when this @a Message depends on a @a Condition.
*/ */
bool isConditional() const { return m_condition!=NULL; } bool isConditional() const { return m_condition != NULL; }
/** /**
* Return whether this @a Message is available (optionally depending on a @a Condition evaluation). * Return whether this @a Message is available (optionally depending on a @a Condition evaluation).
@@ -371,7 +373,7 @@ public:
* @param numeric true for a numeric field, false for a string field. * @param numeric true for a numeric field, false for a string field.
* @return true if the field is available. * @return true if the field is available.
*/ */
bool hasField(const char* fieldName, bool numeric=true); bool hasField(const char* fieldName, bool numeric = true);
/** /**
* @return the number of parts this message is composed of. * @return the number of parts this message is composed of.
@@ -389,8 +391,8 @@ public:
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData, result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData,
istringstream& input, char separator=UI_FIELD_SEPARATOR, istringstream& input, char separator = UI_FIELD_SEPARATOR,
const unsigned char dstAddress=SYN, unsigned char index=0); const unsigned char dstAddress = SYN, unsigned char index = 0);
protected: protected:
@@ -442,8 +444,8 @@ public:
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastData(const PartType partType, virtual result_t decodeLastData(const PartType partType,
ostringstream& output, OutputFormat outputFormat=0, ostringstream& output, OutputFormat outputFormat = 0,
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1); bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
/** /**
* Decode the value from the last stored data. * Decode the value from the last stored data.
@@ -454,8 +456,8 @@ public:
* @param fieldIndex the optional index of the named field to limit the output to, or -1. * @param fieldIndex the optional index of the named field to limit the output to, or -1.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat=0, virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat = 0,
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1); bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
/** /**
* Decode a particular numeric field value from the last stored data. * Decode a particular numeric field value from the last stored data.
@@ -464,7 +466,7 @@ public:
* @param fieldIndex the optional index of the named field, or -1. * @param fieldIndex the optional index of the named field, or -1.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastDataNumField(unsigned int& output, const char* fieldName, signed char fieldIndex=-1); virtual result_t decodeLastDataNumField(unsigned int& output, const char* fieldName, signed char fieldIndex = -1);
/** /**
* Get the last seen master data. * Get the last seen master data.
@@ -509,7 +511,7 @@ public:
* @param columns the list of column indexes to write, or NULL for all (see @p COLUMN_TYPE index constants). * @param columns the list of column indexes to write, or NULL for all (see @p COLUMN_TYPE index constants).
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
*/ */
void dump(ostream& output, vector<size_t>* columns=NULL, bool withConditions=false); void dump(ostream& output, vector<size_t>* columns = NULL, bool withConditions = false);
/** /**
* Write the specified column to the @a ostream. * Write the specified column to the @a ostream.
@@ -517,7 +519,7 @@ public:
* @param column the column index to write (see @p COLUMN_TYPE index constants). * @param column the column index to write (see @p COLUMN_TYPE index constants).
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
*/ */
virtual void dumpColumn(ostream& output, size_t column, bool withConditions=false); virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
protected: protected:
@@ -638,18 +640,18 @@ public:
vector< vector<unsigned char> > ids, vector<unsigned char> lengths, vector< vector<unsigned char> > ids, vector<unsigned char> lengths,
DataField* data, const bool deleteData, DataField* data, const bool deleteData,
const unsigned char pollPriority, const unsigned char pollPriority,
Condition* condition=NULL); Condition* condition = NULL);
virtual ~ChainedMessage(); virtual ~ChainedMessage();
// @copydoc // @copydoc
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress=SYN, const string circuit=""); virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
// @copydoc // @copydoc
virtual unsigned char getIdLength() const { return (unsigned char)(m_ids[0].size() - 2); } virtual unsigned char getIdLength() const { return (unsigned char)(m_ids[0].size() - 2); }
// @copydoc // @copydoc
virtual bool checkId(SymbolString& master, unsigned char* index=NULL); virtual bool checkId(SymbolString& master, unsigned char* index = NULL);
// @copydoc // @copydoc
virtual bool checkId(Message& other); virtual bool checkId(Message& other);
@@ -673,7 +675,7 @@ public:
protected: protected:
// @copydoc // @copydoc
virtual void dumpColumn(ostream& output, size_t column, bool withConditions=false); virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
private: private:
@@ -729,7 +731,7 @@ public:
void push(const value_type& __x) void push(const value_type& __x)
{ {
for (vector<Message*>::iterator it = c.begin(); it != c.end(); it++) { for (vector<Message*>::iterator it = c.begin(); it != c.end(); it++) {
if (*it==__x) { if (*it == __x) {
c.erase(it); c.erase(it);
break; break;
} }
@@ -781,7 +783,7 @@ public:
* @param output the @a ostream to append to. * @param output the @a ostream to append to.
* @param matched true for dumping the matched value if the condition is true, false for dumping the definition. * @param matched true for dumping the matched value if the condition is true, false for dumping the definition.
*/ */
virtual void dump(ostream& output, bool matched=false) = 0; virtual void dump(ostream& output, bool matched = false) = 0;
/** /**
* Combine this condition with another instance using a logical and. * Combine this condition with another instance using a logical and.
@@ -797,7 +799,7 @@ public:
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL. * @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL) = 0; virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL) = 0;
/** /**
* Check and return whether this condition is fulfilled. * Check and return whether this condition is fulfilled.
@@ -833,7 +835,7 @@ public:
* @param field the field name. * @param field the field name.
* @param hasValues whether a value has to be checked against. * @param hasValues whether a value has to be checked against.
*/ */
SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues=false) SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues = false)
: Condition(), : Condition(),
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { } m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
@@ -846,13 +848,13 @@ public:
virtual SimpleCondition* derive(string valueList); virtual SimpleCondition* derive(string valueList);
// @copydoc // @copydoc
virtual void dump(ostream& output, bool matched=false); virtual void dump(ostream& output, bool matched = false);
// @copydoc // @copydoc
virtual CombinedCondition* combineAnd(Condition* other); virtual CombinedCondition* combineAnd(Condition* other);
// @copydoc // @copydoc
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL); virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
// @copydoc // @copydoc
virtual bool isTrue(); virtual bool isTrue();
@@ -1005,13 +1007,13 @@ public:
virtual ~CombinedCondition() {} virtual ~CombinedCondition() {}
// @copydoc // @copydoc
virtual void dump(ostream& output, bool matched=false); virtual void dump(ostream& output, bool matched = false);
// @copydoc // @copydoc
virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; } virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; }
// @copydoc // @copydoc
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL); virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
// @copydoc // @copydoc
virtual bool isTrue(); virtual bool isTrue();
@@ -1158,7 +1160,7 @@ public:
* Construct a new instance. * Construct a new instance.
* @param addAll whether to add all messages, even if duplicate. * @param addAll whether to add all messages, even if duplicate.
*/ */
MessageMap(const bool addAll=false) : FileReader::FileReader(true), MessageMap(const bool addAll = false) : FileReader::FileReader(true),
m_addAll(addAll), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) m_addAll(addAll), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0)
{ {
m_scanMessage = Message::createScanMessage(); m_scanMessage = Message::createScanMessage();
@@ -1179,7 +1181,7 @@ public:
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success. * Note: the caller may not free the added instance on success.
*/ */
result_t add(Message* message, bool storeByName=true); result_t add(Message* message, bool storeByName = true);
// @copydoc // @copydoc
virtual result_t addDefaultFromFile(vector< vector<string> >& defaults, vector<string>& row, virtual result_t addDefaultFromFile(vector< vector<string> >& defaults, vector<string>& row,
@@ -1205,14 +1207,14 @@ public:
* @param dstAddress the destination address, or @a SYN for the base scan @a Message. * @param dstAddress the destination address, or @a SYN for the base scan @a Message.
* @return the scan @a Message instance, or NULL if the dstAddress is no slave. * @return the scan @a Message instance, or NULL if the dstAddress is no slave.
*/ */
Message* getScanMessage(const unsigned char dstAddress=SYN); Message* getScanMessage(const unsigned char dstAddress = SYN);
/** /**
* Resolve all @a Condition instances. * Resolve all @a Condition instances.
* @param verbose whether to verbosely add all problems to the error message. * @param verbose whether to verbosely add all problems to the error message.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t resolveConditions(bool verbose=false); result_t resolveConditions(bool verbose = false);
/** /**
* Resolve a @a Condition. * Resolve a @a Condition.
@@ -1220,7 +1222,7 @@ public:
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL. * @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t resolveCondition(Condition* condition, void (*readMessageFunc)(Message* message)=NULL); result_t resolveCondition(Condition* condition, void (*readMessageFunc)(Message* message) = NULL);
/** /**
* Run all executable @a Instruction instances. * Run all executable @a Instruction instances.
@@ -1229,7 +1231,7 @@ public:
* @a Message values from the bus required for singleton instructions, or NULL. * @a Message values from the bus required for singleton instructions, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t executeInstructions(ostringstream& log, void (*readMessageFunc)(Message* message)=NULL); result_t executeInstructions(ostringstream& log, void (*readMessageFunc)(Message* message) = NULL);
/** /**
* Add a loaded file to a participant. * Add a loaded file to a participant.
@@ -1263,7 +1265,7 @@ public:
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
Message* find(const string& circuit, const string& name, const bool isWrite, const bool isPassive=false); Message* find(const string& circuit, const string& name, const bool isWrite, const bool isPassive = false);
/** /**
* Find all active get @a Message instances for the specified circuit and name. * Find all active get @a Message instances for the specified circuit and name.
@@ -1280,10 +1282,10 @@ public:
* @param until the end time to which to add updates (exclusive, also removes messages with unset destination address), or 0 to ignore. * @param until the end time to which to add updates (exclusive, also removes messages with unset destination address), or 0 to ignore.
* Note: the caller may not free the returned instances. * Note: the caller may not free the returned instances.
*/ */
deque<Message*> findAll(const string& circuit, const string& name, const bool completeMatch=true, deque<Message*> findAll(const string& circuit, const string& name, const bool completeMatch = true,
const bool withRead=true, const bool withWrite=false, const bool withPassive=false, const bool withRead = true, const bool withWrite = false, const bool withPassive = false,
const bool completeMatchIgnoreCircuitSuffix=false, const bool onlyAvailable=true, const bool completeMatchIgnoreCircuitSuffix = false, const bool onlyAvailable = true,
const time_t since=0, const time_t until=0); const time_t since = 0, const time_t until = 0);
/** /**
* Find the @a Message instance for the specified master data. * Find the @a Message instance for the specified master data.
@@ -1295,8 +1297,8 @@ public:
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
Message* find(SymbolString& master, bool anyDestination=false, Message* find(SymbolString& master, bool anyDestination = false,
const bool withRead=true, const bool withWrite=true, const bool withPassive=true); const bool withRead = true, const bool withWrite = true, const bool withPassive = true);
/** /**
* Invalidate cached data of the @a Message and all other instances with a matching name key. * Invalidate cached data of the @a Message and all other instances with a matching name key.
@@ -1309,7 +1311,7 @@ public:
* @param message the @a Message to poll. * @param message the @a Message to poll.
* @param toFront whether to add the @a Message to the very front of the poll queue. * @param toFront whether to add the @a Message to the very front of the poll queue.
*/ */
void addPollMessage(Message* message, bool toFront=false); void addPollMessage(Message* message, bool toFront = false);
/** /**
* Removes all @a Message instances. * Removes all @a Message instances.
@@ -1364,7 +1366,7 @@ public:
* @param output the @a ostream to append the formatted messages to. * @param output the @a ostream to append the formatted messages to.
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
*/ */
void dump(ostream& output, bool withConditions=false); void dump(ostream& output, bool withConditions = false);
private: private:
@@ -1406,4 +1408,4 @@ private:
}; };
#endif // LIBEBUS_MESSAGE_H_ #endif // LIB_EBUS_MESSAGE_H_
+2 -1
View File
@@ -51,8 +51,9 @@ const char* getResultCode(result_t resultCode) {
case RESULT_ERR_SYN: return "ERR: SYN received"; case RESULT_ERR_SYN: return "ERR: SYN received";
default: default:
if (resultCode >= 0) if (resultCode >= 0) {
return "done: unknown result code"; return "done: unknown result code";
}
return "ERR: unknown result code"; return "ERR: unknown result code";
} }
} }
+3 -3
View File
@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_RESULT_H_ #ifndef LIB_EBUS_RESULT_H_
#define LIBEBUS_RESULT_H_ #define LIB_EBUS_RESULT_H_
/** @file result.h /** @file result.h
* Functions, and constants related to execution results. * Functions, and constants related to execution results.
@@ -70,4 +70,4 @@ enum result_t {
*/ */
const char* getResultCode(result_t resultCode); const char* getResultCode(result_t resultCode);
#endif // LIBEBUS_RESULT_H_ #endif // LIB_EBUS_RESULT_H_
+12 -14
View File
@@ -17,9 +17,11 @@
*/ */
#include "symbol.h" #include "symbol.h"
#include "result.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <string>
#include <vector>
#include "result.h"
using namespace std; using namespace std;
@@ -47,13 +49,12 @@ static const unsigned char CRC_LOOKUP_TABLE[] =
}; };
void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol) void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol) {
{
bool addCrc = m_unescapeState == 0; bool addCrc = m_unescapeState == 0;
bool isEscaped = str.m_unescapeState == 0; bool isEscaped = str.m_unescapeState == 0;
vector<unsigned char> data = str.m_data; vector<unsigned char> data = str.m_data;
size_t end = data.size(); size_t end = data.size();
if (end>0 && skipLastSymbol) { if (end > 0 && skipLastSymbol) {
end--; end--;
} }
for (size_t i = 0; i < end; i++) { for (size_t i = 0; i < end; i++) {
@@ -64,8 +65,7 @@ void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol)
} }
} }
result_t SymbolString::parseHex(const string& str, const bool isEscaped) result_t SymbolString::parseHex(const string& str, const bool isEscaped) {
{
bool addCrc = m_unescapeState == 0; bool addCrc = m_unescapeState == 0;
for (size_t i = 0; i < str.size(); i += 2) { for (size_t i = 0; i < str.size(); i += 2) {
char* strEnd = NULL; char* strEnd = NULL;
@@ -83,8 +83,7 @@ result_t SymbolString::parseHex(const string& str, const bool isEscaped)
return RESULT_OK; return RESULT_OK;
} }
const string SymbolString::getDataStr(const bool unescape, const bool skipLastSymbol) const string SymbolString::getDataStr(const bool unescape, const bool skipLastSymbol) {
{
stringstream sstr; stringstream sstr;
bool previousEscape = false; bool previousEscape = false;
@@ -111,8 +110,7 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
return sstr.str(); return sstr.str();
} }
result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) {
{
if (m_unescapeState == 0) { // store escaped data if (m_unescapeState == 0) { // store escaped data
if (!isEscaped && value == ESC) { if (!isEscaped && value == ESC) {
m_data.push_back(ESC); m_data.push_back(ESC);
@@ -214,8 +212,8 @@ unsigned char getMasterPartIndex(unsigned char bits) {
} }
bool isMaster(unsigned char addr) { bool isMaster(unsigned char addr) {
return getMasterPartIndex(addr & 0x0F)>0 return getMasterPartIndex(addr & 0x0F) > 0
&& getMasterPartIndex((addr & 0xF0) >> 4)>0; && getMasterPartIndex((addr & 0xF0)>>4) > 0;
} }
bool isSlaveMaster(unsigned char addr) { bool isSlaveMaster(unsigned char addr) {
@@ -245,11 +243,11 @@ unsigned char getMasterAddress(unsigned char addr) {
unsigned char getMasterNumber(unsigned char addr) { unsigned char getMasterNumber(unsigned char addr) {
unsigned char priority = getMasterPartIndex(addr & 0x0F); unsigned char priority = getMasterPartIndex(addr & 0x0F);
if (priority==0) { if (priority == 0) {
return 0; return 0;
} }
unsigned char index = getMasterPartIndex((addr & 0xF0) >> 4); unsigned char index = getMasterPartIndex((addr & 0xF0) >> 4);
if (index==0) { if (index == 0) {
return 0; return 0;
} }
return (unsigned char)(5*(priority-1) + index); return (unsigned char)(5*(priority-1) + index);
+30 -20
View File
@@ -16,14 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBEBUS_SYMBOL_H_ #ifndef LIB_EBUS_SYMBOL_H_
#define LIBEBUS_SYMBOL_H_ #define LIB_EBUS_SYMBOL_H_
#include "result.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include <queue> #include <queue>
#include <string>
#include <vector>
#include "result.h"
using namespace std;
/** @file symbol.h /** @file symbol.h
* Classes, functions, and constants related to symbols on the eBUS. * Classes, functions, and constants related to symbols on the eBUS.
@@ -61,8 +65,6 @@
* non-acknowledge, the receiving slave has to repeat its data once. * non-acknowledge, the receiving slave has to repeat its data once.
*/ */
using namespace std;
static const unsigned char ESC = 0xA9; //!< escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA static const unsigned char ESC = 0xA9; //!< escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA
static const unsigned char SYN = 0xAA; //!< synchronization symbol static const unsigned char SYN = 0xAA; //!< synchronization symbol
static const unsigned char ACK = 0x00; //!< positive acknowledge static const unsigned char ACK = 0x00; //!< positive acknowledge
@@ -81,14 +83,14 @@ public:
* Creates a new empty escaped or unescaped instance. * Creates a new empty escaped or unescaped instance.
* @param escaped whether to create an escaped instance. * @param escaped whether to create an escaped instance.
*/ */
SymbolString(const bool escaped=true) : m_unescapeState(escaped ? 0 : 1), m_crc(0) {} SymbolString(const bool escaped = true) : m_unescapeState(escaped ? 0 : 1), m_crc(0) {}
/** /**
* Add all symbols from the other @a SymbolString and the calculated CRC if escaped. * Add all symbols from the other @a SymbolString and the calculated CRC if escaped.
* @param str the @a SymbolString to copy from. * @param str the @a SymbolString to copy from.
* @param skipLastSymbol whether to skip the last symbol (probably the CRC). * @param skipLastSymbol whether to skip the last symbol (probably the CRC).
*/ */
void addAll(const SymbolString& str, const bool skipLastSymbol=false); void addAll(const SymbolString& str, const bool skipLastSymbol = false);
/** /**
* Parse the escaped or unescaped hex @a string, add all symbols, and add the calculated CRC if escaped. * Parse the escaped or unescaped hex @a string, add all symbols, and add the calculated CRC if escaped.
@@ -96,7 +98,7 @@ public:
* @param isEscaped whether the hex string is escaped. * @param isEscaped whether the hex string is escaped.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t parseHex(const string& str, const bool isEscaped=false); result_t parseHex(const string& str, const bool isEscaped = false);
/** /**
* Return the symbols as hex string. * Return the symbols as hex string.
@@ -104,28 +106,28 @@ public:
* @param skipLastSymbol whether to skip the last symbol (probably the CRC). * @param skipLastSymbol whether to skip the last symbol (probably the CRC).
* @return the symbols as hex string. * @return the symbols as hex string.
*/ */
const string getDataStr(const bool unescape=true, const bool skipLastSymbol=true); const string getDataStr(const bool unescape = true, const bool skipLastSymbol = true);
/** /**
* Return a reference to the symbol at the specified index. * Return a reference to the symbol at the specified index.
* @param index the index of the symbol to return. * @param index the index of the symbol to return.
* @return the reference to the symbol at the specified index. * @return the reference to the symbol at the specified index.
*/ */
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) m_data.resize(index+1, 0); return m_data[index]; } unsigned char& operator[](const size_t index) { if (index >= m_data.size()) { m_data.resize(index+1, 0); } return m_data[index]; }
/** /**
* Return whether this instance is equal to the other instance. * Return whether this instance is equal to the other instance.
* @param other the other instance. * @param other the other instance.
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols). * @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols).
*/ */
bool operator==(SymbolString& other) { return m_unescapeState==other.m_unescapeState && m_data==other.m_data; } bool operator == (SymbolString& other) { return m_unescapeState == other.m_unescapeState && m_data == other.m_data; }
/** /**
* Return whether this instance is different from the other instance. * Return whether this instance is different from the other instance.
* @param other the other instance. * @param other the other instance.
* @return true if this instance is different from the other instance. * @return true if this instance is different from the other instance.
*/ */
bool operator!=(SymbolString& other) { return m_unescapeState!=other.m_unescapeState || m_data!=other.m_data; } bool operator != (SymbolString& other) { return m_unescapeState != other.m_unescapeState || m_data != other.m_data; }
/** /**
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master address and ending with the CRC). * Compares this instance to the other instance while treating both as master data (i.e. starting with the master address and ending with the CRC).
@@ -135,10 +137,18 @@ public:
* 2 if this instance only differs from the other instance in the first byte (the master address). * 2 if this instance only differs from the other instance in the first byte (the master address).
*/ */
int compareMaster(SymbolString& other) { int compareMaster(SymbolString& other) {
if (m_unescapeState!=other.m_unescapeState || m_data.size()!=other.m_data.size()) return 1; if (m_unescapeState != other.m_unescapeState || m_data.size() != other.m_data.size()) {
if (m_data==other.m_data) return 0; return 1;
if (m_data.size()==1) return 2; }
if (equal(m_data.begin()+1, m_data.end()-1, other.m_data.begin()+1)) return 2; if (m_data == other.m_data) {
return 0;
}
if (m_data.size() == 1) {
return 2;
}
if (equal(m_data.begin()+1, m_data.end()-1, other.m_data.begin()+1)) {
return 2;
}
return 1; return 1;
} }
@@ -151,7 +161,7 @@ public:
* RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received, * RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was received,
* RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected. * RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected.
*/ */
result_t push_back(const unsigned char value, const bool isEscaped=true, const bool updateCRC=true); result_t push_back(const unsigned char value, const bool isEscaped = true, const bool updateCRC = true);
/** /**
* Return the number of symbols in this symbol string. * Return the number of symbols in this symbol string.
@@ -168,7 +178,7 @@ public:
/** /**
* Clear the symbols. * Clear the symbols.
*/ */
void clear() { m_data.clear(); m_unescapeState = m_unescapeState==0 ? 0 : 1; m_crc = 0; } void clear() { m_data.clear(); m_unescapeState = m_unescapeState == 0 ? 0 : 1; m_crc = 0; }
/** /**
* Clear the symbols and adjust the escape mode. * Clear the symbols and adjust the escape mode.
@@ -247,6 +257,6 @@ unsigned char getMasterNumber(unsigned char addr);
* @param allowBroadcast whether to also allow @a addr to be the broadcast address (default true). * @param allowBroadcast whether to also allow @a addr to be the broadcast address (default true).
* @return <code>true</code> if the specified address is a valid bus address. * @return <code>true</code> if the specified address is a valid bus address.
*/ */
bool isValidAddress(unsigned char addr, bool allowBroadcast=true); bool isValidAddress(unsigned char addr, bool allowBroadcast = true);
#endif // LIBEBUS_SYMBOL_H_ #endif // LIB_EBUS_SYMBOL_H_
+19 -20
View File
@@ -16,17 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "data.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <string>
#include <vector>
#include "data.h"
using namespace std; using namespace std;
static bool error = false; static bool error = false;
void verify(bool expectFailMatch, string type, string input, void verify(bool expectFailMatch, string type, string input,
bool match, string expectStr, string gotStr) bool match, string expectStr, string gotStr) {
{
match = match && expectStr == gotStr; match = match && expectStr == gotStr;
if (expectFailMatch) { if (expectFailMatch) {
if (match) { if (match) {
@@ -45,8 +46,7 @@ void verify(bool expectFailMatch, string type, string input,
} }
} }
int main() int main() {
{
string checks[][5] = { string checks[][5] = {
// entry: definition, decoded value, master data, slave data, flags // entry: definition, decoded value, master data, slave data, flags
// definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] // definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
@@ -63,9 +63,9 @@ int main()
{"x,,str:*", "abcde", "10fe0700056162636465", "00", ""}, {"x,,str:*", "abcde", "10fe0700056162636465", "00", ""},
{"x,,str,2", "", "", "", "c"}, {"x,,str,2", "", "", "", "c"},
{"x,,str:10,=dummy", "", "10fe07000a48616c6c6f2044752120", "00", "W"}, {"x,,str:10,=dummy", "", "10fe07000a48616c6c6f2044752120", "00", "W"},
{"x,,str:10,==dummy", "", "10fe07000a48616c6c6f2044752120", "00", "rW"}, {"x,,str:10, == dummy", "", "10fe07000a48616c6c6f2044752120", "00", "rW"},
{"x,,str:10,=dummy", "", "10fe07000a64756d6d792020202020", "00", ""}, {"x,,str:10,=dummy", "", "10fe07000a64756d6d792020202020", "00", ""},
{"x,,str:10,==dummy", "", "10fe07000a64756d6d792020202020", "00", ""}, {"x,,str:10, == dummy", "", "10fe07000a64756d6d792020202020", "00", ""},
{"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, {"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, {"x,,nts:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x,,nts:10", "Hallo, Du", "10fe07000a48616c6c6f2c20447500", "00", ""}, {"x,,nts:10", "Hallo, Du", "10fe07000a48616c6c6f2c20447500", "00", ""},
@@ -83,9 +83,9 @@ int main()
{"x,,hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, {"x,,hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"},
{"x,,hex,2", "", "", "", "c"}, {"x,,hex,2", "", "", "", "c"},
{"x,,hex:5,=48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "W"}, {"x,,hex:5,=48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "W"},
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"}, {"x,,hex:5, == 48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"},
{"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""}, {"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""}, {"x,,hex:5, == 48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
{"x,,bda", "26.10.2014","10fe07000426100614", "00", ""}, // Sunday {"x,,bda", "26.10.2014","10fe07000426100614", "00", ""}, // Sunday
{"x,,bda", "01.01.2000","10fe07000401010500", "00", ""}, // Saturday {"x,,bda", "01.01.2000","10fe07000401010500", "00", ""}, // Saturday
{"x,,bda", "31.12.2099","10fe07000431120399", "00", ""}, // Thursday {"x,,bda", "31.12.2099","10fe07000431120399", "00", ""}, // Thursday
@@ -264,9 +264,9 @@ int main()
{"x,,uch,10", "3.8", "10feffff0126", "00", ""}, {"x,,uch,10", "3.8", "10feffff0126", "00", ""},
{"x,,uch,-10", "380","10feffff0126", "00", ""}, {"x,,uch,-10", "380","10feffff0126", "00", ""},
{"x,,uch,=48", "", "10feffff01ab", "00", "W"}, {"x,,uch,=48", "", "10feffff01ab", "00", "W"},
{"x,,uch,==48", "", "10feffff01ab", "00", "rW"}, {"x,,uch, == 48", "", "10feffff01ab", "00", "rW"},
{"x,,uch,=48", "", "10feffff0130", "00", ""}, {"x,,uch,=48", "", "10feffff0130", "00", ""},
{"x,,uch,==48", "", "10feffff0130", "00", ""}, {"x,,uch, == 48", "", "10feffff0130", "00", ""},
{"x,,sch", "-90", "10feffff01a6", "00", ""}, {"x,,sch", "-90", "10feffff01a6", "00", ""},
{"x,,sch", "0", "10feffff0100", "00", ""}, {"x,,sch", "0", "10feffff0100", "00", ""},
{"x,,sch", "-1", "10feffff01ff", "00", ""}, {"x,,sch", "-1", "10feffff01ff", "00", ""},
@@ -510,7 +510,7 @@ int main()
fields = NULL; fields = NULL;
} }
vector<string>::iterator it = entries.begin(); vector<string>::iterator it = entries.begin();
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1]==BROADCAST || isMaster(mstr[1]))); result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
if (failedCreate) { if (failedCreate) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
@@ -568,7 +568,7 @@ int main()
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, !output.str().empty()); result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, !output.str().empty());
} }
if (failedRead) if (failedRead) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
@@ -577,21 +577,21 @@ int main()
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< OK" << endl; << "< OK" << endl;
} }
else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " read " << fields->getName() << " >" << check[2] << " " << check[3]
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} } else {
else {
bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0; bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0;
verify(failedReadMatch, "read", check[2], match, expectStr, output.str()); verify(failedReadMatch, "read", check[2], match, expectStr, output.str());
} }
if (verbosity==0) { if (verbosity == 0) {
istringstream input(expectStr); istringstream input(expectStr);
result = fields->write(input, pt_masterData, writeMstr, 0); result = fields->write(input, pt_masterData, writeMstr, 0);
if (result >= RESULT_OK) if (result >= RESULT_OK) {
result = fields->write(input, pt_slaveData, writeSstr, 0); result = fields->write(input, pt_slaveData, writeSstr, 0);
}
if (failedWrite) { if (failedWrite) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName() << " >"
@@ -601,8 +601,7 @@ int main()
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName() << " >"
<< expectStr << "< OK" << endl; << expectStr << "< OK" << endl;
} }
} } else if (result < RESULT_OK) {
else if (result < RESULT_OK) {
cout << " write " << fields->getName() << " >" << expectStr cout << " write " << fields->getName() << " >" << expectStr
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
+8 -8
View File
@@ -16,14 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "device.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "device.h"
using namespace std; using namespace std;
int main () int main () {
{
Device* device = Device::create("/dev/ttyUSB20", true, false, false); Device* device = Device::create("/dev/ttyUSB20", true, false, false);
if (device == NULL) { if (device == NULL) {
cout << "unable to create device" << endl; cout << "unable to create device" << endl;
@@ -33,26 +32,27 @@ int main ()
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "open failed: " << getResultCode(result) << endl; cout << "open failed: " << getResultCode(result) << endl;
} else { } else {
if (!device->isValid()) if (!device->isValid()) {
cout << "device not available." << endl; cout << "device not available." << endl;
}
int count = 0; int count = 0;
while (1) { while (1) {
unsigned char byte = 0; unsigned char byte = 0;
result = device->recv(0, byte); result = device->recv(0, byte);
if (result == RESULT_OK) if (result == RESULT_OK) {
cout << hex << setw(2) << setfill('0') cout << hex << setw(2) << setfill('0')
<< static_cast<unsigned>(byte) << endl; << static_cast<unsigned>(byte) << endl;
}
count++; count++;
} }
device->close(); device->close();
if (!device->isValid()) if (!device->isValid()) {
cout << "close successful." << endl; cout << "close successful." << endl;
}
} }
delete device; delete device;
+5 -5
View File
@@ -16,17 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "filereader.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <string>
#include <vector>
#include "filereader.h"
using namespace std; using namespace std;
static bool error = false; static bool error = false;
void verify(bool expectFailMatch, string type, string input, void verify(bool expectFailMatch, string type, string input,
bool match, string expectStr, string gotStr) bool match, string expectStr, string gotStr) {
{
match = match && expectStr == gotStr; match = match && expectStr == gotStr;
if (expectFailMatch) { if (expectFailMatch) {
if (match) { if (match) {
@@ -45,8 +46,7 @@ void verify(bool expectFailMatch, string type, string input,
} }
} }
int main() int main() {
{
istringstream ifs( istringstream ifs(
"line 1 col 1,line 1 col 2,line 1 col 3\n" "line 1 col 1,line 1 col 2,line 1 col 3\n"
"line 2 col 1,\"line 2 col 2\",\"line 2 \"\"col 3\"\"\"\n" "line 2 col 1,\"line 2 col 2\",\"line 2 \"\"col 3\"\"\"\n"
+65 -53
View File
@@ -16,41 +16,43 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "message.h"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <string>
#include <vector>
#include <map>
#include "message.h"
using namespace std; using namespace std;
void verify(bool expectFailMatch, string type, string input, void verify(bool expectFailMatch, string type, string input,
bool match, string expectStr, string gotStr) bool match, string expectStr, string gotStr) {
{
if (expectFailMatch) { if (expectFailMatch) {
if (match) if (match) {
cout << " failed " << type << " match >" << input cout << " failed " << type << " match >" << input
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
else } else {
cout << " failed " << type << " match >" << input << "< OK" << endl; cout << " failed " << type << " match >" << input << "< OK" << endl;
} }
else if (match) } else if (match) {
cout << " " << type << " match >" << input << "< OK" << endl; cout << " " << type << " match >" << input << "< OK" << endl;
else } else {
cout << " " << type << " match >" << input << "< error: got >" cout << " " << type << " match >" << input << "< error: got >"
<< gotStr << "<, expected >" << expectStr << "<" << endl; << gotStr << "<, expected >" << expectStr << "<" << endl;
}
} }
DataFieldTemplates* templates = NULL; DataFieldTemplates* templates = NULL;
DataFieldTemplates* getTemplates(const string filename) DataFieldTemplates* getTemplates(const string filename) {
{ if (filename == "") { // avoid compiler warning
if (filename=="") // avoid compiler warning
return templates; return templates;
}
return templates; return templates;
} }
int main() int main() {
{
// message: [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields... // message: [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields...
// field: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] // field: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
// template: name,type[:len][,[divisor|values][,[unit][,[comment]]]] // template: name,type[:len][,[divisor|values][,[unit][,[comment]]]]
@@ -167,17 +169,16 @@ int main()
DataField* fields = NULL; DataField* fields = NULL;
vector<string>::iterator it = entries.begin(); vector<string>::iterator it = entries.begin();
result = DataField::create(it, entries.end(), templates, fields, false, true, false); result = DataField::create(it, entries.end(), templates, fields, false, true, false);
if (result != RESULT_OK) if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": template fields create error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": template fields create error: " << getResultCode(result) << endl;
else if (it != entries.end()) { } else if (it != entries.end()) {
cout << "\"" << check[0] << "\": template fields create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl; cout << "\"" << check[0] << "\": template fields create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
} } else {
else {
cout << "\"" << check[0] << "\": create template OK" << endl; cout << "\"" << check[0] << "\": create template OK" << endl;
result = templates->add(fields, "", true); result = templates->add(fields, "", true);
if (result == RESULT_OK) if (result == RESULT_OK) {
cout << " store template OK" << endl; cout << " store template OK" << endl;
else { } else {
cout << " store template error: " << getResultCode(result) << endl; cout << " store template error: " << getResultCode(result) << endl;
delete fields; delete fields;
} }
@@ -189,21 +190,22 @@ int main()
vector<string>::iterator it = entries.begin(); vector<string>::iterator it = entries.begin();
size_t oldSize = conditions.size(); size_t oldSize = conditions.size();
result = messages->addDefaultFromFile(defaultsRows, entries, it, "", "", "", "no file", 1); result = messages->addDefaultFromFile(defaultsRows, entries, it, "", "", "", "no file", 1);
if (result != RESULT_OK) if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": defaults read error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": defaults read error: " << getResultCode(result) << endl;
else if (it != entries.end()) } else if (it != entries.end()) {
cout << "\"" << check[0] << "\": defaults read error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl; cout << "\"" << check[0] << "\": defaults read error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
else { } else {
cout << "\"" << check[0] << "\": read defaults OK" << endl; cout << "\"" << check[0] << "\": read defaults OK" << endl;
if (isCondition) { if (isCondition) {
if (conditions.size()==oldSize) { if (conditions.size() == oldSize) {
cout << " create condition error" << endl; cout << " create condition error" << endl;
} else { } else {
result = messages->resolveConditions(); result = messages->resolveConditions();
if (result != RESULT_OK) if (result != RESULT_OK) {
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError() << endl; cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError() << endl;
else } else {
cout << " resolve conditions OK" << endl; cout << " resolve conditions OK" << endl;
}
} }
} }
} }
@@ -214,10 +216,11 @@ int main()
string token; string token;
istringstream stream(check[2]); istringstream stream(check[2]);
while (getline(stream, token, VALUE_SEPARATOR)) { while (getline(stream, token, VALUE_SEPARATOR)) {
if (pos >= mstrs.size()) if (pos >= mstrs.size()) {
mstrs.resize(pos+1); mstrs.resize(pos+1);
else if (mstrs[pos]!=NULL) } else if (mstrs[pos] != NULL) {
delete mstrs[pos]; delete mstrs[pos];
}
mstrs[pos] = new SymbolString(false); mstrs[pos] = new SymbolString(false);
result = mstrs[pos]->parseHex(token); result = mstrs[pos]->parseHex(token);
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -230,10 +233,11 @@ int main()
stream.str(check[3]); stream.str(check[3]);
stream.clear(); stream.clear();
while (getline(stream, token, VALUE_SEPARATOR)) { while (getline(stream, token, VALUE_SEPARATOR)) {
if (pos >= sstrs.size()) if (pos >= sstrs.size()) {
sstrs.resize(pos+1); sstrs.resize(pos+1);
else if (sstrs[pos]!=NULL) } else if (sstrs[pos] != NULL) {
delete sstrs[pos]; delete sstrs[pos];
}
sstrs[pos] = new SymbolString(false); sstrs[pos] = new SymbolString(false);
result = sstrs[pos]->parseHex(token); result = sstrs[pos]->parseHex(token);
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -242,19 +246,22 @@ int main()
} }
pos++; pos++;
} }
if (result != RESULT_OK) if (result != RESULT_OK) {
continue; continue;
}
} else { } else {
if (mstrs[0]!=NULL) if (mstrs[0] != NULL) {
delete mstrs[0]; delete mstrs[0];
}
mstrs[0] = new SymbolString(false); mstrs[0] = new SymbolString(false);
result = mstrs[0]->parseHex(check[2]); result = mstrs[0]->parseHex(check[2]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
continue; continue;
} }
if (sstrs[0]!=NULL) if (sstrs[0] != NULL) {
delete sstrs[0]; delete sstrs[0];
}
sstrs[0] = new SymbolString(false); sstrs[0] = new SymbolString(false);
result = sstrs[0]->parseHex(check[3]); result = sstrs[0]->parseHex(check[3]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -263,7 +270,7 @@ int main()
} }
} }
if (deleteMessages.size()>0) { if (deleteMessages.size() > 0) {
for (vector<Message*>::iterator it = deleteMessages.begin(); it != deleteMessages.end(); it++) { for (vector<Message*>::iterator it = deleteMessages.begin(); it != deleteMessages.end(); it++) {
Message* deleteMessage = *it; Message* deleteMessage = *it;
delete deleteMessage; delete deleteMessage;
@@ -282,15 +289,16 @@ int main()
string types = *it; string types = *it;
Condition* condition = NULL; Condition* condition = NULL;
result = messages->readConditions(types, "no file", condition); result = messages->readConditions(types, "no file", condition);
if (result==RESULT_OK) { if (result == RESULT_OK) {
*it = types; *it = types;
result = Message::create(it, entries.end(), &defaultsRows, condition, "no file", templates, deleteMessages); result = Message::create(it, entries.end(), &defaultsRows, condition, "no file", templates, deleteMessages);
} }
if (failedCreate) { if (failedCreate) {
if (result == RESULT_OK) if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
else } else {
cout << "\"" << check[0] << "\": failed create OK" << endl; cout << "\"" << check[0] << "\": failed create OK" << endl;
}
continue; continue;
} }
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -299,7 +307,7 @@ int main()
printErrorPos(cout, entries.begin(), entries.end(), it, "", 0, result); printErrorPos(cout, entries.begin(), entries.end(), it, "", 0, result);
continue; continue;
} }
if (deleteMessages.size()==0) { if (deleteMessages.size() == 0) {
cout << "\"" << check[0] << "\": create error: NULL" << endl; cout << "\"" << check[0] << "\": create error: NULL" << endl;
continue; continue;
} }
@@ -307,11 +315,11 @@ int main()
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl; cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
continue; continue;
} }
if (multi && deleteMessages.size()==1) { if (multi && deleteMessages.size() == 1) {
cout << "\"" << check[0] << "\": create error: single message instead of multiple" << endl; cout << "\"" << check[0] << "\": create error: single message instead of multiple" << endl;
continue; continue;
} }
if (!multi && deleteMessages.size()>1) { if (!multi && deleteMessages.size() > 1) {
cout << "\"" << check[0] << "\": create error: multiple messages instead of single" << endl; cout << "\"" << check[0] << "\": create error: multiple messages instead of single" << endl;
continue; continue;
} }
@@ -327,28 +335,31 @@ int main()
break; break;
} }
} }
if (result != RESULT_OK) if (result != RESULT_OK) {
continue; continue;
}
cout << " map OK" << endl; cout << " map OK" << endl;
message = deleteMessages.front(); message = deleteMessages.front();
deleteMessages.clear(); deleteMessages.clear();
if (onlyMap) if (onlyMap) {
continue; continue;
}
Message* foundMessage = messages->find(*mstrs[0]); Message* foundMessage = messages->find(*mstrs[0]);
if (foundMessage == message) if (foundMessage == message) {
cout << " find OK" << endl; cout << " find OK" << endl;
else if (foundMessage == NULL) } else if (foundMessage == NULL) {
cout << " find error: NULL" << endl; cout << " find error: NULL" << endl;
else } else {
cout << " find error: different" << endl; cout << " find error: different" << endl;
} }
else } else {
message = deleteMessages.front(); message = deleteMessages.front();
}
} }
if (message->isPassive() || decode) { if (message->isPassive() || decode) {
ostringstream output; ostringstream output;
for (unsigned char index=0; index<message->getCount(); index++) { for (unsigned char index = 0; index < message->getCount(); index++) {
message->storeLastData(*mstrs[index], *sstrs[index]); message->storeLastData(*mstrs[index], *sstrs[index]);
} }
if (withMessageDump && !decodeJson) { if (withMessageDump && !decodeJson) {
@@ -370,10 +381,11 @@ int main()
SymbolString writeMstr(false); SymbolString writeMstr(false);
result = message->prepareMaster(0xff, writeMstr, input); result = message->prepareMaster(0xff, writeMstr, input);
if (failedPrepare) { if (failedPrepare) {
if (result == RESULT_OK) if (result == RESULT_OK) {
cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl;
else } else {
cout << " \"" << inputStr << "\": failed prepare OK" << endl; cout << " \"" << inputStr << "\": failed prepare OK" << endl;
}
continue; continue;
} }
@@ -384,12 +396,12 @@ int main()
} }
cout << " \"" << inputStr << "\": prepare OK" << endl; cout << " \"" << inputStr << "\": prepare OK" << endl;
bool match = writeMstr==*mstrs[0]; bool match = writeMstr == *mstrs[0];
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false), writeMstr.getDataStr(true, false)); verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false), writeMstr.getDataStr(true, false));
} }
} }
if (deleteMessages.size()>0) { if (deleteMessages.size() > 0) {
for (vector<Message*>::iterator it = deleteMessages.begin(); it != deleteMessages.end(); it++) { for (vector<Message*>::iterator it = deleteMessages.begin(); it != deleteMessages.end(); it++) {
Message* deleteMessage = *it; Message* deleteMessage = *it;
delete deleteMessage; delete deleteMessage;
@@ -399,10 +411,10 @@ int main()
delete templates; delete templates;
delete messages; delete messages;
for (vector<SymbolString*>::iterator it = mstrs.begin(); it!=mstrs.end(); it++) { for (vector<SymbolString*>::iterator it = mstrs.begin(); it != mstrs.end(); it++) {
delete *it; delete *it;
} }
for (vector<SymbolString*>::iterator it = sstrs.begin(); it!=sstrs.end(); it++) { for (vector<SymbolString*>::iterator it = sstrs.begin(); it != sstrs.end(); it++) {
delete *it; delete *it;
} }
return 0; return 0;
+6 -7
View File
@@ -16,17 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "symbol.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <string>
#include "symbol.h"
using namespace std; using namespace std;
static bool error = false; static bool error = false;
void verify(bool expectFailMatch, string type, string input, void verify(bool expectFailMatch, string type, string input,
bool match, string expectStr, string gotStr) bool match, string expectStr, string gotStr) {
{
match = match && expectStr == gotStr; match = match && expectStr == gotStr;
if (expectFailMatch) { if (expectFailMatch) {
if (match) { if (match) {
@@ -45,11 +45,10 @@ void verify(bool expectFailMatch, string type, string input,
} }
} }
int main(int argc, char** argv) int main(int argc, char** argv) {
{
SymbolString sstr(true); SymbolString sstr(true);
if (argc>1) { if (argc > 1) {
result_t result = sstr.parseHex(argv[1], true); result_t result = sstr.parseHex(argv[1], true);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "parse escaped error: " << getResultCode(result) << endl; cout << "parse escaped error: " << getResultCode(result) << endl;
@@ -76,7 +75,7 @@ int main(int argc, char** argv)
ostr.str(""); ostr.str("");
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc); ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc);
gotStr = ostr.str(); gotStr = ostr.str();
verify(false, "CRC", "10feb5050427a915aa", gotCrc==expectCrc, expectStr, gotStr); verify(false, "CRC", "10feb5050427a915aa", gotCrc == expectCrc, expectStr, gotStr);
gotStr = sstr.getDataStr(true, false), expectStr = "10feb5050427a915aa77"; gotStr = sstr.getDataStr(true, false), expectStr = "10feb5050427a915aa77";
verify(false, "unescape", "10feb5050427a915aa", true, expectStr, gotStr); verify(false, "unescape", "10feb5050427a915aa", true, expectStr, gotStr);
+1 -2
View File
@@ -27,8 +27,7 @@ static bool clockInitialized = false;
static clock_serv_t clockServ; static clock_serv_t clockServ;
#endif #endif
void clockGettime(struct timespec* t) void clockGettime(struct timespec* t) {
{
#ifdef __MACH__ #ifdef __MACH__
if (!clockInitialized) { if (!clockInitialized) {
clockInitialized = true; clockInitialized = true;
+3 -3
View File
@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_CLOCK_H_ #ifndef LIB_UTILS_CLOCK_H_
#define LIBUTILS_CLOCK_H_ #define LIB_UTILS_CLOCK_H_
#include <time.h> #include <time.h>
@@ -29,4 +29,4 @@
*/ */
void clockGettime(struct timespec* t); void clockGettime(struct timespec* t);
#endif // LIBUTILS_CLOCK_H_ #endif // LIB_UTILS_CLOCK_H_
+14 -24
View File
@@ -57,8 +57,7 @@ static LogLevel s_logLevel = ll_notice;
/** the current log FILE. */ /** the current log FILE. */
static FILE* s_logFile = stdout; static FILE* s_logFile = stdout;
bool setLogFacilities(const char* facilities) bool setLogFacilities(const char* facilities) {
{
char *input = strdup(facilities); char *input = strdup(facilities);
char *opt = (char*)input, *value = NULL; char *opt = (char*)input, *value = NULL;
int newFacilites = 0; int newFacilites = 0;
@@ -80,14 +79,13 @@ bool setLogFacilities(const char* facilities)
return true; return true;
} }
bool getLogFacilities(char* buffer) bool getLogFacilities(char* buffer) {
{ if (s_logFacilites == LF_ALL) {
if (s_logFacilites==LF_ALL) {
return strcpy(buffer, facilityNames[lf_COUNT]) != NULL; return strcpy(buffer, facilityNames[lf_COUNT]) != NULL;
} }
*buffer = 0; // for strcat to work *buffer = 0; // for strcat to work
bool found = false; bool found = false;
for (int val=0; val<lf_COUNT; val++) { for (int val = 0; val < lf_COUNT; val++) {
if (s_logFacilites&(1<<val)) { if (s_logFacilites&(1<<val)) {
if (found) { if (found) {
strcat(buffer, ","); strcat(buffer, ",");
@@ -99,8 +97,7 @@ bool getLogFacilities(char* buffer)
return true; return true;
} }
bool setLogLevel(const char* level) bool setLogLevel(const char* level) {
{
char *input = strdup(level); char *input = strdup(level);
char *opt = (char*)input, *value = NULL; char *opt = (char*)input, *value = NULL;
int newLevel = 0; int newLevel = 0;
@@ -117,24 +114,21 @@ bool setLogLevel(const char* level)
return true; return true;
} }
const char* getLogLevel() const char* getLogLevel() {
{
return levelNames[s_logLevel]; return levelNames[s_logLevel];
} }
bool setLogFile(const char* filename) bool setLogFile(const char* filename) {
{
FILE* newFile = fopen(filename, "a"); FILE* newFile = fopen(filename, "a");
if (newFile == NULL) if (newFile == NULL) {
return false; return false;
}
closeLogFile(); closeLogFile();
s_logFile = newFile; s_logFile = newFile;
return true; return true;
} }
void closeLogFile() void closeLogFile() {
{
if (s_logFile != NULL) { if (s_logFile != NULL) {
if (s_logFile != stdout) { if (s_logFile != stdout) {
fclose(s_logFile); fclose(s_logFile);
@@ -143,14 +137,12 @@ void closeLogFile()
} }
} }
bool needsLog(const LogFacility facility, const LogLevel level) bool needsLog(const LogFacility facility, const LogLevel level) {
{
return ((s_logFacilites & (1<<facility)) != 0) return ((s_logFacilites & (1<<facility)) != 0)
&& (s_logLevel >= level); && (s_logLevel >= level);
} }
void logWrite(const char* facility, const char* level, const char* message, va_list ap) void logWrite(const char* facility, const char* level, const char* message, va_list ap) {
{
struct timespec ts; struct timespec ts;
struct tm* tm; struct tm* tm;
clockGettime(&ts); clockGettime(&ts);
@@ -168,16 +160,14 @@ void logWrite(const char* facility, const char* level, const char* message, va_l
} }
} }
void logWrite(const LogFacility facility, const LogLevel level, const char* message, ...) void logWrite(const LogFacility facility, const LogLevel level, const char* message, ...) {
{
va_list ap; va_list ap;
va_start(ap, message); va_start(ap, message);
logWrite(facilityNames[facility], levelNames[level], message, ap); logWrite(facilityNames[facility], levelNames[level], message, ap);
va_end(ap); va_end(ap);
} }
void logWrite(const char* facility, const LogLevel level, const char* message, ...) void logWrite(const char* facility, const LogLevel level, const char* message, ...) {
{
va_list ap; va_list ap;
va_start(ap, message); va_start(ap, message);
logWrite(facility, levelNames[level], message, ap); logWrite(facility, levelNames[level], message, ap);
+15 -15
View File
@@ -16,19 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_LOG_H_ #ifndef LIB_UTILS_LOG_H_
#define LIBUTILS_LOG_H_ #define LIB_UTILS_LOG_H_
/** \file log.h */ /** \file log.h */
/** the available log facilities. */ /** the available log facilities. */
enum LogFacility { enum LogFacility {
lf_main=0, //!< main loop lf_main = 0, //!< main loop
lf_network, //!< network related lf_network, //!< network related
lf_bus, //!< eBUS related lf_bus, //!< eBUS related
lf_update, //!< updates found while listening to the bus lf_update, //!< updates found while listening to the bus
lf_other, //!< all other log facilities lf_other, //!< all other log facilities
lf_COUNT=5 //!< number of available log facilities lf_COUNT = 5 //!< number of available log facilities
}; };
/** macro for enabling all log facilities. */ /** macro for enabling all log facilities. */
@@ -36,12 +36,12 @@ enum LogFacility {
/** the available log levels. */ /** the available log levels. */
enum LogLevel { enum LogLevel {
ll_none=0, //!< no level at all ll_none = 0, //!< no level at all
ll_error, //!< error message ll_error, //!< error message
ll_notice, //!< important message ll_notice, //!< important message
ll_info, //!< informational message ll_info, //!< informational message
ll_debug, //!< debugging message (normally suppressed) ll_debug, //!< debugging message (normally suppressed)
ll_COUNT=5 //!< number of available log levels ll_COUNT = 5 //!< number of available log levels
}; };
/** /**
@@ -136,4 +136,4 @@ void logWrite(const char* facility, const LogLevel level, const char* message, .
/** A macro for a debug message that calls the logging function only if needed. */ /** A macro for a debug message that calls the logging function only if needed. */
#define logOtherDebug(facility, ...) (needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0)) #define logOtherDebug(facility, ...) (needsLog(lf_other, ll_debug) ? logWrite(facility, ll_debug, __VA_ARGS__) : void(0))
#endif // LIBUTILS_LOG_H_ #endif // LIB_UTILS_LOG_H_
+3 -3
View File
@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_NOTIFY_H_ #ifndef LIB_UTILS_NOTIFY_H_
#define LIBUTILS_NOTIFY_H_ #define LIB_UTILS_NOTIFY_H_
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@@ -73,6 +73,6 @@ private:
}; };
#endif // LIBUTILS_NOTIFY_H_ #endif // LIB_UTILS_NOTIFY_H_
+14 -12
View File
@@ -16,12 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_QUEUE_H_ #ifndef LIB_UTILS_QUEUE_H_
#define LIBUTILS_QUEUE_H_ #define LIB_UTILS_QUEUE_H_
#include <list>
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
#include <list>
#include "clock.h" #include "clock.h"
/** \file queue.h */ /** \file queue.h */
@@ -82,22 +82,23 @@ public:
* @param timeout the maximum time in seconds to wait for the queue being filled, or 0 for no wait. * @param timeout the maximum time in seconds to wait for the queue being filled, or 0 for no wait.
* @return the item, or NULL if no item is available within the specified time. * @return the item, or NULL if no item is available within the specified time.
*/ */
T pop(int timeout=0) T pop(int timeout = 0)
{ {
T item; T item;
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
if (timeout>0) { if (timeout > 0) {
struct timespec t; struct timespec t;
clockGettime(&t); clockGettime(&t);
t.tv_sec += timeout; t.tv_sec += timeout;
while (m_queue.empty()) { while (m_queue.empty()) {
if (pthread_cond_timedwait(&m_cond, &m_mutex, &t)==ETIMEDOUT) if (pthread_cond_timedwait(&m_cond, &m_mutex, &t) == ETIMEDOUT) {
break; break;
}
} }
} }
if (m_queue.empty()) if (m_queue.empty()) {
item = NULL; item = NULL;
else { } else {
item = m_queue.front(); item = m_queue.front();
m_queue.pop_front(); m_queue.pop_front();
} }
@@ -111,7 +112,7 @@ public:
* @param wait true to wait for the item to appear in the queue. * @param wait true to wait for the item to appear in the queue.
* @return whether the item was removed. * @return whether the item was removed.
*/ */
bool remove(T item, bool wait=false) bool remove(T item, bool wait = false)
{ {
bool ret = false; bool ret = false;
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
@@ -138,10 +139,11 @@ public:
{ {
T item; T item;
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
if (m_queue.empty()) if (m_queue.empty()) {
item = NULL; item = NULL;
else } else {
item = m_queue.front(); item = m_queue.front();
}
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
return item; return item;
} }
@@ -158,4 +160,4 @@ private:
}; };
#endif // LIBUTILS_QUEUE_H_ #endif // LIB_UTILS_QUEUE_H_
+11 -13
View File
@@ -17,28 +17,27 @@
*/ */
#include "rotatefile.h" #include "rotatefile.h"
#include "clock.h"
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <fstream>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/file.h> #include <sys/file.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <string>
#include "clock.h"
using namespace std; using namespace std;
RotateFile::~RotateFile() RotateFile::~RotateFile() {
{
if (m_stream) { if (m_stream) {
fclose(m_stream); fclose(m_stream);
m_stream = NULL; m_stream = NULL;
} }
} }
bool RotateFile::setEnabled(bool enabled) bool RotateFile::setEnabled(bool enabled) {
{ if (enabled == m_enabled) {
if (enabled==m_enabled) {
return false; return false;
} }
m_enabled = enabled; m_enabled = enabled;
@@ -53,8 +52,7 @@ bool RotateFile::setEnabled(bool enabled)
return true; return true;
} }
void RotateFile::write(unsigned char* value, unsigned int size, bool received) void RotateFile::write(unsigned char* value, unsigned int size, bool received) {
{
if (!m_enabled || !m_stream) { if (!m_enabled || !m_stream) {
return; return;
} }
@@ -68,7 +66,7 @@ void RotateFile::write(unsigned char* value, unsigned int size, bool received)
tm->tm_hour, tm->tm_min, tm->tm_sec, ts.tv_nsec/1000000, tm->tm_hour, tm->tm_min, tm->tm_sec, ts.tv_nsec/1000000,
received ? '<' : '>' received ? '<' : '>'
); );
for (unsigned int pos=0; pos<size; pos++) { for (unsigned int pos = 0; pos < size; pos++) {
fprintf(m_stream, "%2.2x ", value[pos]); fprintf(m_stream, "%2.2x ", value[pos]);
} }
fprintf(m_stream, "\n"); fprintf(m_stream, "\n");
+7 -6
View File
@@ -16,12 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_ROTATEFILE_H_ #ifndef LIB_UTILS_ROTATEFILE_H_
#define LIBUTILS_ROTATEFILE_H_ #define LIB_UTILS_ROTATEFILE_H_
#include <unistd.h> #include <unistd.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <string>
/** @file rotatefile.h /** @file rotatefile.h
* Helpers for writing to rotating files. * Helpers for writing to rotating files.
@@ -41,7 +42,7 @@ public:
* @param maxSize the maximum size of the file to write to. * @param maxSize the maximum size of the file to write to.
* @param textMode whether to write each byte with prefixed timestamp and direction as text. * @param textMode whether to write each byte with prefixed timestamp and direction as text.
*/ */
RotateFile(const string fileName, const unsigned long maxSize, const bool textMode=false) RotateFile(const string fileName, const unsigned long maxSize, const bool textMode = false)
: m_enabled(false), m_fileName(fileName), m_maxSize(maxSize), m_textMode(textMode), m_stream(), m_fileSize(0) {} : m_enabled(false), m_fileName(fileName), m_maxSize(maxSize), m_textMode(textMode), m_stream(), m_fileSize(0) {}
/** /**
@@ -54,7 +55,7 @@ public:
* @param enabled @p true to enable writing to the file, @p false to disable it. * @param enabled @p true to enable writing to the file, @p false to disable it.
* @return @p true when the state was changed, @p false otherwise. * @return @p true when the state was changed, @p false otherwise.
*/ */
bool setEnabled(bool enabled=true); bool setEnabled(bool enabled = true);
/** /**
* Return whether writing to the file is enabled. * Return whether writing to the file is enabled.
@@ -68,7 +69,7 @@ public:
* @param size the number of bytes to write. * @param size the number of bytes to write.
* @param received @a true on reception, @a false on sending (only relevant in text mode). * @param received @a true on reception, @a false on sending (only relevant in text mode).
*/ */
void write(unsigned char* value, unsigned int size, bool received=true); void write(unsigned char* value, unsigned int size, bool received = true);
private: private:
/** whether writing to the file is enabled. */ /** whether writing to the file is enabled. */
@@ -91,5 +92,5 @@ private:
}; };
#endif // LIBUTILS_ROTATEFILE_H_ #endif // LIB_UTILS_ROTATEFILE_H_
+6 -11
View File
@@ -17,30 +17,27 @@
*/ */
#include "tcpsocket.h" #include "tcpsocket.h"
#include <cstdlib>
#include <fcntl.h> #include <fcntl.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <string.h> #include <string.h>
#include <cstdlib>
using namespace std; using namespace std;
TCPSocket::TCPSocket(int sfd, struct sockaddr_in* address) : m_sfd(sfd) TCPSocket::TCPSocket(int sfd, struct sockaddr_in* address) : m_sfd(sfd) {
{
char ip[17]; char ip[17];
inet_ntop(AF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, (socklen_t)sizeof(ip)-1); inet_ntop(AF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, (socklen_t)sizeof(ip)-1);
m_ip = ip; m_ip = ip;
m_port = (uint16_t)ntohs(address->sin_port); m_port = (uint16_t)ntohs(address->sin_port);
} }
bool TCPSocket::isValid() bool TCPSocket::isValid() {
{
return fcntl(m_sfd, F_GETFL) != -1; return fcntl(m_sfd, F_GETFL) != -1;
} }
TCPSocket* TCPClient::connect(const string& server, const uint16_t& port) TCPSocket* TCPClient::connect(const string& server, const uint16_t& port) {
{
struct sockaddr_in address; struct sockaddr_in address;
int ret; int ret;
@@ -76,8 +73,7 @@ TCPSocket* TCPClient::connect(const string& server, const uint16_t& port)
} }
int TCPServer::start() int TCPServer::start() {
{
if (m_listening) { if (m_listening) {
return 0; return 0;
} }
@@ -109,8 +105,7 @@ int TCPServer::start()
return result; return result;
} }
TCPSocket* TCPServer::newSocket() TCPSocket* TCPServer::newSocket() {
{
if (!m_listening) { if (!m_listening) {
return NULL; return NULL;
} }
+4 -4
View File
@@ -16,13 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_TCPSOCKET_H_ #ifndef LIB_UTILS_TCPSOCKET_H_
#define LIBUTILS_TCPSOCKET_H_ #define LIB_UTILS_TCPSOCKET_H_
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <string>
#include <stdint.h> #include <stdint.h>
#include <string>
/** \file tcpsocket.h */ /** \file tcpsocket.h */
@@ -181,5 +181,5 @@ private:
}; };
#endif // LIBUTILS_TCPSOCKET_H_ #endif // LIB_UTILS_TCPSOCKET_H_
+9 -18
View File
@@ -23,22 +23,19 @@
#include "thread.h" #include "thread.h"
#include "clock.h" #include "clock.h"
void* Thread::runThread(void* arg) void* Thread::runThread(void* arg) {
{
((Thread*)arg)->enter(); ((Thread*)arg)->enter();
return NULL; return NULL;
} }
Thread::~Thread() Thread::~Thread() {
{
if (m_started) { if (m_started) {
pthread_cancel(m_threadid); pthread_cancel(m_threadid);
pthread_detach(m_threadid); pthread_detach(m_threadid);
} }
} }
bool Thread::start(const char* name) bool Thread::start(const char* name) {
{
int result = pthread_create(&m_threadid, NULL, runThread, this); int result = pthread_create(&m_threadid, NULL, runThread, this);
@@ -58,8 +55,7 @@ bool Thread::start(const char* name)
return false; return false;
} }
bool Thread::join() bool Thread::join() {
{
int result = -1; int result = -1;
if (m_started) { if (m_started) {
@@ -82,36 +78,31 @@ void Thread::enter() {
WaitThread::WaitThread() WaitThread::WaitThread()
: Thread() : Thread() {
{
pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL); pthread_cond_init(&m_cond, NULL);
} }
WaitThread::~WaitThread() WaitThread::~WaitThread() {
{
pthread_mutex_destroy(&m_mutex); pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond); pthread_cond_destroy(&m_cond);
} }
void WaitThread::stop() void WaitThread::stop() {
{
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond); pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
Thread::stop(); Thread::stop();
} }
bool WaitThread::join() bool WaitThread::join() {
{
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond); pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
return Thread::join(); return Thread::join();
} }
bool WaitThread::Wait(int seconds) bool WaitThread::Wait(int seconds) {
{
struct timespec t; struct timespec t;
clockGettime(&t); clockGettime(&t);
t.tv_sec += seconds; t.tv_sec += seconds;
+3 -3
View File
@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBUTILS_THREAD_H_ #ifndef LIB_UTILS_THREAD_H_
#define LIBUTILS_THREAD_H_ #define LIB_UTILS_THREAD_H_
#include <pthread.h> #include <pthread.h>
@@ -145,4 +145,4 @@ private:
}; };
#endif // LIBUTILS_THREAD_H_ #endif // LIB_UTILS_THREAD_H_
+34 -37
View File
@@ -21,16 +21,17 @@
#endif #endif
#include <argp.h> #include <argp.h>
#include "tcpsocket.h"
#include <string.h> #include <string.h>
#ifdef HAVE_PPOLL
# include <poll.h>
#endif
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include <string>
#include "tcpsocket.h"
#ifdef HAVE_PPOLL
# include <poll.h>
#endif
using namespace std; using namespace std;
@@ -84,8 +85,7 @@ static const struct argp_option argpoptions[] = {
* @param arg the option argument, or NULL. * @param arg the option argument, or NULL.
* @param state the parsing state. * @param state the parsing state.
*/ */
error_t parse_opt(int key, char *arg, struct argp_state *state) error_t parse_opt(int key, char *arg, struct argp_state *state) {
{
struct options *opt = (struct options*)state->input; struct options *opt = (struct options*)state->input;
char* strEnd = NULL; char* strEnd = NULL;
unsigned int port; unsigned int port;
@@ -116,8 +116,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
return 0; return 0;
} }
string fetchData(TCPSocket* socket, bool& listening) string fetchData(TCPSocket* socket, bool& listening) {
{
char data[1024]; char data[1024];
ssize_t datalen; ssize_t datalen;
ostringstream ostream; ostringstream ostream;
@@ -150,13 +149,13 @@ string fetchData(TCPSocket* socket, bool& listening)
FD_SET(STDIN_FILENO, &checkfds); FD_SET(STDIN_FILENO, &checkfds);
FD_SET(socket->getFD(), &checkfds); FD_SET(socket->getFD(), &checkfds);
maxfd = STDIN_FILENO; maxfd = STDIN_FILENO;
if (socket->getFD()>maxfd) if (socket->getFD() > maxfd) {
maxfd = socket->getFD(); maxfd = socket->getFD();
}
#endif #endif
#endif #endif
while(true) { while(true) {
#ifdef HAVE_PPOLL #ifdef HAVE_PPOLL
// wait for new fd event // wait for new fd event
ret = ppoll(fds, nfds, &tdiff, NULL); ret = ppoll(fds, nfds, &tdiff, NULL);
@@ -198,19 +197,20 @@ string fetchData(TCPSocket* socket, bool& listening)
break; break;
} }
for (int i = 0; i < datalen; i++) for (int i = 0; i < datalen; i++) {
ostream << data[i]; ostream << data[i];
}
string str = ostream.str(); string str = ostream.str();
if (listening) if (listening) {
return str; return str;
if (str.length() >= 2 && str[str.length()-2] == '\n' && str[str.length()-1] == '\n') }
if (str.length() >= 2 && str[str.length()-2] == '\n' && str[str.length()-1] == '\n') {
return str; return str;
} }
else } else {
break; break;
} }
else if (newInput) { } else if (newInput) {
getline(cin, message); getline(cin, message);
sendmessage = message+'\n'; sendmessage = message+'\n';
socket->send(sendmessage.c_str(), sendmessage.size()); socket->send(sendmessage.c_str(), sendmessage.size());
@@ -221,7 +221,6 @@ string fetchData(TCPSocket* socket, bool& listening)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
return ""; return "";
} }
message.clear(); message.clear();
} }
} }
@@ -229,8 +228,7 @@ string fetchData(TCPSocket* socket, bool& listening)
return ostream.str(); return ostream.str();
} }
void connect(const char* host, uint16_t port, char* const *args, int argCount) void connect(const char* host, uint16_t port, char* const *args, int argCount) {
{
TCPClient* client = new TCPClient(); TCPClient* client = new TCPClient();
TCPSocket* socket = client->connect(host, port); TCPSocket* socket = client->connect(host, port);
@@ -247,14 +245,17 @@ void connect(const char* host, uint16_t port, char* const *args, int argCount)
} }
else { else {
for (int i = 0; i < argCount; i++) { for (int i = 0; i < argCount; i++) {
if (i > 0) if (i > 0) {
message += " "; message += " ";
}
bool quote = strchr(args[i], ' ') != NULL && strchr(args[i], '"') == NULL; bool quote = strchr(args[i], ' ') != NULL && strchr(args[i], '"') == NULL;
if (quote) if (quote) {
message += "\""; message += "\"";
}
message += args[i]; message += args[i];
if (quote) if (quote) {
message += "\""; message += "\"";
}
} }
} }
@@ -273,32 +274,28 @@ void connect(const char* host, uint16_t port, char* const *args, int argCount)
while (listening && !cin.eof()) { while (listening && !cin.eof()) {
string result(fetchData(socket, listening)); string result(fetchData(socket, listening));
cout << result; cout << result;
if (strcasecmp(result.c_str(), "LISTEN STOPPED") == 0) if (strcasecmp(result.c_str(), "LISTEN STOPPED") == 0) {
break; break;
}
} }
} } else {
else
cout << fetchData(socket, listening); cout << fetchData(socket, listening);
}
} }
} while (!once && !cin.eof()); } while (!once && !cin.eof());
delete socket; delete socket;
} else {
}
else
cout << "error connecting to " << host << ":" << port << endl; cout << "error connecting to " << host << ":" << port << endl;
}
delete client; delete client;
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[]) {
{
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, NULL, NULL, NULL }; struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, NULL, NULL, NULL };
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0); setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &opt) != 0) if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &opt) != 0) {
return EINVAL; return EINVAL;
}
connect(opt.server, opt.port, opt.args, opt.argCount); connect(opt.server, opt.port, opt.args, opt.argCount);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
+14 -21
View File
@@ -21,13 +21,13 @@
#endif #endif
#include <argp.h> #include <argp.h>
#include "device.h"
#include <unistd.h> #include <unistd.h>
#include <iostream>
#include <string.h> #include <string.h>
#include <iostream>
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include "device.h"
using namespace std; using namespace std;
@@ -85,8 +85,7 @@ static const struct argp_option argpoptions[] = {
* @param arg the option argument, or NULL. * @param arg the option argument, or NULL.
* @param state the parsing state. * @param state the parsing state.
*/ */
error_t parse_opt(int key, char *arg, struct argp_state *state) error_t parse_opt(int key, char *arg, struct argp_state *state) {
{
struct options *opt = (struct options*)state->input; struct options *opt = (struct options*)state->input;
char* strEnd = NULL; char* strEnd = NULL;
switch (key) { switch (key) {
@@ -122,50 +121,44 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[]) {
{
struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, NULL, NULL, NULL }; struct argp argp = { argpoptions, parse_opt, argpargsdoc, argpdoc, NULL, NULL, NULL };
setenv("ARGP_HELP_FMT", "no-dup-args-note", 0); setenv("ARGP_HELP_FMT", "no-dup-args-note", 0);
if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &opt) != 0) if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, &opt) != 0) {
return EINVAL; return EINVAL;
}
Device* device = Device::create(opt.device, false, false, NULL); Device* device = Device::create(opt.device, false, false, NULL);
if (device == NULL) { if (device == NULL) {
cout << "unable to create device " << opt.device << endl; cout << "unable to create device " << opt.device << endl;
return EINVAL; return EINVAL;
} }
result_t result = device->open(); result_t result = device->open();
if (result != RESULT_OK) if (result != RESULT_OK) {
cout << "unable to open " << opt.device << ": " << getResultCode(result) << endl; cout << "unable to open " << opt.device << ": " << getResultCode(result) << endl;
}
if (!device->isValid()) if (!device->isValid()) {
cout << "device " << opt.device << " not available" << endl; cout << "device " << opt.device << " not available" << endl;
else { } else {
cout << "device opened" << endl; cout << "device opened" << endl;
fstream file(opt.dumpFile, ios::in | ios::binary); fstream file(opt.dumpFile, ios::in | ios::binary);
if (file.is_open()) { if (file.is_open()) {
while (true) { while (true) {
unsigned char byte = (unsigned char)file.get(); unsigned char byte = (unsigned char)file.get();
if (file.eof()) if (file.eof()) {
break; break;
}
cout << hex << setw(2) << setfill('0') cout << hex << setw(2) << setfill('0')
<< static_cast<unsigned>(byte) << endl; << static_cast<unsigned>(byte) << endl;
device->send(byte); device->send(byte);
usleep(opt.time); usleep(opt.time);
} }
file.close(); file.close();
} } else {
else
cout << "error opening file " << opt.dumpFile << endl; cout << "error opening file " << opt.dumpFile << endl;
}
} }
delete device; delete device;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }