Merge branch 'master' of github.com:john30/ebusd
This commit is contained in:
+191
-200
@@ -16,22 +16,23 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "bushandler.h"
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include "message.h"
|
||||
#include "data.h"
|
||||
#include "result.h"
|
||||
#include "symbol.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;
|
||||
|
||||
@@ -44,8 +45,7 @@ using namespace std;
|
||||
* @return the string corresponding to the @a BusState.
|
||||
*/
|
||||
const char* getStateCode(BusState state) {
|
||||
switch (state)
|
||||
{
|
||||
switch (state) {
|
||||
case bs_noSignal: return "no signal";
|
||||
case bs_skip: return "skip";
|
||||
case bs_ready: return "ready";
|
||||
@@ -62,20 +62,19 @@ const char* getStateCode(BusState state) {
|
||||
}
|
||||
}
|
||||
|
||||
result_t PollRequest::prepare(unsigned char ownMasterAddress)
|
||||
{
|
||||
result_t PollRequest::prepare(unsigned char ownMasterAddress) {
|
||||
istringstream input;
|
||||
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());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PollRequest::notify(result_t result, SymbolString& slave)
|
||||
{
|
||||
bool PollRequest::notify(result_t result, SymbolString& slave) {
|
||||
if (result == RESULT_OK) {
|
||||
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++;
|
||||
result = prepare(m_master[0]);
|
||||
if (result >= RESULT_OK) {
|
||||
@@ -84,73 +83,79 @@ bool PollRequest::notify(result_t result, SymbolString& slave)
|
||||
}
|
||||
}
|
||||
ostringstream output;
|
||||
if (result==RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
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));
|
||||
else
|
||||
} else {
|
||||
logNotice(lf_bus, "poll %s %s: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), output.str().c_str());
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
result_t ScanRequest::prepare(unsigned char ownMasterAddress)
|
||||
{
|
||||
if (m_slaves.empty())
|
||||
result_t ScanRequest::prepare(unsigned char ownMasterAddress) {
|
||||
if (m_slaves.empty()) {
|
||||
return RESULT_ERR_EOF;
|
||||
}
|
||||
unsigned char dstAddress = m_slaves.front();
|
||||
if (m_index==0 && m_messages.size()==m_allMessages.size()) // first message for this address
|
||||
if (m_index == 0 && m_messages.size() == m_allMessages.size()) { // first message for this address
|
||||
m_busHandler->setScanResult(dstAddress, "");
|
||||
|
||||
}
|
||||
istringstream input;
|
||||
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index);
|
||||
if (result >= RESULT_OK)
|
||||
if (result >= RESULT_OK) {
|
||||
logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getDataStr().c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ScanRequest::notify(result_t result, SymbolString& slave)
|
||||
{
|
||||
bool ScanRequest::notify(result_t result, SymbolString& slave) {
|
||||
unsigned char dstAddress = m_master[1];
|
||||
if (result == RESULT_OK) {
|
||||
if (m_message==m_messageMap->getScanMessage()) {
|
||||
if (m_message == m_messageMap->getScanMessage()) {
|
||||
Message* message = m_messageMap->getScanMessage(dstAddress);
|
||||
if (message!=NULL) {
|
||||
if (message != NULL) {
|
||||
m_message = message;
|
||||
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_messageMap->add(m_message);
|
||||
m_message->storeLastData(pt_masterData, m_master, m_index); // expected to work since this is a clone
|
||||
}
|
||||
result = m_message->storeLastData(pt_slaveData, slave, m_index);
|
||||
if (result>=RESULT_OK && m_index+1 < m_message->getCount()) {
|
||||
if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
|
||||
m_index++;
|
||||
result = prepare(m_master[0]);
|
||||
if (result >= RESULT_OK)
|
||||
if (result >= RESULT_OK) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (result==RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
result = m_message->decodeLastData(m_scanResult, 0, true); // decode data
|
||||
}
|
||||
}
|
||||
if (result < RESULT_OK) {
|
||||
if (!m_slaves.empty())
|
||||
if (!m_slaves.empty()) {
|
||||
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());
|
||||
else
|
||||
} else {
|
||||
logError(lf_bus, "scan %2.2x failed (%d slaves left): %s", dstAddress, m_slaves.size(), getResultCode(result));
|
||||
}
|
||||
m_messages.clear(); // skip remaining secondary messages
|
||||
} else if (m_messages.empty()) {
|
||||
if (!m_slaves.empty())
|
||||
if (!m_slaves.empty()) {
|
||||
m_slaves.pop_front();
|
||||
}
|
||||
logNotice(lf_bus, "scan %2.2x completed (%d slaves left)", dstAddress, m_slaves.size());
|
||||
}
|
||||
if (m_messages.empty()) // last message for this address
|
||||
if (m_messages.empty()) { // last message for this address
|
||||
m_busHandler->setScanResult(dstAddress, m_scanResult.str());
|
||||
|
||||
}
|
||||
if (m_slaves.empty()) {
|
||||
logNotice(lf_bus, "scan finished");
|
||||
m_busHandler->setScanFinished();
|
||||
@@ -172,19 +177,16 @@ bool ScanRequest::notify(result_t result, SymbolString& slave)
|
||||
}
|
||||
|
||||
|
||||
bool ActiveBusRequest::notify(result_t result, SymbolString& slave)
|
||||
{
|
||||
if (result == RESULT_OK)
|
||||
bool ActiveBusRequest::notify(result_t result, SymbolString& slave) {
|
||||
if (result == RESULT_OK) {
|
||||
logDebug(lf_bus, "read res: %s", slave.getDataStr().c_str());
|
||||
|
||||
}
|
||||
m_result = result;
|
||||
m_slave.addAll(slave, true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave)
|
||||
{
|
||||
void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) {
|
||||
m_lastMaster.clear(false);
|
||||
m_lastMaster.addAll(master);
|
||||
m_lastSlave.clear(false);
|
||||
@@ -192,8 +194,7 @@ void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave)
|
||||
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);
|
||||
if (unknown && message) {
|
||||
return false;
|
||||
@@ -214,15 +215,13 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first,
|
||||
}
|
||||
|
||||
|
||||
void BusHandler::clear()
|
||||
{
|
||||
void BusHandler::clear() {
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
m_masterCount = 1;
|
||||
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;
|
||||
slave.clear();
|
||||
ActiveBusRequest request(master, slave);
|
||||
@@ -232,31 +231,28 @@ result_t BusHandler::sendAndWait(SymbolString& master, SymbolString& slave)
|
||||
m_nextRequests.push(&request);
|
||||
bool success = m_finishedRequests.remove(&request, true);
|
||||
result = success ? request.m_result : RESULT_ERR_TIMEOUT;
|
||||
|
||||
if (result == RESULT_OK) {
|
||||
Message* message = m_messages->find(master);
|
||||
if (message != NULL)
|
||||
if (message != NULL) {
|
||||
m_messages->invalidateCache(message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
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));
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
SymbolString master(true);
|
||||
SymbolString slave(false);
|
||||
for (unsigned char index=0; index<message->getCount(); index++) {
|
||||
for (unsigned char index = 0; index < message->getCount(); index++) {
|
||||
istringstream input(inputStr);
|
||||
ret = message->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index);
|
||||
if (ret != RESULT_OK) {
|
||||
@@ -278,16 +274,16 @@ result_t BusHandler::readFromBus(Message* message, string inputStr, const unsign
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BusHandler::run()
|
||||
{
|
||||
void BusHandler::run() {
|
||||
unsigned int symCount = 0;
|
||||
time_t lastTime;
|
||||
time(&lastTime);
|
||||
do {
|
||||
if (m_device->isValid() && !m_reconnect) {
|
||||
result_t result = handleSymbol();
|
||||
if (result != RESULT_ERR_TIMEOUT)
|
||||
if (result != RESULT_ERR_TIMEOUT) {
|
||||
symCount++;
|
||||
}
|
||||
time_t now;
|
||||
time(&now);
|
||||
if (now > lastTime) {
|
||||
@@ -318,18 +314,16 @@ void BusHandler::run()
|
||||
} while (isRunning());
|
||||
}
|
||||
|
||||
result_t BusHandler::handleSymbol()
|
||||
{
|
||||
result_t BusHandler::handleSymbol() {
|
||||
long timeout = SYN_TIMEOUT;
|
||||
unsigned char sendSymbol = ESC;
|
||||
bool sending = false;
|
||||
BusRequest* startRequest = NULL;
|
||||
|
||||
// check if another symbol has to be sent and determine timeout for receive
|
||||
switch (m_state)
|
||||
{
|
||||
switch (m_state) {
|
||||
case bs_noSignal:
|
||||
timeout = m_generateSynInterval>0 ? m_generateSynInterval : SIGNAL_TIMEOUT;
|
||||
timeout = m_generateSynInterval > 0 ? m_generateSynInterval : SIGNAL_TIMEOUT;
|
||||
break;
|
||||
|
||||
case bs_skip:
|
||||
@@ -373,10 +367,11 @@ result_t BusHandler::handleSymbol()
|
||||
break;
|
||||
|
||||
case bs_recvRes:
|
||||
if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT)
|
||||
if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) {
|
||||
timeout = m_slaveRecvTimeout;
|
||||
else
|
||||
} else {
|
||||
timeout = SYN_TIMEOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case bs_recvResAck:
|
||||
@@ -422,10 +417,11 @@ result_t BusHandler::handleSymbol()
|
||||
if (sending) {
|
||||
result = m_device->send(sendSymbol);
|
||||
if (result == RESULT_OK) {
|
||||
if (m_state == bs_ready)
|
||||
if (m_state == bs_ready) {
|
||||
timeout = m_transferLatency+m_busAcquireTimeout;
|
||||
else
|
||||
} else {
|
||||
timeout = m_transferLatency+SEND_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
sending = false;
|
||||
timeout = SYN_TIMEOUT;
|
||||
@@ -450,9 +446,9 @@ result_t BusHandler::handleSymbol()
|
||||
if (result == RESULT_ERR_TIMEOUT) {
|
||||
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));
|
||||
else if (recvSymbol != SYN) {
|
||||
} else if (recvSymbol != SYN) {
|
||||
logError(lf_bus, "received %2.2x instead of AUTO-SYN symbol", recvSymbol);
|
||||
} else {
|
||||
if (m_generateSynInterval != SYN_TIMEOUT) {
|
||||
@@ -473,26 +469,25 @@ result_t BusHandler::handleSymbol()
|
||||
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
|
||||
|| m_state == bs_noSignal)
|
||||
|| m_state == bs_noSignal) {
|
||||
return setState(bs_noSignal, result);
|
||||
|
||||
}
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
|
||||
m_lastReceive = now;
|
||||
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--;
|
||||
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)
|
||||
|
||||
}
|
||||
return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN);
|
||||
}
|
||||
|
||||
unsigned int headerLen, crcPos;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
switch (m_state) {
|
||||
case bs_noSignal:
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
|
||||
@@ -514,15 +509,16 @@ result_t BusHandler::handleSymbol()
|
||||
}
|
||||
// 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
|
||||
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)
|
||||
m_remainLockCount = m_lockCount;
|
||||
}
|
||||
setState(m_state, RESULT_ERR_BUS_LOST); // try again later
|
||||
}
|
||||
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);
|
||||
|
||||
}
|
||||
m_repeat = false;
|
||||
return setState(bs_recvCmd, RESULT_OK);
|
||||
|
||||
@@ -530,9 +526,9 @@ result_t BusHandler::handleSymbol()
|
||||
headerLen = 4;
|
||||
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);
|
||||
if (result < RESULT_OK)
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
|
||||
}
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
|
||||
unsigned char dstAddress = m_command[1];
|
||||
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); // header symbols are never escaped
|
||||
@@ -542,36 +538,34 @@ result_t BusHandler::handleSymbol()
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
addSeenAddress(m_command[0]);
|
||||
if (m_answer
|
||||
&& (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress))
|
||||
if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
|
||||
return setState(bs_sendCmdAck, RESULT_OK);
|
||||
|
||||
}
|
||||
return setState(bs_recvCmdAck, RESULT_OK);
|
||||
}
|
||||
if (dstAddress == BROADCAST)
|
||||
if (dstAddress == BROADCAST) {
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
|
||||
if (m_answer
|
||||
&& (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
|
||||
}
|
||||
if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
|
||||
return setState(bs_sendCmdAck, RESULT_ERR_CRC);
|
||||
}
|
||||
if (m_repeat)
|
||||
if (m_repeat) {
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_recvCmdAck, RESULT_ERR_CRC);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_recvCmdAck:
|
||||
if (recvSymbol == ACK) {
|
||||
if (!m_commandCrcValid)
|
||||
if (!m_commandCrcValid) {
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
|
||||
}
|
||||
if (m_currentRequest != NULL) {
|
||||
if (isMaster(m_currentRequest->m_master[1])) {
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
}
|
||||
}
|
||||
else if (isMaster(m_command[1])) { // header symbols are never escaped
|
||||
} else if (isMaster(m_command[1])) { // header symbols are never escaped
|
||||
receiveCompleted();
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
@@ -584,50 +578,48 @@ result_t BusHandler::handleSymbol()
|
||||
m_repeat = true;
|
||||
m_nextSendPos = 0;
|
||||
m_command.clear();
|
||||
if (m_currentRequest != NULL)
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendCmd, RESULT_ERR_NAK, true);
|
||||
|
||||
}
|
||||
return setState(bs_recvCmd, RESULT_ERR_NAK);
|
||||
}
|
||||
|
||||
return setState(bs_skip, RESULT_ERR_NAK);
|
||||
}
|
||||
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
|
||||
case bs_recvRes:
|
||||
headerLen = 0;
|
||||
crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff;
|
||||
result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos);
|
||||
if (result < RESULT_OK)
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
|
||||
}
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received
|
||||
m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC();
|
||||
if (m_responseCrcValid) {
|
||||
if (m_currentRequest != NULL)
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendResAck, RESULT_OK);
|
||||
|
||||
}
|
||||
return setState(bs_recvResAck, RESULT_OK);
|
||||
}
|
||||
if (m_repeat) {
|
||||
if (m_currentRequest != NULL)
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendSyn, 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_recvResAck, RESULT_ERR_CRC);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_recvResAck:
|
||||
if (recvSymbol == ACK) {
|
||||
if (!m_responseCrcValid)
|
||||
if (!m_responseCrcValid) {
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
|
||||
}
|
||||
receiveCompleted();
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
@@ -647,9 +639,9 @@ result_t BusHandler::handleSymbol()
|
||||
m_nextSendPos++;
|
||||
if (m_nextSendPos >= m_currentRequest->m_master.size()) {
|
||||
// master data completely sent
|
||||
if (m_currentRequest->m_master[1] == BROADCAST)
|
||||
if (m_currentRequest->m_master[1] == BROADCAST) {
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
|
||||
}
|
||||
m_commandCrcValid = true;
|
||||
return setState(bs_recvCmdAck, RESULT_OK);
|
||||
}
|
||||
@@ -695,20 +687,22 @@ result_t BusHandler::handleSymbol()
|
||||
message = m_messages->find(m_command);
|
||||
if (message == NULL) {
|
||||
message = m_messages->find(m_command, true);
|
||||
if (message!=NULL && message->getSrcAddress()!=SYN)
|
||||
if (message != NULL && message->getSrcAddress() != SYN) {
|
||||
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
|
||||
}
|
||||
if (message == m_messages->getScanMessage(m_ownSlaveAddress)) {
|
||||
input.str(SCAN_ANSWER);
|
||||
}
|
||||
|
||||
// build response and store in m_response for sending back to requesting master
|
||||
m_response.clear(true); // escape while sending response
|
||||
result = message->prepareSlave(input, m_response);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
return setState(bs_sendRes, RESULT_OK);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
@@ -731,30 +725,25 @@ result_t BusHandler::handleSymbol()
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
|
||||
}
|
||||
|
||||
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 (result == RESULT_ERR_BUS_LOST && m_currentRequest->m_busLostRetries < m_busLostRetries) {
|
||||
logDebug(lf_bus, "%s during %s, retry", getResultCode(result), getStateCode(m_state));
|
||||
m_currentRequest->m_busLostRetries++;
|
||||
m_nextRequests.push(m_currentRequest); // repeat
|
||||
m_currentRequest = NULL;
|
||||
}
|
||||
else if (state == bs_sendSyn || (result != RESULT_OK && !firstRepetition)) {
|
||||
} else if (state == bs_sendSyn || (result != RESULT_OK && !firstRepetition)) {
|
||||
logDebug(lf_bus, "notify request: %s", getResultCode(result));
|
||||
unsigned char dstAddress = m_currentRequest->m_master[1];
|
||||
if (result == RESULT_OK) {
|
||||
addSeenAddress(dstAddress);
|
||||
}
|
||||
bool restart = m_currentRequest->notify(
|
||||
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes) ? RESULT_ERR_TIMEOUT : result, m_response
|
||||
);
|
||||
result == RESULT_ERR_SYN && (m_state == bs_recvCmdAck || m_state == bs_recvRes) ? RESULT_ERR_TIMEOUT : result, m_response);
|
||||
if (restart) {
|
||||
m_currentRequest->m_busLostRetries = 0;
|
||||
m_nextRequests.push(m_currentRequest);
|
||||
@@ -808,13 +797,12 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
return result;
|
||||
}
|
||||
|
||||
void BusHandler::addSeenAddress(unsigned char address)
|
||||
{
|
||||
void BusHandler::addSeenAddress(unsigned char address) {
|
||||
if (!isValidAddress(address, false)) {
|
||||
return;
|
||||
}
|
||||
if (!isMaster(address)) {
|
||||
if (!m_device->isReadOnly() && address==m_ownSlaveAddress) {
|
||||
if (!m_device->isReadOnly() && address == m_ownSlaveAddress) {
|
||||
if (!m_addressConflict) {
|
||||
m_addressConflict = true;
|
||||
logError(lf_bus, "own slave address %2.2x is used by another participant", address);
|
||||
@@ -822,19 +810,19 @@ void BusHandler::addSeenAddress(unsigned char address)
|
||||
}
|
||||
m_seenAddresses[address] |= SEEN;
|
||||
address = getMasterAddress(address);
|
||||
if (address==SYN) {
|
||||
if (address == SYN) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((m_seenAddresses[address]&SEEN)==0) {
|
||||
if (!m_device->isReadOnly() && address==m_ownMasterAddress) {
|
||||
if ((m_seenAddresses[address]&SEEN) == 0) {
|
||||
if (!m_device->isReadOnly() && address == m_ownMasterAddress) {
|
||||
if (!m_addressConflict) {
|
||||
m_addressConflict = true;
|
||||
logError(lf_bus, "own master address %2.2x is used by another participant", address);
|
||||
}
|
||||
} else {
|
||||
m_masterCount++;
|
||||
if (m_autoLockCount && m_masterCount>m_lockCount) {
|
||||
if (m_autoLockCount && m_masterCount > m_lockCount) {
|
||||
m_lockCount = m_masterCount;
|
||||
}
|
||||
logNotice(lf_bus, "new master %2.2x, master count %d", address, m_masterCount);
|
||||
@@ -843,8 +831,7 @@ void BusHandler::addSeenAddress(unsigned char address)
|
||||
}
|
||||
}
|
||||
|
||||
void BusHandler::receiveCompleted()
|
||||
{
|
||||
void BusHandler::receiveCompleted() {
|
||||
unsigned char srcAddress = m_command[0], dstAddress = m_command[1];
|
||||
if (srcAddress == dstAddress) {
|
||||
logError(lf_bus, "invalid self-addressed message from %2.2x", srcAddress);
|
||||
@@ -856,17 +843,17 @@ void BusHandler::receiveCompleted()
|
||||
bool master = isMaster(dstAddress);
|
||||
if (dstAddress == BROADCAST) {
|
||||
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);
|
||||
addSeenAddress(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
|
||||
m_seenAddresses[slaveAddress] |= SCAN_INIT;
|
||||
SymbolString idData;
|
||||
istringstream input;
|
||||
result_t result = message->prepareMaster(m_ownMasterAddress, idData, input);
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
idData.clear();
|
||||
idData.push_back(9);
|
||||
for (size_t i = 5; i <= 5+9; i++) {
|
||||
@@ -874,7 +861,7 @@ void BusHandler::receiveCompleted()
|
||||
}
|
||||
result = message->storeLastData(pt_slaveData, idData, 0);
|
||||
}
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
m_seenAddresses[slaveAddress] |= SCAN_DONE;
|
||||
}
|
||||
logNotice(lf_update, "store BC ident: %s", getResultCode(result));
|
||||
@@ -909,7 +896,7 @@ void BusHandler::receiveCompleted()
|
||||
string name = message->getName();
|
||||
result_t result = message->storeLastData(m_command, m_response);
|
||||
ostringstream output;
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
result = message->decodeLastData(output);
|
||||
}
|
||||
if (result < RESULT_OK) {
|
||||
@@ -933,29 +920,31 @@ void BusHandler::receiveCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
result_t BusHandler::startScan(bool full)
|
||||
{
|
||||
result_t BusHandler::startScan(bool full) {
|
||||
deque<Message*> messages = m_messages->findAll("scan", "", true);
|
||||
for (deque<Message*>::iterator it = messages.begin(); it < messages.end(); 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
|
||||
}
|
||||
}
|
||||
|
||||
Message* scanMessage = m_messages->getScanMessage();
|
||||
if (scanMessage==NULL)
|
||||
if (scanMessage == NULL) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
|
||||
}
|
||||
m_scanResults.clear();
|
||||
|
||||
deque<unsigned char> slaves;
|
||||
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;
|
||||
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
|
||||
if (master == SYN || (m_seenAddresses[master]&SEEN)==0)
|
||||
if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
slaves.push_back(slave);
|
||||
}
|
||||
@@ -964,55 +953,55 @@ result_t BusHandler::startScan(bool full)
|
||||
result_t result = request->prepare(m_ownMasterAddress);
|
||||
if (result < RESULT_OK) {
|
||||
delete request;
|
||||
return result==RESULT_ERR_EOF ? RESULT_EMPTY : result;
|
||||
return result == RESULT_ERR_EOF ? RESULT_EMPTY : result;
|
||||
}
|
||||
m_runningScans++;
|
||||
m_nextRequests.push(request);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void BusHandler::setScanResult(unsigned char dstAddress, string str)
|
||||
{
|
||||
void BusHandler::setScanResult(unsigned char dstAddress, string str) {
|
||||
m_seenAddresses[dstAddress] |= SCAN_INIT;
|
||||
if (str.length()>0) {
|
||||
if (str.length() > 0) {
|
||||
m_seenAddresses[dstAddress] |= SCAN_DONE;
|
||||
m_scanResults[dstAddress] = str;
|
||||
logNotice(lf_bus, "scan %2.2x: %s", dstAddress, str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void BusHandler::setScanFinished()
|
||||
{
|
||||
if (m_runningScans>0)
|
||||
void BusHandler::setScanFinished() {
|
||||
if (m_runningScans > 0) {
|
||||
m_runningScans--;
|
||||
}
|
||||
}
|
||||
|
||||
void BusHandler::formatScanResult(ostringstream& output)
|
||||
{
|
||||
if (m_runningScans>0) {
|
||||
void BusHandler::formatScanResult(ostringstream& output) {
|
||||
if (m_runningScans > 0) {
|
||||
output << static_cast<unsigned>(m_runningScans) << " scan(s) still running" << endl;
|
||||
}
|
||||
bool first = true;
|
||||
for (unsigned char slave = 1; slave != 0; slave++) { // 0 is known to be a master
|
||||
map<unsigned char, string>::iterator it = m_scanResults.find(slave);
|
||||
if (it != m_scanResults.end()) {
|
||||
if (first)
|
||||
if (first) {
|
||||
first = false;
|
||||
else
|
||||
} else {
|
||||
output << endl;
|
||||
}
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave) << it->second;
|
||||
}
|
||||
}
|
||||
if (first) {
|
||||
// fallback to autoscan results
|
||||
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);
|
||||
if (message!=NULL && message->getLastUpdateTime()>0) {
|
||||
if (first)
|
||||
if (message != NULL && message->getLastUpdateTime() > 0) {
|
||||
if (first) {
|
||||
first = false;
|
||||
else
|
||||
} else {
|
||||
output << endl;
|
||||
}
|
||||
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave);
|
||||
message->decodeLastData(output, 0, true);
|
||||
}
|
||||
@@ -1021,12 +1010,11 @@ void BusHandler::formatScanResult(ostringstream& output)
|
||||
}
|
||||
}
|
||||
|
||||
void BusHandler::formatSeenInfo(ostringstream& output)
|
||||
{
|
||||
void BusHandler::formatSeenInfo(ostringstream& output) {
|
||||
unsigned char address = 0;
|
||||
for (int index=0; index<256; index++, address++) {
|
||||
for (int index = 0; index < 256; index++, address++) {
|
||||
if (isValidAddress(address, false)
|
||||
&& ((m_seenAddresses[address]&SEEN)!=0 || (!m_device->isReadOnly() && (address==m_ownMasterAddress || address==m_ownSlaveAddress)))) {
|
||||
&& ((m_seenAddresses[address]&SEEN) != 0 || (!m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress)))) {
|
||||
output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address);
|
||||
unsigned char master;
|
||||
if (isMaster(address)) {
|
||||
@@ -1036,25 +1024,26 @@ void BusHandler::formatSeenInfo(ostringstream& output)
|
||||
output << ": slave";
|
||||
master = getMasterAddress(address);
|
||||
}
|
||||
if (master != SYN)
|
||||
if (master != SYN) {
|
||||
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";
|
||||
if (m_answer) {
|
||||
output << " (answering)";
|
||||
}
|
||||
if (m_addressConflict && (m_seenAddresses[address]&SEEN)!=0) {
|
||||
if (m_addressConflict && (m_seenAddresses[address]&SEEN) != 0) {
|
||||
output << ", conflict";
|
||||
}
|
||||
}
|
||||
if ((m_seenAddresses[address]&SCAN_DONE)!=0) {
|
||||
if ((m_seenAddresses[address]&SCAN_DONE) != 0) {
|
||||
output << ", scanned";
|
||||
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
|
||||
output << " \"";
|
||||
result_t result = message->decodeLastData(output, OF_NAMES);
|
||||
if (result!=RESULT_OK) {
|
||||
if (result != RESULT_OK) {
|
||||
output << "\" error: " << getResultCode(result);
|
||||
} else {
|
||||
output << "\"";
|
||||
@@ -1062,45 +1051,46 @@ void BusHandler::formatSeenInfo(ostringstream& output)
|
||||
}
|
||||
}
|
||||
string loadedFiles = m_messages->getLoadedFiles(address);
|
||||
if (!loadedFiles.empty())
|
||||
if (!loadedFiles.empty()) {
|
||||
output << ", loaded " << loadedFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
|
||||
{
|
||||
if (!isValidAddress(dstAddress) || isMaster(dstAddress))
|
||||
result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave) {
|
||||
if (!isValidAddress(dstAddress) || isMaster(dstAddress)) {
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
}
|
||||
m_seenAddresses[dstAddress] |= SCAN_INIT;
|
||||
Message* scanMessage = m_messages->getScanMessage();
|
||||
if (scanMessage==NULL) {
|
||||
if (scanMessage == NULL) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
istringstream input;
|
||||
SymbolString master;
|
||||
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);
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
Message* message = m_messages->getScanMessage(dstAddress);
|
||||
if (message!=NULL && message!=scanMessage) {
|
||||
if (message != NULL && message != scanMessage) {
|
||||
scanMessage = message;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (result != RESULT_OK || slave.size() == 0) // avoid "invalid position" during decode
|
||||
if (result != RESULT_OK || slave.size() == 0) { // avoid "invalid position" during decode
|
||||
return result;
|
||||
|
||||
}
|
||||
return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
|
||||
}
|
||||
|
||||
bool BusHandler::enableGrab(bool enable)
|
||||
{
|
||||
if (enable==m_grabMessages) {
|
||||
bool BusHandler::enableGrab(bool enable) {
|
||||
if (enable == m_grabMessages) {
|
||||
return false;
|
||||
}
|
||||
if (!enable) {
|
||||
@@ -1110,8 +1100,7 @@ bool BusHandler::enableGrab(bool enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BusHandler::formatGrabResult(const bool unknown, ostringstream& output)
|
||||
{
|
||||
void BusHandler::formatGrabResult(const bool unknown, ostringstream& output) {
|
||||
if (!m_grabMessages) {
|
||||
output << "grab disabled";
|
||||
} else {
|
||||
@@ -1125,18 +1114,20 @@ void BusHandler::formatGrabResult(const bool unknown, ostringstream& output)
|
||||
}
|
||||
|
||||
unsigned char BusHandler::getNextScanAddress(unsigned char lastAddress, bool& scanned) {
|
||||
if (lastAddress==SYN)
|
||||
if (lastAddress == 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;
|
||||
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;
|
||||
}
|
||||
unsigned char master = getMasterAddress(lastAddress);
|
||||
if (master!=SYN && (m_seenAddresses[master]&SEEN)!=0 && (m_seenAddresses[lastAddress]&LOAD_INIT)==0) {
|
||||
scanned = (m_seenAddresses[lastAddress]&SCAN_INIT)!=0;
|
||||
if (master != SYN && (m_seenAddresses[master]&SEEN) != 0 && (m_seenAddresses[lastAddress]&LOAD_INIT) == 0) {
|
||||
scanned = (m_seenAddresses[lastAddress]&SCAN_INIT) != 0;
|
||||
return lastAddress;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-52
@@ -16,9 +16,14 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BUSHANDLER_H_
|
||||
#define BUSHANDLER_H_
|
||||
#ifndef EBUSD_BUSHANDLER_H_
|
||||
#define EBUSD_BUSHANDLER_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include "message.h"
|
||||
#include "data.h"
|
||||
#include "symbol.h"
|
||||
@@ -26,10 +31,6 @@
|
||||
#include "device.h"
|
||||
#include "queue.h"
|
||||
#include "thread.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
|
||||
/** @file bushandler.h
|
||||
* Classes, functions, and constants related to handling of symbols on the eBUS.
|
||||
@@ -92,11 +93,10 @@ class BusHandler;
|
||||
/**
|
||||
* Generic request for sending to and receiving from the bus.
|
||||
*/
|
||||
class BusRequest
|
||||
{
|
||||
class BusRequest {
|
||||
friend class BusHandler;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param master the escaped master data @a SymbolString to send.
|
||||
@@ -119,8 +119,8 @@ public:
|
||||
*/
|
||||
virtual bool notify(result_t result, SymbolString& slave) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** the escaped master data @a SymbolString to send. */
|
||||
SymbolString& m_master;
|
||||
|
||||
@@ -129,18 +129,16 @@ protected:
|
||||
|
||||
/** whether to automatically delete this @a BusRequest when finished. */
|
||||
const bool m_deleteOnFinish;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A poll @a BusRequest handled by @a BusHandler itself.
|
||||
*/
|
||||
class PollRequest : public BusRequest
|
||||
{
|
||||
class PollRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param message the associated @a Message.
|
||||
@@ -163,8 +161,8 @@ public:
|
||||
// @copydoc
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the escaped master data @a SymbolString. */
|
||||
SymbolString m_master;
|
||||
|
||||
@@ -173,18 +171,16 @@ private:
|
||||
|
||||
/** the current part index in @a m_message. */
|
||||
unsigned char m_index;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A scan @a BusRequest handled by @a BusHandler itself.
|
||||
*/
|
||||
class ScanRequest : public BusRequest
|
||||
{
|
||||
class ScanRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param messageMap the @a MessageMap instance.
|
||||
@@ -193,8 +189,7 @@ public:
|
||||
* @param busHandler the @a BusHandler instance to notify of final scan result.
|
||||
*/
|
||||
ScanRequest(MessageMap* messageMap, deque<Message*> messages, deque<unsigned char> slaves, BusHandler* busHandler)
|
||||
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages), m_slaves(slaves), m_busHandler(busHandler)
|
||||
{
|
||||
: BusRequest(m_master, true), m_messageMap(messageMap), m_index(0), m_allMessages(messages), m_messages(messages), m_slaves(slaves), m_busHandler(busHandler) {
|
||||
m_message = m_messages.front();
|
||||
m_messages.pop_front();
|
||||
}
|
||||
@@ -214,8 +209,8 @@ public:
|
||||
// @copydoc
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the @a MessageMap instance. */
|
||||
MessageMap* m_messageMap;
|
||||
|
||||
@@ -242,18 +237,16 @@ private:
|
||||
|
||||
/** the @a BusHandler instance to notify of final scan result. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An active @a BusRequest that can be waited for.
|
||||
*/
|
||||
class ActiveBusRequest : public BusRequest
|
||||
{
|
||||
class ActiveBusRequest : public BusRequest {
|
||||
friend class BusHandler;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param master the escaped master data @a SymbolString to send.
|
||||
@@ -270,25 +263,21 @@ public:
|
||||
// @copydoc
|
||||
virtual bool notify(result_t result, SymbolString& slave);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the result of handling the request. */
|
||||
result_t m_result;
|
||||
|
||||
/** reference to @a SymbolString for filling in the received slave data. */
|
||||
SymbolString& m_slave;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for keeping track of grabbed messages.
|
||||
*/
|
||||
class GrabbedMessage
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
class GrabbedMessage {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -320,8 +309,8 @@ public:
|
||||
*/
|
||||
bool dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the last master @a SymbolString. */
|
||||
SymbolString m_lastMaster;
|
||||
|
||||
@@ -330,17 +319,14 @@ private:
|
||||
|
||||
/** the number of times this message was seen. */
|
||||
unsigned int m_count;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles input from and output to the bus with respect to the eBUS protocol.
|
||||
*/
|
||||
class BusHandler : public WaitThread
|
||||
{
|
||||
public:
|
||||
|
||||
class BusHandler : public WaitThread {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param device the @a Device instance for accessing the bus.
|
||||
@@ -367,15 +353,14 @@ public:
|
||||
m_answer(answer), m_addressConflict(false),
|
||||
m_busLostRetries(busLostRetries), m_failedSendRetries(failedSendRetries),
|
||||
m_transferLatency(transferLatency), m_busAcquireTimeout(busAcquireTimeout), m_slaveRecvTimeout(slaveRecvTimeout),
|
||||
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount==0), m_lockCount(lockCount<=3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
|
||||
m_masterCount(device->isReadOnly()?0:1), m_autoLockCount(lockCount == 0), m_lockCount(lockCount <= 3 ? 3 : lockCount), m_remainLockCount(m_autoLockCount),
|
||||
m_generateSynInterval(generateSyn ? SYN_TIMEOUT*getMasterNumber(ownAddress)+SYMBOL_DURATION : 0),
|
||||
m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0),
|
||||
m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0),
|
||||
m_symPerSec(0), m_maxSymPerSec(0),
|
||||
m_state(bs_noSignal), m_repeat(false),
|
||||
m_command(false), m_commandCrcValid(false), m_response(false), m_responseCrcValid(false),
|
||||
m_grabMessages(true)
|
||||
{
|
||||
m_grabMessages(true) {
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
}
|
||||
|
||||
@@ -386,15 +371,15 @@ public:
|
||||
stop();
|
||||
join();
|
||||
BusRequest* req;
|
||||
while ((req = m_finishedRequests.pop())!=NULL) {
|
||||
while ((req = m_finishedRequests.pop()) != NULL) {
|
||||
delete req;
|
||||
}
|
||||
while ((req = m_nextRequests.pop())!=NULL) {
|
||||
while ((req = m_nextRequests.pop()) != NULL) {
|
||||
if (req->m_deleteOnFinish) {
|
||||
delete req;
|
||||
}
|
||||
}
|
||||
if (m_currentRequest!=NULL) {
|
||||
if (m_currentRequest != NULL) {
|
||||
delete m_currentRequest;
|
||||
m_currentRequest = NULL;
|
||||
}
|
||||
@@ -420,7 +405,7 @@ public:
|
||||
* @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction.
|
||||
* @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.
|
||||
@@ -432,7 +417,7 @@ public:
|
||||
* @param full true for a full scan (all slaves), false for scanning only already seen slaves.
|
||||
* @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.
|
||||
@@ -471,7 +456,7 @@ public:
|
||||
* @param enable true to enable grabbing, false to disable it.
|
||||
* @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.
|
||||
@@ -524,8 +509,8 @@ public:
|
||||
*/
|
||||
void setScanConfigLoaded(unsigned char address, string file);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handle the next symbol on the bus.
|
||||
* @return RESULT_OK on success, or an error code.
|
||||
@@ -539,7 +524,7 @@ private:
|
||||
* @param firstRepetition true if the first repetition of a message part is being started.
|
||||
* @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.
|
||||
@@ -663,7 +648,6 @@ private:
|
||||
|
||||
/** the grabbed messages by key.*/
|
||||
map<unsigned long long, GrabbedMessage> m_grabbedMessages;
|
||||
|
||||
};
|
||||
|
||||
#endif // BUSHANDLER_H_
|
||||
#endif // EBUSD_BUSHANDLER_H_
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "datahandler.h"
|
||||
#include <list>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "datahandler.h"
|
||||
#include <list>
|
||||
#ifdef HAVE_MQTT
|
||||
# include "mqtthandler.h"
|
||||
#endif
|
||||
@@ -38,21 +39,19 @@ static struct argp_child g_argp_children[
|
||||
+1
|
||||
];
|
||||
|
||||
const struct argp_child* datahandler_getargs()
|
||||
{
|
||||
const struct argp_child* datahandler_getargs() {
|
||||
size_t count = 0;
|
||||
#ifdef HAVE_MQTT
|
||||
g_argp_children[count++] = *mqtthandler_getargs();
|
||||
#endif
|
||||
if (count>0) {
|
||||
if (count > 0) {
|
||||
g_argp_children[count] = g_last_argp_child;
|
||||
return g_argp_children;
|
||||
}
|
||||
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;
|
||||
#ifdef HAVE_MQTT
|
||||
DataHandler* handler = mqtthandler_register(busHandler, messages);
|
||||
@@ -65,7 +64,6 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
|
||||
return success;
|
||||
}
|
||||
|
||||
void DataSink::notifyUpdate(Message* message)
|
||||
{
|
||||
void DataSink::notifyUpdate(Message* message) {
|
||||
m_updatedMessages[message]++;
|
||||
}
|
||||
|
||||
+14
-20
@@ -16,12 +16,14 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DATAHANDLER_H_
|
||||
#define DATAHANDLER_H_
|
||||
#ifndef EBUSD_DATAHANDLER_H_
|
||||
#define EBUSD_DATAHANDLER_H_
|
||||
|
||||
#include <argp.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "bushandler.h"
|
||||
#include "message.h"
|
||||
#include <argp.h>
|
||||
|
||||
/** @file datahandler.h
|
||||
* Classes and functions for implementing and registering generic data sinks
|
||||
@@ -52,9 +54,8 @@ bool datahandler_register(BusHandler* busHandler, MessageMap* messages, list<Dat
|
||||
/**
|
||||
* Base class for all kinds of data handlers.
|
||||
*/
|
||||
class DataHandler
|
||||
{
|
||||
public:
|
||||
class DataHandler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -81,17 +82,14 @@ public:
|
||||
* @return whether this is a @a DataSource instance.
|
||||
*/
|
||||
virtual bool isDataSource() { return false; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base class for listening to data updates.
|
||||
*/
|
||||
class DataSink : virtual public DataHandler
|
||||
{
|
||||
public:
|
||||
|
||||
class DataSink : virtual public DataHandler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -111,21 +109,18 @@ public:
|
||||
// @copydoc
|
||||
virtual bool isDataSink() { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** a map of updated @p Message instances. */
|
||||
map<Message*, int> m_updatedMessages;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base class providing data to be sent on the bus.
|
||||
*/
|
||||
class DataSource : virtual public DataHandler
|
||||
{
|
||||
public:
|
||||
|
||||
class DataSource : virtual public DataHandler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param busHandler the @a BusHandler instance.
|
||||
@@ -141,11 +136,10 @@ public:
|
||||
// @copydoc
|
||||
virtual bool isDataSource() { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** the @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
};
|
||||
|
||||
#endif // DATAHANDLER_H_
|
||||
#endif // EBUSD_DATAHANDLER_H_
|
||||
|
||||
+88
-90
@@ -21,19 +21,22 @@
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
#include "mainloop.h"
|
||||
#include "bushandler.h"
|
||||
#include "log.h"
|
||||
#include "rotatefile.h"
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <argp.h>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "mainloop.h"
|
||||
#include "bushandler.h"
|
||||
#include "log.h"
|
||||
#include "rotatefile.h"
|
||||
|
||||
/** the path and name of the PID file. */
|
||||
#ifdef PACKAGE_PIDFILE
|
||||
@@ -207,8 +210,7 @@ static map<string, DataFieldTemplates*> s_templatesByPath;
|
||||
* @param arg the option argument, or NULL.
|
||||
* @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;
|
||||
result_t result = RESULT_OK;
|
||||
|
||||
@@ -278,8 +280,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
}
|
||||
break;
|
||||
case O_CHKCFG: // --checkconfig
|
||||
if (opt->checkConfig==0)
|
||||
if (opt->checkConfig == 0) {
|
||||
opt->checkConfig = 1;
|
||||
}
|
||||
break;
|
||||
case O_DMPCFG: // --dumpconfig
|
||||
opt->checkConfig = 2;
|
||||
@@ -466,8 +469,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void daemonize()
|
||||
{
|
||||
void daemonize() {
|
||||
// fork off the parent process
|
||||
pid_t pid = fork();
|
||||
|
||||
@@ -477,9 +479,9 @@ void daemonize()
|
||||
}
|
||||
|
||||
// If we got a good PID, then we can exit the parent process
|
||||
if (pid > 0)
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
// At this point we are executing as the child process
|
||||
|
||||
// Create a new SID for the child process and
|
||||
@@ -509,7 +511,7 @@ void daemonize()
|
||||
if (pidFile != NULL) {
|
||||
setbuf(pidFile, NULL); // disable buffering
|
||||
if (lockf(fileno(pidFile), F_TLOCK, 0) < 0
|
||||
|| fprintf(pidFile, "%d\n", getpid()) <=0) {
|
||||
|| fprintf(pidFile, "%d\n", getpid()) <= 0) {
|
||||
fclose(pidFile);
|
||||
pidFile = NULL;
|
||||
}
|
||||
@@ -522,12 +524,11 @@ void daemonize()
|
||||
isDaemon = true;
|
||||
}
|
||||
|
||||
void closePidFile()
|
||||
{
|
||||
void closePidFile() {
|
||||
if (pidFile != NULL) {
|
||||
if (fclose(pidFile) != 0)
|
||||
if (fclose(pidFile) != 0) {
|
||||
return;
|
||||
|
||||
}
|
||||
remove(opt.pidFile);
|
||||
}
|
||||
}
|
||||
@@ -535,20 +536,19 @@ void closePidFile()
|
||||
/**
|
||||
* Helper method performing shutdown.
|
||||
*/
|
||||
void shutdown()
|
||||
{
|
||||
void shutdown() {
|
||||
// stop main loop and all dependent components
|
||||
if (s_mainLoop != NULL) {
|
||||
delete s_mainLoop;
|
||||
s_mainLoop = NULL;
|
||||
}
|
||||
if (s_messageMap!=NULL) {
|
||||
if (s_messageMap != NULL) {
|
||||
delete s_messageMap;
|
||||
s_messageMap = NULL;
|
||||
}
|
||||
// free templates
|
||||
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;
|
||||
}
|
||||
it->second = NULL;
|
||||
@@ -573,8 +573,7 @@ void shutdown()
|
||||
* The signal handling function.
|
||||
* @param sig the received signal.
|
||||
*/
|
||||
void signalHandler(int sig)
|
||||
{
|
||||
void signalHandler(int sig) {
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
logNotice(lf_main, "SIGHUP received");
|
||||
@@ -604,37 +603,36 @@ void signalHandler(int sig)
|
||||
* @return the result code.
|
||||
*/
|
||||
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());
|
||||
|
||||
if (dir == NULL)
|
||||
if (dir == NULL) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
|
||||
}
|
||||
dirent* d;
|
||||
while ((d = readdir(dir)) != NULL) {
|
||||
string name = d->d_name;
|
||||
|
||||
if (name == "." || name == "..")
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
|
||||
}
|
||||
const string p = path + "/" + name;
|
||||
struct stat stat_buf;
|
||||
|
||||
if (stat(p.c_str(), &stat_buf) != 0)
|
||||
if (stat(p.c_str(), &stat_buf) != 0) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (S_ISDIR(stat_buf.st_mode)) {
|
||||
if (dirs!=NULL)
|
||||
if (dirs != NULL) {
|
||||
dirs->push_back(p);
|
||||
} else if (S_ISREG(stat_buf.st_mode) && name.length()>=extension.length()
|
||||
&& name.substr(name.length()-extension.length())==extension) {
|
||||
if (name=="_templates"+extension) {
|
||||
}
|
||||
} else if (S_ISREG(stat_buf.st_mode) && name.length() >= extension.length()
|
||||
&& name.substr(name.length()-extension.length()) == extension) {
|
||||
if (name == "_templates"+extension) {
|
||||
if (hasTemplates) {
|
||||
*hasTemplates = true;
|
||||
}
|
||||
} else if (prefix.length()==0 || (name.length()>=prefix.length() && name.substr(0, prefix.length())==prefix)) {
|
||||
} else if (prefix.length() == 0 || (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
|
||||
files.push_back(p);
|
||||
}
|
||||
}
|
||||
@@ -647,11 +645,11 @@ static result_t collectConfigFiles(const string path, const string prefix, const
|
||||
DataFieldTemplates* getTemplates(const string filename) {
|
||||
string path;
|
||||
size_t pos = filename.find_last_of('/');
|
||||
if (pos!=string::npos) {
|
||||
if (pos != string::npos) {
|
||||
path = filename.substr(0, pos);
|
||||
}
|
||||
map<string, DataFieldTemplates*>::iterator it = s_templatesByPath.find(path);
|
||||
if (it!=s_templatesByPath.end()) {
|
||||
if (it != s_templatesByPath.end()) {
|
||||
return it->second;
|
||||
}
|
||||
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 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);
|
||||
if (it!=s_templatesByPath.end()) {
|
||||
if (it != s_templatesByPath.end()) {
|
||||
return false;
|
||||
}
|
||||
DataFieldTemplates* templates;
|
||||
if (path==opt.configPath || !available) {
|
||||
if (path == opt.configPath || !available) {
|
||||
templates = &s_globalTemplates;
|
||||
} else {
|
||||
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.
|
||||
* @return the result code.
|
||||
*/
|
||||
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose)
|
||||
{
|
||||
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, bool verbose) {
|
||||
vector<string> files, dirs;
|
||||
bool hasTemplates = false;
|
||||
result_t result = collectConfigFiles(path, "", extension, files, &dirs, &hasTemplates);
|
||||
if (result!=RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
readTemplates(path, extension, hasTemplates, verbose);
|
||||
for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
|
||||
string name = *it;
|
||||
logInfo(lf_main, "reading file %s", name.c_str());
|
||||
result_t result = messages->readFromFile(name, verbose);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (recursive) {
|
||||
for (vector<string>::iterator it = dirs.begin(); it != dirs.end(); it++) {
|
||||
string name = *it;
|
||||
logInfo(lf_main, "reading dir %s", name.c_str());
|
||||
result_t result = readConfigFiles(name, extension, messages, true, verbose);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RESULT_OK;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for immediate reading of a @a Message from the bus.
|
||||
* @param message the @a Message to read.
|
||||
*/
|
||||
void readMessage(Message* message)
|
||||
{
|
||||
void readMessage(Message* message) {
|
||||
if (!s_mainLoop || !message) {
|
||||
return;
|
||||
}
|
||||
@@ -749,8 +747,7 @@ void readMessage(Message* message)
|
||||
* @param messages the @a MessageMap instance.
|
||||
* @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);
|
||||
if (result != RESULT_OK) {
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
messages->clear();
|
||||
s_globalTemplates.clear();
|
||||
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;
|
||||
}
|
||||
it->second = NULL;
|
||||
@@ -788,19 +784,18 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose)
|
||||
{
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose) {
|
||||
PartType partType;
|
||||
if (isMaster(address)) {
|
||||
address = (unsigned char)(data[0]+5); // slave address of sending master
|
||||
partType = pt_masterData;
|
||||
if (data.size()<5+1+5+2+2) { // skip QQ ZZ PB SB NN
|
||||
if (data.size() < 5+1+5+2+2) { // skip QQ ZZ PB SB NN
|
||||
logError(lf_main, "unable to load scan config %2.2x: master part too short", address);
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
} else {
|
||||
partType = pt_slaveData;
|
||||
if (data.size()<1+1+5+2+2) { // skip NN
|
||||
if (data.size() < 1+1+5+2+2) { // skip NN
|
||||
logError(lf_main, "unable to load scan config %2.2x: slave part too short", address);
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
@@ -812,9 +807,10 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
unsigned char offset = 0;
|
||||
size_t field = 0;
|
||||
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
|
||||
if (result==RESULT_OK) {
|
||||
}
|
||||
if (result == RESULT_OK) {
|
||||
path = out.str();
|
||||
transform(path.begin(), path.end(), path.begin(), ::tolower);
|
||||
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));
|
||||
result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
|
||||
}
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
ident = out.str();
|
||||
out.str("");
|
||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
|
||||
}
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||
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));
|
||||
return result;
|
||||
}
|
||||
@@ -844,7 +840,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
bool hasTemplates = false;
|
||||
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
|
||||
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));
|
||||
return result;
|
||||
}
|
||||
@@ -853,7 +849,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
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));
|
||||
for (string::iterator it = ident.begin(); it!=ident.end(); it++) {
|
||||
for (string::iterator it = ident.begin(); it != ident.end(); it++) {
|
||||
if (::isspace(*it)) {
|
||||
ident.erase(it--);
|
||||
} 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
|
||||
size_t bestMatch = 0;
|
||||
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;
|
||||
unsigned char checkDest;
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
size_t match = 1;
|
||||
if (!checkIdent.empty()) {
|
||||
string remain = ident;
|
||||
bool matches = false;
|
||||
while (remain.length()>0 && remain.length()>=checkIdent.length()) {
|
||||
if (checkIdent==remain) {
|
||||
while (remain.length() > 0 && remain.length() >= checkIdent.length()) {
|
||||
if (checkIdent == remain) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
if (remain[remain.length()-1]<'0' || remain[remain.length()-1]>'9')
|
||||
if (remain[remain.length()-1] < '0' || remain[remain.length()-1] > '9') {
|
||||
break;
|
||||
}
|
||||
remain.erase(remain.length()-1); // remove trailing digit
|
||||
}
|
||||
if (!matches) {
|
||||
@@ -892,7 +889,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
}
|
||||
match += remain.length();
|
||||
}
|
||||
if (match>=bestMatch) {
|
||||
if (match >= bestMatch) {
|
||||
bestMatch = match;
|
||||
best = name;
|
||||
}
|
||||
@@ -908,25 +905,27 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
bool readCommon = readTemplates(path, ".csv", hasTemplates, opt.checkConfig);
|
||||
if (readCommon) {
|
||||
result = collectConfigFiles(path, "", ".csv", files);
|
||||
if (result==RESULT_OK && !files.empty()) {
|
||||
for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) {
|
||||
if (result == RESULT_OK && !files.empty()) {
|
||||
for (vector<string>::iterator it = files.begin(); it != files.end(); it++) {
|
||||
string name = *it;
|
||||
name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
|
||||
if (name=="_templates.") // skip templates
|
||||
if (name == "_templates.") { // skip templates
|
||||
continue;
|
||||
if (name.length()<3 || name.find_first_of('.')!=2) { // different from the scheme "ZZ."
|
||||
}
|
||||
if (name.length() < 3 || name.find_first_of('.') != 2) { // different from the scheme "ZZ."
|
||||
name = *it;
|
||||
result = messages->readFromFile(name, opt.checkConfig);
|
||||
if (result==RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
return result;
|
||||
}
|
||||
@@ -943,8 +942,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
||||
* @param argc the number of 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 };
|
||||
int arg_index = -1;
|
||||
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
|
||||
string arg = argv[arg_index++];
|
||||
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());
|
||||
continue;
|
||||
}
|
||||
SymbolString master(false), slave(false);
|
||||
result_t res = master.parseHex(arg.substr(0, pos));
|
||||
if (res==RESULT_OK) {
|
||||
if (res == RESULT_OK) {
|
||||
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));
|
||||
continue;
|
||||
}
|
||||
if (master.size()<5) { // skip QQ ZZ PB SB NN
|
||||
if (master.size() < 5) { // skip QQ ZZ PB SB NN
|
||||
logError(lf_main, "invalid scan message %s: master part too short", arg.c_str());
|
||||
continue;
|
||||
}
|
||||
@@ -988,7 +986,7 @@ int main(int argc, char* argv[])
|
||||
message->storeLastData(master, slave);
|
||||
string file;
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -1027,7 +1025,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// load configuration files
|
||||
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");
|
||||
}
|
||||
// wait for end of MainLoop
|
||||
|
||||
+10
-10
@@ -16,19 +16,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAIN_H_
|
||||
#define MAIN_H_
|
||||
#ifndef EBUSD_MAIN_H_
|
||||
#define EBUSD_MAIN_H_
|
||||
|
||||
#include "result.h"
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "data.h"
|
||||
#include "message.h"
|
||||
#include <stdint.h>
|
||||
#include "result.h"
|
||||
|
||||
/** \file main.h */
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options
|
||||
{
|
||||
struct options {
|
||||
const char* device; //!< eBUS device (serial device or [udp:]ip:port) [/dev/ttyUSB0]
|
||||
bool noDeviceCheck; //!< skip serial eBUS device test
|
||||
bool readOnly; //!< read-only access to the device
|
||||
@@ -38,7 +38,7 @@ struct options
|
||||
const char* configPath; //!< path to CSV configuration files [/etc/ebusd]
|
||||
bool scanConfig; //!< pick configuration files matching initial scan
|
||||
unsigned char initialScan; //!< the initial address to scan for scanconfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address)
|
||||
int checkConfig; //!< check CSV config files (!=0) and optionally dump (2), then stop
|
||||
int checkConfig; //!< check CSV config files ( != 0) and optionally dump (2), then stop
|
||||
int pollInterval; //!< poll interval in seconds, 0 to disable [5]
|
||||
|
||||
unsigned char address; //!< own bus address [31]
|
||||
@@ -83,7 +83,7 @@ DataFieldTemplates* getTemplates(const string filename);
|
||||
* @param denyRecursive whether to avoid loading all files recursively (e.g. for scan config check).
|
||||
* @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.
|
||||
@@ -94,6 +94,6 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose=false, bool denyRecu
|
||||
* @param verbose whether to verbosely log problems.
|
||||
* @return the result code.
|
||||
*/
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose=false);
|
||||
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile, bool verbose = false);
|
||||
|
||||
#endif // MAIN_H_
|
||||
#endif // EBUSD_MAIN_H_
|
||||
|
||||
+244
-208
File diff suppressed because it is too large
Load Diff
+12
-15
@@ -16,17 +16,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAINLOOP_H_
|
||||
#define MAINLOOP_H_
|
||||
#ifndef EBUSD_MAINLOOP_H_
|
||||
#define EBUSD_MAINLOOP_H_
|
||||
|
||||
#include "message.h"
|
||||
#include "network.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "bushandler.h"
|
||||
#include "datahandler.h"
|
||||
#include "network.h"
|
||||
#include "message.h"
|
||||
#include "rotatefile.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/** \file mainloop.h */
|
||||
|
||||
@@ -35,10 +35,8 @@ using namespace std;
|
||||
/**
|
||||
* The main loop handling requests from connected clients.
|
||||
*/
|
||||
class MainLoop : public Thread, DeviceListener
|
||||
{
|
||||
public:
|
||||
|
||||
class MainLoop : public Thread, DeviceListener {
|
||||
public:
|
||||
/**
|
||||
* Construct the main loop and create network and bus handling components.
|
||||
* @param opt the program options.
|
||||
@@ -67,13 +65,13 @@ public:
|
||||
// @copydoc
|
||||
virtual void notifyDeviceData(const unsigned char byte, bool received);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Decode and execute client message.
|
||||
* @param data the data string to decode (may be empty).
|
||||
@@ -252,7 +250,6 @@ private:
|
||||
|
||||
/** the registered @a DataHandler instances. */
|
||||
list<DataHandler*> m_dataHandlers;
|
||||
|
||||
};
|
||||
|
||||
#endif // MAINLOOP_H_
|
||||
#endif // EBUSD_MAINLOOP_H_
|
||||
|
||||
+58
-70
@@ -16,12 +16,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mqtthandler.h"
|
||||
#include "log.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "mqtthandler.h"
|
||||
#include "log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** the definition of the MQTT arguments. */
|
||||
@@ -45,13 +46,12 @@ static const char* g_topic = PACKAGE; //!< MQTT topic to use (prefix if without
|
||||
* @param arg the option argument, or NULL.
|
||||
* @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;
|
||||
|
||||
switch (key) {
|
||||
case 1: // --mqtthost=localhost
|
||||
if (arg == NULL || arg[0] == 0 || arg[0]=='/' || arg[strlen(arg)-1]=='/') {
|
||||
if (arg == NULL || arg[0] == 0) {
|
||||
argp_error(state, "invalid mqtthost");
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state)
|
||||
break;
|
||||
|
||||
case 3: // --mqtttopic=ebusd
|
||||
if (arg == NULL || arg[0] == 0 || arg[0]=='/' || arg[strlen(arg)-1]=='/') {
|
||||
if (arg == NULL || arg[0] == 0 || arg[0] == '/' || arg[strlen(arg)-1] == '/') {
|
||||
argp_error(state, "invalid mqtttopic");
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -82,13 +82,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_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;
|
||||
}
|
||||
|
||||
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages)
|
||||
{
|
||||
DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages) {
|
||||
return new MqttHandler(busHandler, messages);
|
||||
}
|
||||
|
||||
@@ -121,21 +119,21 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
|
||||
size_t lastpos = 0;
|
||||
size_t end = topic.length();
|
||||
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 len = 0;
|
||||
for (size_t i = 0; i < columnCount; i++) {
|
||||
len = strlen(columnNames[i]);
|
||||
if (topic.substr(pos+1, len)==columnNames[i]) {
|
||||
if (topic.substr(pos+1, len) == columnNames[i]) {
|
||||
col = columnIds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (col==columnCount) {
|
||||
if (col == columnCount) {
|
||||
return false;
|
||||
}
|
||||
for (vector<size_t>::iterator it=cols.begin(); it!=cols.end(); it++) {
|
||||
if (*it==col) {
|
||||
for (vector<size_t>::iterator it=cols.begin(); it != cols.end(); it++) {
|
||||
if (*it == col) {
|
||||
return false; // duplicate column
|
||||
}
|
||||
}
|
||||
@@ -144,7 +142,7 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
|
||||
lastpos = pos+1+len;
|
||||
pos = topic.find('%', lastpos);
|
||||
}
|
||||
if (lastpos<end) {
|
||||
if (lastpos < end) {
|
||||
strs.push_back(topic.substr(lastpos, end-lastpos));
|
||||
}
|
||||
return true;
|
||||
@@ -152,9 +150,8 @@ bool parseTopic(const string topic, vector<string> &strs, vector<size_t> &cols)
|
||||
|
||||
|
||||
MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
: DataSink(), DataSource(busHandler), Thread(), m_messages(messages)
|
||||
{
|
||||
bool enabled = g_port!=0;
|
||||
: DataSink(), DataSource(busHandler), Thread(), m_messages(messages) {
|
||||
bool enabled = g_port != 0;
|
||||
m_publishByField = false;
|
||||
m_mosquitto = NULL;
|
||||
if (enabled && !parseTopic(g_topic, m_topicStrs, m_topicCols)) {
|
||||
@@ -166,7 +163,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
}
|
||||
int major = -1;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@@ -175,7 +172,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
m_topicStrs.push_back("");
|
||||
} else {
|
||||
string str = m_topicStrs[0];
|
||||
if (str.empty() || str[str.length()-1]!='/') {
|
||||
if (str.empty() || str[str.length()-1] != '/') {
|
||||
m_topicStrs[0] = str+"/";
|
||||
}
|
||||
}
|
||||
@@ -183,8 +180,8 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
m_topicStrs.push_back("/");
|
||||
m_topicCols.push_back(COLUMN_NAME); // name
|
||||
} else {
|
||||
for (size_t i=0; i<m_topicCols.size(); i++) {
|
||||
if (m_topicCols[i]==COLUMN_FIELDS) { // fields
|
||||
for (size_t i = 0; i < m_topicCols.size(); i++) {
|
||||
if (m_topicCols[i] == COLUMN_FIELDS) { // fields
|
||||
m_publishByField = true;
|
||||
break;
|
||||
}
|
||||
@@ -192,13 +189,13 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
}
|
||||
m_globalTopic = getTopic(NULL)+"global/";
|
||||
m_mosquitto = NULL;
|
||||
if (mosquitto_lib_init()!=MOSQ_ERR_SUCCESS) {
|
||||
if (mosquitto_lib_init() != MOSQ_ERR_SUCCESS) {
|
||||
logOtherError("mqtt", "unable to initialize");
|
||||
} else {
|
||||
string clientId = PACKAGE_STRING;
|
||||
clientId += " "+static_cast<unsigned>(getpid());
|
||||
m_mosquitto = mosquitto_new(clientId.c_str(),
|
||||
#if (LIBMOSQUITTO_MAJOR>=1)
|
||||
#if (LIBMOSQUITTO_MAJOR >= 1)
|
||||
true,
|
||||
#endif
|
||||
this);
|
||||
@@ -213,15 +210,15 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
string willData = "false";
|
||||
size_t len = willData.length();
|
||||
mosquitto_will_set(m_mosquitto,
|
||||
#if (LIBMOSQUITTO_MAJOR<1)
|
||||
#if (LIBMOSQUITTO_MAJOR < 1)
|
||||
true,
|
||||
#endif
|
||||
willTopic.c_str(), (uint32_t)len, (uint8_t*)(willData.c_str()), 0, true);
|
||||
if (mosquitto_connect(m_mosquitto, g_host, g_port, 60
|
||||
#if (LIBMOSQUITTO_MAJOR<1)
|
||||
#if (LIBMOSQUITTO_MAJOR < 1)
|
||||
, true
|
||||
#endif
|
||||
)!=MOSQ_ERR_SUCCESS) {
|
||||
) != MOSQ_ERR_SUCCESS) {
|
||||
logOtherError("mqtt", "unable to connect");
|
||||
mosquitto_destroy(m_mosquitto);
|
||||
m_mosquitto = NULL;
|
||||
@@ -231,8 +228,7 @@ MqttHandler::MqttHandler(BusHandler* busHandler, MessageMap* messages)
|
||||
}
|
||||
}
|
||||
|
||||
MqttHandler::~MqttHandler()
|
||||
{
|
||||
MqttHandler::~MqttHandler() {
|
||||
join();
|
||||
if (m_mosquitto) {
|
||||
mosquitto_destroy(m_mosquitto);
|
||||
@@ -241,32 +237,29 @@ MqttHandler::~MqttHandler()
|
||||
mosquitto_lib_cleanup();
|
||||
}
|
||||
|
||||
void MqttHandler::start()
|
||||
{
|
||||
void MqttHandler::start() {
|
||||
if (m_mosquitto) {
|
||||
Thread::start("MQTT");
|
||||
}
|
||||
}
|
||||
|
||||
void on_message(
|
||||
#if (LIBMOSQUITTO_MAJOR>=1)
|
||||
#if (LIBMOSQUITTO_MAJOR >= 1)
|
||||
struct mosquitto *mosq,
|
||||
#endif
|
||||
void *obj, const struct mosquitto_message *message)
|
||||
{
|
||||
void *obj, const struct mosquitto_message *message) {
|
||||
MqttHandler* handler = (MqttHandler*)obj;
|
||||
if (!handler || !message || !handler->isRunning()) {
|
||||
return;
|
||||
}
|
||||
string topic(message->topic);
|
||||
string data(message->payloadlen>0 ? (char*)message->payload : "");
|
||||
string data(message->payloadlen > 0 ? (char*)message->payload : "");
|
||||
handler->notifyTopic(topic, data);
|
||||
}
|
||||
|
||||
void MqttHandler::notifyTopic(string topic, string data)
|
||||
{
|
||||
void MqttHandler::notifyTopic(string topic, string data) {
|
||||
size_t pos = topic.rfind('/');
|
||||
if (pos==string::npos) {
|
||||
if (pos == string::npos) {
|
||||
return;
|
||||
}
|
||||
string suffix = topic.substr(pos+1);
|
||||
@@ -275,8 +268,8 @@ void MqttHandler::notifyTopic(string topic, string data)
|
||||
return;
|
||||
}
|
||||
string direction = suffix.substr(0, 3);
|
||||
isWrite = direction=="set";
|
||||
if (!isWrite && direction!="get") {
|
||||
isWrite = direction == "set";
|
||||
if (!isWrite && direction != "get") {
|
||||
return;
|
||||
}
|
||||
suffix = suffix.substr(3); // security level
|
||||
@@ -285,26 +278,26 @@ void MqttHandler::notifyTopic(string topic, string data)
|
||||
size_t last = 0;
|
||||
string circuit, name;
|
||||
size_t idx;
|
||||
for (idx=0; idx<m_topicStrs.size()+1; idx++) {
|
||||
for (idx = 0; idx < m_topicStrs.size()+1; idx++) {
|
||||
string field;
|
||||
string chk;
|
||||
if (idx<m_topicStrs.size()) {
|
||||
if (idx < m_topicStrs.size()) {
|
||||
chk = m_topicStrs[idx];
|
||||
pos = remain.find(chk, last);
|
||||
if (pos==string::npos) {
|
||||
if (pos == string::npos) {
|
||||
return;
|
||||
}
|
||||
} else if (idx-1<m_topicCols.size()) {
|
||||
} else if (idx-1 < m_topicCols.size()) {
|
||||
pos = remain.size();
|
||||
} else if (last<remain.size()) {
|
||||
} else if (last < remain.size()) {
|
||||
return;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
field = remain.substr(last, pos-last);
|
||||
last = pos+chk.size();
|
||||
if (idx==0) {
|
||||
if (pos>0) {
|
||||
if (idx == 0) {
|
||||
if (pos > 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -330,20 +323,20 @@ void MqttHandler::notifyTopic(string topic, string data)
|
||||
return;
|
||||
}
|
||||
logOtherInfo("mqtt", "received topic for %s %s", circuit.c_str(), name.c_str());
|
||||
if (suffix.length()>0) {
|
||||
if (suffix.length() > 0) {
|
||||
circuit += "#"+suffix;
|
||||
}
|
||||
Message* message = m_messages->find(circuit, name, isWrite);
|
||||
if (message==NULL) {
|
||||
if (message == NULL) {
|
||||
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());
|
||||
return;
|
||||
}
|
||||
if (!message->isPassive()) {
|
||||
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));
|
||||
return;
|
||||
}
|
||||
@@ -353,8 +346,7 @@ void MqttHandler::notifyTopic(string topic, string data)
|
||||
publishMessage(message, ostream);
|
||||
}
|
||||
|
||||
void MqttHandler::run()
|
||||
{
|
||||
void MqttHandler::run() {
|
||||
time_t lastTaskRun, now, start, lastSignal = 0;
|
||||
bool signal = false;
|
||||
string signalTopic = m_globalTopic+"signal";
|
||||
@@ -372,9 +364,9 @@ void MqttHandler::run()
|
||||
while (isRunning()) {
|
||||
handleTraffic();
|
||||
time(&now);
|
||||
if (now<start) {
|
||||
if (now < start) {
|
||||
// clock skew
|
||||
if (now<lastSignal) {
|
||||
if (now < lastSignal) {
|
||||
lastSignal -= lastTaskRun-now;
|
||||
}
|
||||
lastTaskRun = now;
|
||||
@@ -411,27 +403,25 @@ void MqttHandler::run()
|
||||
}
|
||||
}
|
||||
|
||||
void MqttHandler::handleTraffic()
|
||||
{
|
||||
void MqttHandler::handleTraffic() {
|
||||
if (m_mosquitto) {
|
||||
mosquitto_loop(m_mosquitto, -1
|
||||
#if (LIBMOSQUITTO_MAJOR>=1)
|
||||
,1
|
||||
#if (LIBMOSQUITTO_MAJOR >= 1)
|
||||
, 1
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
string MqttHandler::getTopic(Message* message, signed char fieldIndex)
|
||||
{
|
||||
string MqttHandler::getTopic(Message* message, signed char fieldIndex) {
|
||||
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];
|
||||
if (!message) {
|
||||
break;
|
||||
}
|
||||
if (i<m_topicCols.size()) {
|
||||
if (m_topicCols[i]==COLUMN_FIELDS && fieldIndex>=0) {
|
||||
if (i < m_topicCols.size()) {
|
||||
if (m_topicCols[i] == COLUMN_FIELDS && fieldIndex >= 0) {
|
||||
ret << message->getFieldName(fieldIndex);
|
||||
} else {
|
||||
message->dumpColumn(ret, m_topicCols[i]);
|
||||
@@ -441,10 +431,9 @@ string MqttHandler::getTopic(Message* message, signed char fieldIndex)
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
void MqttHandler::publishMessage(Message* message, ostringstream& updates)
|
||||
{
|
||||
void MqttHandler::publishMessage(Message* message, ostringstream& 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));
|
||||
return;
|
||||
}
|
||||
@@ -462,8 +451,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());
|
||||
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), (uint8_t*)(data.c_str()), 0, retain);
|
||||
}
|
||||
|
||||
+13
-13
@@ -16,13 +16,16 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MQTTHANDLER_H_
|
||||
#define MQTTHANDLER_H_
|
||||
#ifndef EBUSD_MQTTHANDLER_H_
|
||||
#define EBUSD_MQTTHANDLER_H_
|
||||
|
||||
#include <mosquitto.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "datahandler.h"
|
||||
#include "bushandler.h"
|
||||
#include "message.h"
|
||||
#include <mosquitto.h>
|
||||
|
||||
/** @file mqtthandler.h
|
||||
* A data handler enabling MQTT support via mosquitto.
|
||||
@@ -47,10 +50,8 @@ DataHandler* mqtthandler_register(BusHandler* busHandler, MessageMap* messages);
|
||||
/**
|
||||
* The main class supporting MQTT data handling.
|
||||
*/
|
||||
class MqttHandler : public DataSink, public DataSource, public Thread
|
||||
{
|
||||
public:
|
||||
|
||||
class MqttHandler : public DataSink, public DataSource, public Thread {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param busHandler the @a BusHandler instance.
|
||||
@@ -73,13 +74,13 @@ public:
|
||||
*/
|
||||
void notifyTopic(string topic, string data);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called regularly to handle MQTT traffic.
|
||||
*/
|
||||
@@ -91,7 +92,7 @@ private:
|
||||
* @param fieldIndex the optional field index for the field column, or -1.
|
||||
* @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.
|
||||
@@ -106,7 +107,7 @@ private:
|
||||
* @param data the data string.
|
||||
* @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. */
|
||||
MessageMap* m_messages;
|
||||
@@ -125,7 +126,6 @@ private:
|
||||
|
||||
/** the mosquitto structure if initialized, or NULL. */
|
||||
struct mosquitto* m_mosquitto;
|
||||
|
||||
};
|
||||
|
||||
#endif // DATAHANDLER_H_
|
||||
#endif // EBUSD_MQTTHANDLER_H_
|
||||
|
||||
+9
-17
@@ -21,19 +21,17 @@
|
||||
#endif
|
||||
|
||||
#include "network.h"
|
||||
#include "log.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include "log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int Connection::m_ids = 0;
|
||||
|
||||
void Connection::run()
|
||||
{
|
||||
void Connection::run() {
|
||||
int ret;
|
||||
struct timespec tdiff;
|
||||
|
||||
@@ -143,7 +141,6 @@ void Connection::run()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete m_socket;
|
||||
@@ -153,14 +150,13 @@ void Connection::run()
|
||||
|
||||
|
||||
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");
|
||||
|
||||
if (m_tcpServer != NULL && m_tcpServer->start() == 0) {
|
||||
m_listening = true;
|
||||
}
|
||||
if (httpPort>0) {
|
||||
if (httpPort > 0) {
|
||||
m_httpServer = new TCPServer(httpPort, "0.0.0.0");
|
||||
m_httpServer->start();
|
||||
} else {
|
||||
@@ -168,8 +164,7 @@ Network::Network(const bool local, const uint16_t port, const uint16_t httpPort,
|
||||
}
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
{
|
||||
Network::~Network() {
|
||||
stop();
|
||||
while (!m_connections.empty()) {
|
||||
Connection* connection = m_connections.back();
|
||||
@@ -188,8 +183,7 @@ Network::~Network()
|
||||
join();
|
||||
}
|
||||
|
||||
void Network::run()
|
||||
{
|
||||
void Network::run() {
|
||||
if (!m_listening) {
|
||||
return;
|
||||
}
|
||||
@@ -230,12 +224,11 @@ void Network::run()
|
||||
|
||||
maxfd = (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();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
#ifdef HAVE_PPOLL
|
||||
// wait for new fd event
|
||||
@@ -294,8 +287,7 @@ void Network::run()
|
||||
}
|
||||
}
|
||||
|
||||
void Network::cleanConnections()
|
||||
{
|
||||
void Network::cleanConnections() {
|
||||
list<Connection*>::iterator c_it;
|
||||
for (c_it = m_connections.begin(); c_it != m_connections.end(); c_it++) {
|
||||
if (!(*c_it)->isRunning()) {
|
||||
|
||||
+40
-47
@@ -16,16 +16,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORK_H_
|
||||
#define NETWORK_H_
|
||||
#ifndef EBUSD_NETWORK_H_
|
||||
#define EBUSD_NETWORK_H_
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include "tcpsocket.h"
|
||||
#include "queue.h"
|
||||
#include "notify.h"
|
||||
#include "thread.h"
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
|
||||
/** \file network.h */
|
||||
|
||||
@@ -37,17 +38,14 @@ class Connection;
|
||||
/**
|
||||
* Class for data/message transfer between @a Connection and @a MainLoop.
|
||||
*/
|
||||
class NetMessage
|
||||
{
|
||||
|
||||
public:
|
||||
class NetMessage {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param isHttp whether this is a HTTP message.
|
||||
*/
|
||||
NetMessage(const bool isHttp)
|
||||
: m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listening(false), m_listenSince(0)
|
||||
{
|
||||
: m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listening(false), m_listenSince(0) {
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
}
|
||||
@@ -55,56 +53,56 @@ public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~NetMessage()
|
||||
{
|
||||
~NetMessage() {
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
*/
|
||||
NetMessage(const NetMessage& src);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Add request data received from the client.
|
||||
* @param request the request data from the client.
|
||||
* @return true when the request is complete and the response shall be prepared.
|
||||
*/
|
||||
bool add(string request)
|
||||
{
|
||||
if (request.length()>0) {
|
||||
bool add(string request) {
|
||||
if (request.length() > 0) {
|
||||
request.erase(remove(request.begin(), request.end(), '\r'), request.end());
|
||||
m_request.append(request);
|
||||
}
|
||||
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
|
||||
if (pos!=string::npos) {
|
||||
if (pos != string::npos) {
|
||||
if (m_isHttp) {
|
||||
pos = m_request.find("\n");
|
||||
m_request.resize(pos); // reduce to first line
|
||||
// typical first line: GET /ehp/outsidetemp HTTP/1.1
|
||||
pos = m_request.rfind(" HTTP/");
|
||||
if (pos!=string::npos) {
|
||||
if (pos != string::npos) {
|
||||
m_request.resize(pos); // remove "HTTP/x.x" suffix
|
||||
}
|
||||
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;
|
||||
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;
|
||||
m_request[pos] = (char)(((value1&0x0f)<<4)|(value2&0x0f));
|
||||
}
|
||||
m_request[pos] = (char)(((value1&0x0f)<<4) | (value2&0x0f));
|
||||
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
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return m_request.length()==0 && m_listening;
|
||||
return m_request.length() == 0 && m_listening;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,8 +121,7 @@ public:
|
||||
* Wait for the result being set and return the result string.
|
||||
* @return the result string.
|
||||
*/
|
||||
string getResult()
|
||||
{
|
||||
string getResult() {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
while (!m_resultSet)
|
||||
@@ -146,8 +143,7 @@ public:
|
||||
* @param listenUntil the end time to which to updates were added (exclusive).
|
||||
* @param disconnect true when the client shall be disconnected.
|
||||
*/
|
||||
void setResult(const string result, const bool listening, const time_t listenUntil, const bool disconnect)
|
||||
{
|
||||
void setResult(const string result, const bool listening, const time_t listenUntil, const bool disconnect) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_result = result;
|
||||
m_disconnect = disconnect;
|
||||
@@ -163,7 +159,7 @@ public:
|
||||
* @param listenSince set to the start time from which to add updates (inclusive).
|
||||
* @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.
|
||||
@@ -171,7 +167,8 @@ public:
|
||||
*/
|
||||
bool isDisconnect() { return m_disconnect; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** whether this is a HTTP message. */
|
||||
const bool m_isHttp;
|
||||
|
||||
@@ -198,16 +195,13 @@ private:
|
||||
|
||||
/** start timestamp of listening update. */
|
||||
time_t m_listenSince;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* class connection which handle client and baseloop communication.
|
||||
*/
|
||||
class Connection : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
class Connection : public Thread {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param socket the @a TCPSocket for communication.
|
||||
@@ -215,8 +209,9 @@ public:
|
||||
* @param netQueue the reference to the @a NetMessage @a Queue.
|
||||
*/
|
||||
Connection(TCPSocket* socket, const bool isHttp, Queue<NetMessage*>* netQueue)
|
||||
: Thread(), m_isHttp(isHttp), m_socket(socket), m_netQueue(netQueue)
|
||||
{ m_id = ++m_ids; }
|
||||
: Thread(), m_isHttp(isHttp), m_socket(socket), m_netQueue(netQueue) {
|
||||
m_id = ++m_ids;
|
||||
}
|
||||
|
||||
virtual ~Connection() { if (m_socket) delete m_socket; }
|
||||
/**
|
||||
@@ -235,7 +230,8 @@ public:
|
||||
*/
|
||||
int getID() { return m_id; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** whether this is a HTTP connection. */
|
||||
const bool m_isHttp;
|
||||
|
||||
@@ -253,16 +249,13 @@ private:
|
||||
|
||||
/** the IF of the last opened connection. */
|
||||
static int m_ids;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* class network which listening on tcp socket for incoming connections.
|
||||
*/
|
||||
class Network : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
class Network : public Thread {
|
||||
public:
|
||||
/**
|
||||
* create a network instance and listening for incoming connections.
|
||||
* @param local true to accept connections only for local host.
|
||||
@@ -287,7 +280,8 @@ public:
|
||||
*/
|
||||
void stop() const { m_notify.notify(); usleep(100000); }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the list of active @a Connection instances. */
|
||||
list<Connection*> m_connections;
|
||||
|
||||
@@ -310,8 +304,7 @@ private:
|
||||
* clean inactive connections from container.
|
||||
*/
|
||||
void cleanConnections();
|
||||
|
||||
};
|
||||
|
||||
#endif // NETWORK_H_
|
||||
#endif // EBUSD_NETWORK_H_
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "contrib.h"
|
||||
#include "tem.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_CONTRIB_H_
|
||||
#define LIBEBUS_CONTRIB_H_
|
||||
#ifndef LIB_EBUS_CONTRIB_CONTRIB_H_
|
||||
#define LIB_EBUS_CONTRIB_CONTRIB_H_
|
||||
|
||||
/** @file contrib.h
|
||||
* Contributed sources that may be excluded from regular builds.
|
||||
@@ -32,4 +32,4 @@ using namespace std;
|
||||
*/
|
||||
bool libebus_contrib_register();
|
||||
|
||||
#endif // LIBEBUS_CONTRIB_H_
|
||||
#endif // LIB_EBUS_CONTRIB_CONTRIB_H_
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "datatype.h"
|
||||
#include "tem.h"
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
#include "datatype.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -35,8 +35,7 @@ void contrib_tem_register() {
|
||||
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) {
|
||||
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,
|
||||
const unsigned char offset, const unsigned char length,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
unsigned int value = 0;
|
||||
|
||||
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,
|
||||
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;
|
||||
int grp, num;
|
||||
string token;
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_CONTRIB_TEM_H_
|
||||
#define LIBEBUS_CONTRIB_TEM_H_
|
||||
#ifndef LIB_EBUS_CONTRIB_TEM_H_
|
||||
#define LIB_EBUS_CONTRIB_TEM_H_
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "datatype.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -29,6 +26,9 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "datatype.h"
|
||||
|
||||
/** @file tem.h
|
||||
* Contributed data types for TEM devices not part of regular releases.
|
||||
@@ -40,10 +40,8 @@ using namespace std;
|
||||
* A special variant of @a NumberDataType for TEM/Dungs ParamID in master/slave
|
||||
* data.
|
||||
*/
|
||||
class TemParamDataType : public NumberDataType
|
||||
{
|
||||
public:
|
||||
|
||||
class TemParamDataType : public NumberDataType {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -63,7 +61,6 @@ public:
|
||||
virtual result_t writeSymbols(istringstream& input,
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -71,4 +68,4 @@ public:
|
||||
*/
|
||||
void contrib_tem_register();
|
||||
|
||||
#endif // LIBEBUS_CONTRIB_TEM_H_
|
||||
#endif // LIB_EBUS_CONTRIB_TEM_H_
|
||||
|
||||
@@ -16,18 +16,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tem.h"
|
||||
#include "data.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "tem.h"
|
||||
#include "data.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool error = false;
|
||||
|
||||
void verify(bool expectFailMatch, string type, string input,
|
||||
bool match, string expectStr, string gotStr)
|
||||
{
|
||||
bool match, string expectStr, string gotStr) {
|
||||
match = match && expectStr == gotStr;
|
||||
if (expectFailMatch) {
|
||||
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");
|
||||
if (type == NULL) {
|
||||
cout << "datatype not registered" << endl;
|
||||
@@ -108,7 +108,7 @@ int main()
|
||||
fields = NULL;
|
||||
}
|
||||
vector<string>::iterator it = entries.begin();
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1]==BROADCAST || isMaster(mstr[1])));
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, false, (mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": create error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
@@ -145,7 +145,7 @@ int main()
|
||||
if (result >= RESULT_OK) {
|
||||
result = fields->read(pt_slaveData, sstr, 0, output, 0, -1, !output.str().empty());
|
||||
}
|
||||
if (failedRead)
|
||||
if (failedRead) {
|
||||
if (result >= RESULT_OK) {
|
||||
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< error: unexpectedly succeeded" << endl;
|
||||
@@ -154,20 +154,20 @@ int main()
|
||||
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< OK" << endl;
|
||||
}
|
||||
else if (result < RESULT_OK) {
|
||||
} else if (result < RESULT_OK) {
|
||||
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0;
|
||||
verify(failedReadMatch, "read", check[2], match, expectStr, output.str());
|
||||
}
|
||||
|
||||
istringstream input(expectStr);
|
||||
result = fields->write(input, pt_masterData, writeMstr, 0);
|
||||
if (result >= RESULT_OK)
|
||||
if (result >= RESULT_OK) {
|
||||
result = fields->write(input, pt_slaveData, writeSstr, 0);
|
||||
}
|
||||
if (failedWrite) {
|
||||
if (result >= RESULT_OK) {
|
||||
cout << " failed write " << fields->getName() << " >"
|
||||
@@ -177,8 +177,7 @@ int main()
|
||||
cout << " failed write " << fields->getName() << " >"
|
||||
<< expectStr << "< OK" << endl;
|
||||
}
|
||||
}
|
||||
else if (result < RESULT_OK) {
|
||||
} else if (result < RESULT_OK) {
|
||||
cout << " write " << fields->getName() << " >" << expectStr
|
||||
<< "< error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
@@ -191,6 +190,5 @@ int main()
|
||||
}
|
||||
|
||||
delete templates;
|
||||
|
||||
return error ? 1 : 0;
|
||||
}
|
||||
|
||||
+192
-205
@@ -21,12 +21,13 @@
|
||||
#endif
|
||||
|
||||
#include "data.h"
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -39,14 +40,13 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
DataFieldTemplates* templates, DataField*& returnField,
|
||||
const bool isWriteMessage,
|
||||
const bool isTemplate, const bool isBroadcastOrMasterDestination,
|
||||
const unsigned char maxFieldLength)
|
||||
{
|
||||
const unsigned char maxFieldLength) {
|
||||
vector<SingleDataField*> fields;
|
||||
string firstName, firstComment;
|
||||
result_t result = RESULT_OK;
|
||||
if (it == end)
|
||||
if (it == end) {
|
||||
return RESULT_ERR_EOF;
|
||||
|
||||
}
|
||||
while (it != end && result == RESULT_OK) {
|
||||
string unit, comment;
|
||||
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]]]]
|
||||
const string name = *it++; // name
|
||||
if (it == end) {
|
||||
if (!name.empty())
|
||||
if (!name.empty()) {
|
||||
result = RESULT_ERR_MISSING_TYPE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -69,8 +70,9 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
const char* partStr = (*it++).c_str(); // part
|
||||
hasPartStr = partStr[0] != 0;
|
||||
if (it == end) {
|
||||
if (!name.empty() || hasPartStr)
|
||||
if (!name.empty() || hasPartStr) {
|
||||
result = RESULT_ERR_MISSING_TYPE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isBroadcastOrMasterDestination
|
||||
@@ -110,7 +112,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
if (equalPos == string::npos) {
|
||||
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
|
||||
} else if (equalPos == 0 && divisorStr.length() > 1) {
|
||||
verifyValue = divisorStr[1]=='='; // == forced verification of constant value
|
||||
verifyValue = divisorStr[1] == '='; // == forced verification of constant value
|
||||
if (verifyValue && divisorStr.length() == 1) {
|
||||
result = RESULT_ERR_INVALID_LIST;
|
||||
break;
|
||||
@@ -188,7 +190,7 @@ result_t DataField::create(vector<string>::iterator& it,
|
||||
length = 0; // no length specified
|
||||
typeName = token;
|
||||
} else {
|
||||
if (pos+2==token.length() && token[pos+1]=='*') {
|
||||
if (pos+2 == token.length() && token[pos+1] == '*') {
|
||||
length = REMAIN_LEN;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
void DataField::dumpString(ostream& output, const string str, const bool prependFieldSeparator)
|
||||
{
|
||||
void DataField::dumpString(ostream& output, const string str, const bool prependFieldSeparator) {
|
||||
if (prependFieldSeparator) {
|
||||
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,
|
||||
const string name, const string comment, const string unit,
|
||||
const PartType partType, int divisor, map<unsigned int, string> values,
|
||||
const string constantValue, const bool verifyValue, SingleDataField* &returnField)
|
||||
{
|
||||
DataType* dataType = DataTypeList::getInstance()->get(id, length==REMAIN_LEN ? (unsigned char)0 : length);
|
||||
const string constantValue, const bool verifyValue, SingleDataField* &returnField) {
|
||||
DataType* dataType = DataTypeList::getInstance()->get(id, length == REMAIN_LEN ? (unsigned char)0 : length);
|
||||
if (!dataType) {
|
||||
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];
|
||||
}
|
||||
result_t result = numType->derive(divisor, bitCount, numType);
|
||||
if (result!=RESULT_OK) {
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
if (values.empty()) {
|
||||
@@ -318,15 +318,15 @@ result_t SingleDataField::create(const string id, const unsigned char length,
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void SingleDataField::dump(ostream& output)
|
||||
{
|
||||
void SingleDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData)
|
||||
if (m_partType == pt_masterData) {
|
||||
output << "m";
|
||||
else if (m_partType == pt_slaveData)
|
||||
} else if (m_partType == pt_slaveData) {
|
||||
output << "s";
|
||||
}
|
||||
output << FIELD_SEPARATOR;
|
||||
m_dataType->dump(output, m_length);
|
||||
dumpString(output, m_unit);
|
||||
@@ -336,13 +336,11 @@ void SingleDataField::dump(ostream& output)
|
||||
|
||||
result_t SingleDataField::read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
unsigned int& output, const char* fieldName, signed char fieldIndex)
|
||||
{
|
||||
if (partType != m_partType)
|
||||
unsigned int& output, const char* fieldName, signed char fieldIndex) {
|
||||
if (partType != m_partType) {
|
||||
return RESULT_EMPTY;
|
||||
|
||||
switch (m_partType)
|
||||
{
|
||||
}
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
@@ -352,7 +350,7 @@ result_t SingleDataField::read(const PartType partType,
|
||||
default:
|
||||
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()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
@@ -365,13 +363,11 @@ result_t SingleDataField::read(const PartType partType,
|
||||
result_t SingleDataField::read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
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) {
|
||||
return RESULT_OK;
|
||||
}
|
||||
switch (m_partType)
|
||||
{
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
@@ -381,7 +377,7 @@ result_t SingleDataField::read(const PartType partType,
|
||||
default:
|
||||
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()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
@@ -393,8 +389,8 @@ result_t SingleDataField::read(const PartType partType,
|
||||
if (leadingSeparator) {
|
||||
output << ",";
|
||||
}
|
||||
if (outputIndex>=0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
|
||||
output << "\n \"" << static_cast<signed int>(outputIndex<0?0:outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
|
||||
if (outputIndex >= 0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
|
||||
output << "\n \"" << static_cast<signed int>(outputIndex < 0 ? 0 : outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
|
||||
} else {
|
||||
output << "\n \"" << m_name << "\": {\"value\": ";
|
||||
}
|
||||
@@ -407,7 +403,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) {
|
||||
return result;
|
||||
}
|
||||
@@ -433,13 +429,11 @@ result_t SingleDataField::read(const PartType partType,
|
||||
|
||||
result_t SingleDataField::write(istringstream& input,
|
||||
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) {
|
||||
return RESULT_OK;
|
||||
}
|
||||
switch (m_partType)
|
||||
{
|
||||
switch (m_partType) {
|
||||
case pt_masterData:
|
||||
offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
|
||||
break;
|
||||
@@ -449,50 +443,52 @@ result_t SingleDataField::write(istringstream& input,
|
||||
default:
|
||||
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,
|
||||
const unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
return m_dataType->readSymbols(input, isMaster, offset, m_length, output, outputFormat);
|
||||
}
|
||||
|
||||
result_t SingleDataField::writeSymbols(istringstream& input,
|
||||
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);
|
||||
}
|
||||
|
||||
SingleDataField* SingleDataField::clone()
|
||||
{
|
||||
SingleDataField* SingleDataField::clone() {
|
||||
return new SingleDataField(*this);
|
||||
}
|
||||
|
||||
result_t SingleDataField::derive(string name, string comment,
|
||||
string unit, const PartType partType,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields)
|
||||
{
|
||||
if (m_partType != pt_any && partType == pt_any)
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
}
|
||||
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
|
||||
if (name.empty())
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
if (comment.empty())
|
||||
}
|
||||
if (comment.empty()) {
|
||||
comment = m_comment;
|
||||
if (unit.empty())
|
||||
}
|
||||
if (unit.empty()) {
|
||||
unit = m_unit;
|
||||
}
|
||||
DataType* dataType = m_dataType;
|
||||
if (numeric) {
|
||||
NumberDataType* numType = (NumberDataType*)m_dataType;
|
||||
result_t result = numType->derive(divisor, 0, numType);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
dataType = numType;
|
||||
}
|
||||
if (values.empty()) {
|
||||
@@ -503,23 +499,20 @@ result_t SingleDataField::derive(string name, string comment,
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
bool SingleDataField::hasField(const char* fieldName, bool numeric)
|
||||
{
|
||||
bool SingleDataField::hasField(const char* fieldName, bool numeric) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool SingleDataField::hasFullByteOffset(bool after)
|
||||
{
|
||||
bool SingleDataField::hasFullByteOffset(bool after) {
|
||||
if (m_length > 1 || !m_dataType->isNumeric()) {
|
||||
return true;
|
||||
}
|
||||
@@ -529,49 +522,50 @@ bool SingleDataField::hasFullByteOffset(bool after)
|
||||
}
|
||||
|
||||
|
||||
ValueListDataField* ValueListDataField::clone()
|
||||
{
|
||||
ValueListDataField* ValueListDataField::clone() {
|
||||
return new ValueListDataField(*this);
|
||||
}
|
||||
|
||||
result_t ValueListDataField::derive(string name, string comment,
|
||||
string unit, const PartType partType,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields)
|
||||
{
|
||||
if (m_partType != pt_any && partType == pt_any)
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
if (name.empty())
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
if (comment.empty())
|
||||
}
|
||||
if (comment.empty()) {
|
||||
comment = m_comment;
|
||||
if (unit.empty())
|
||||
}
|
||||
if (unit.empty()) {
|
||||
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
|
||||
|
||||
}
|
||||
if (!values.empty()) {
|
||||
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
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
values = m_values;
|
||||
|
||||
}
|
||||
fields.push_back(new ValueListDataField(name, comment, unit, (NumberDataType*)m_dataType, partType, m_length, values));
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void ValueListDataField::dump(ostream& output)
|
||||
{
|
||||
void ValueListDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData)
|
||||
if (m_partType == pt_masterData) {
|
||||
output << "m";
|
||||
else if (m_partType == pt_slaveData)
|
||||
} else if (m_partType == pt_slaveData) {
|
||||
output << "s";
|
||||
}
|
||||
output << FIELD_SEPARATOR;
|
||||
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++) {
|
||||
@@ -587,13 +581,13 @@ void ValueListDataField::dump(ostream& output)
|
||||
|
||||
result_t ValueListDataField::readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
unsigned int value = 0;
|
||||
|
||||
result_t result = m_dataType->readRawValue(input, offset, m_length, value);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
map<unsigned int, string>::iterator it = m_values.find(value);
|
||||
if (it == m_values.end() && value != m_dataType->getReplacement()) {
|
||||
// fall back to raw value in input
|
||||
@@ -601,85 +595,90 @@ result_t ValueListDataField::readSymbols(SymbolString& input, const bool isMaste
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (it == m_values.end()) {
|
||||
if (outputFormat & OF_JSON)
|
||||
if (outputFormat & OF_JSON) {
|
||||
output << "null";
|
||||
else if (value == m_dataType->getReplacement())
|
||||
} else if (value == m_dataType->getReplacement()) {
|
||||
output << NULL_VALUE;
|
||||
} else if (outputFormat & OF_NUMERIC)
|
||||
}
|
||||
} else if (outputFormat & OF_NUMERIC) {
|
||||
output << setw(0) << dec << static_cast<unsigned>(value);
|
||||
else if (outputFormat & OF_JSON)
|
||||
} else if (outputFormat & OF_JSON) {
|
||||
output << '"' << it->second << '"';
|
||||
else
|
||||
} else {
|
||||
output << it->second;
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t ValueListDataField::writeSymbols(istringstream& input,
|
||||
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;
|
||||
if (isIgnored())
|
||||
if (isIgnored()) {
|
||||
return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); // replacement value
|
||||
|
||||
}
|
||||
const char* str = input.str().c_str();
|
||||
|
||||
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++)
|
||||
if (it->second.compare(str) == 0)
|
||||
for (map<unsigned int, string>::iterator it = m_values.begin(); it != m_values.end(); it++) {
|
||||
if (it->second.compare(str) == 0) {
|
||||
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
|
||||
|
||||
}
|
||||
char* strEnd = NULL; // fall back to raw value in input
|
||||
unsigned int value;
|
||||
value = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.'))
|
||||
if (strEnd == NULL || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
|
||||
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 RESULT_ERR_NOTFOUND; // value assignment not found
|
||||
}
|
||||
|
||||
|
||||
ConstantDataField* ConstantDataField::clone()
|
||||
{
|
||||
ConstantDataField* ConstantDataField::clone() {
|
||||
return new ConstantDataField(*this);
|
||||
}
|
||||
|
||||
result_t ConstantDataField::derive(string name, string comment,
|
||||
string unit, const PartType partType,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields)
|
||||
{
|
||||
if (m_partType != pt_any && partType == pt_any)
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (m_partType != pt_any && partType == pt_any) {
|
||||
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
|
||||
if (name.empty())
|
||||
}
|
||||
if (name.empty()) {
|
||||
name = m_name;
|
||||
if (comment.empty())
|
||||
}
|
||||
if (comment.empty()) {
|
||||
comment = m_comment;
|
||||
if (unit.empty())
|
||||
}
|
||||
if (unit.empty()) {
|
||||
unit = m_unit;
|
||||
if (divisor != 0)
|
||||
}
|
||||
if (divisor != 0) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use other than current divisor for constant value field
|
||||
}
|
||||
if (!values.empty()) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field
|
||||
}
|
||||
fields.push_back(new ConstantDataField(name, comment, unit, m_dataType, partType, m_length, m_value, m_verify));
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void ConstantDataField::dump(ostream& output)
|
||||
{
|
||||
void ConstantDataField::dump(ostream& output) {
|
||||
output << setw(0) << dec; // initialize formatting
|
||||
dumpString(output, m_name, false);
|
||||
output << FIELD_SEPARATOR;
|
||||
if (m_partType == pt_masterData)
|
||||
if (m_partType == pt_masterData) {
|
||||
output << "m";
|
||||
else if (m_partType == pt_slaveData)
|
||||
} else if (m_partType == pt_slaveData) {
|
||||
output << "s";
|
||||
}
|
||||
output << FIELD_SEPARATOR;
|
||||
if (!m_dataType->dump(output, m_length)) { // no divisor appended
|
||||
output << (m_verify?"==":"=") << m_value;
|
||||
@@ -690,8 +689,7 @@ void ConstantDataField::dump(ostream& output)
|
||||
|
||||
result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
ostringstream coutput;
|
||||
result_t result = SingleDataField::readSymbols(input, isMaster, offset, coutput, 0);
|
||||
if (result != RESULT_OK) {
|
||||
@@ -700,7 +698,7 @@ result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster
|
||||
if (m_verify) {
|
||||
string value = coutput.str();
|
||||
FileReader::trim(value);
|
||||
if (value!=m_value) {
|
||||
if (value != m_value) {
|
||||
return RESULT_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
@@ -709,8 +707,7 @@ result_t ConstantDataField::readSymbols(SymbolString& input, const bool isMaster
|
||||
|
||||
result_t ConstantDataField::writeSymbols(istringstream& input,
|
||||
const unsigned char offset,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength)
|
||||
{
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength) {
|
||||
istringstream cinput(m_value);
|
||||
return SingleDataField::writeSymbols(cinput, offset, output, isMaster, usedLength);
|
||||
}
|
||||
@@ -718,9 +715,8 @@ result_t ConstantDataField::writeSymbols(istringstream& input,
|
||||
|
||||
DataFieldSet* DataFieldSet::s_identFields = NULL;
|
||||
|
||||
DataFieldSet* DataFieldSet::getIdentFields()
|
||||
{
|
||||
if (s_identFields==NULL) {
|
||||
DataFieldSet* DataFieldSet::getIdentFields() {
|
||||
if (s_identFields == NULL) {
|
||||
NumberDataType* uchDataType = (NumberDataType*)DataTypeList::getInstance()->get("UCH");
|
||||
StringDataType* stringDataType = (StringDataType*)DataTypeList::getInstance()->get("STR");
|
||||
NumberDataType* pinDataType = (NumberDataType*)DataTypeList::getInstance()->get("PIN");
|
||||
@@ -760,16 +756,14 @@ DataFieldSet* DataFieldSet::getIdentFields()
|
||||
return s_identFields;
|
||||
}
|
||||
|
||||
DataFieldSet::~DataFieldSet()
|
||||
{
|
||||
DataFieldSet::~DataFieldSet() {
|
||||
while (!m_fields.empty()) {
|
||||
delete m_fields.back();
|
||||
m_fields.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
DataFieldSet* DataFieldSet::clone()
|
||||
{
|
||||
DataFieldSet* DataFieldSet::clone() {
|
||||
vector<SingleDataField*> fields;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
fields.push_back((*it)->clone());
|
||||
@@ -777,23 +771,22 @@ DataFieldSet* DataFieldSet::clone()
|
||||
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;
|
||||
|
||||
bool previousFullByteOffset[] = { true, true, true, true };
|
||||
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
SingleDataField* field = *it;
|
||||
if (field->getPartType() == partType) {
|
||||
if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false))
|
||||
if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) {
|
||||
length--;
|
||||
|
||||
}
|
||||
unsigned char fieldLength = field->getLength(partType, maxLength);
|
||||
if (fieldLength>=maxLength)
|
||||
if (fieldLength >= maxLength) {
|
||||
maxLength = 0;
|
||||
else
|
||||
} else {
|
||||
maxLength = (unsigned char)(maxLength-fieldLength);
|
||||
}
|
||||
length = (unsigned char)(length + fieldLength);
|
||||
|
||||
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
|
||||
@@ -803,12 +796,11 @@ unsigned char DataFieldSet::getLength(PartType partType, unsigned char maxLength
|
||||
return length;
|
||||
}
|
||||
|
||||
string DataFieldSet::getName(signed char fieldIndex)
|
||||
{
|
||||
if (fieldIndex<0) {
|
||||
string DataFieldSet::getName(signed char fieldIndex) {
|
||||
if (fieldIndex < 0) {
|
||||
return m_name;
|
||||
}
|
||||
if ((unsigned char)fieldIndex>=m_fields.size()) {
|
||||
if ((unsigned char)fieldIndex >= m_fields.size()) {
|
||||
return "";
|
||||
}
|
||||
if (m_uniqueNames) {
|
||||
@@ -822,33 +814,33 @@ string DataFieldSet::getName(signed char fieldIndex)
|
||||
result_t DataFieldSet::derive(string name, string comment,
|
||||
string unit, const PartType partType,
|
||||
int divisor, map<unsigned int, string> values,
|
||||
vector<SingleDataField*>& fields)
|
||||
{
|
||||
if (!values.empty())
|
||||
vector<SingleDataField*>& fields) {
|
||||
if (!values.empty()) {
|
||||
return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive
|
||||
}
|
||||
bool first = true;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
result_t result = (*it)->derive("", first?comment:"", first?unit:"", partType, divisor, values, fields);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
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++) {
|
||||
SingleDataField* field = *it;
|
||||
if (field->hasField(fieldName, numeric)==0)
|
||||
if (field->hasField(fieldName, numeric) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DataFieldSet::dump(ostream& output)
|
||||
{
|
||||
void DataFieldSet::dump(ostream& output) {
|
||||
bool first = true;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
if (first) {
|
||||
@@ -862,22 +854,20 @@ void DataFieldSet::dump(ostream& output)
|
||||
|
||||
result_t DataFieldSet::read(const PartType partType,
|
||||
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;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
SingleDataField* field = *it;
|
||||
if (partType != pt_any && field->getPartType() != partType)
|
||||
if (partType != pt_any && field->getPartType() != partType) {
|
||||
continue;
|
||||
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false))
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
offset--;
|
||||
|
||||
}
|
||||
result_t result = field->read(partType, data, offset, output, fieldName, fieldIndex);
|
||||
|
||||
if (result < RESULT_OK)
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
if (result != RESULT_EMPTY) {
|
||||
@@ -885,8 +875,9 @@ result_t DataFieldSet::read(const PartType partType,
|
||||
}
|
||||
if (findFieldIndex && fieldName == field->getName()) {
|
||||
if (fieldIndex == 0) {
|
||||
if (!found)
|
||||
if (!found) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fieldIndex--;
|
||||
@@ -903,26 +894,26 @@ result_t DataFieldSet::read(const PartType partType,
|
||||
result_t DataFieldSet::read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
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;
|
||||
if (!m_uniqueNames && outputIndex<0)
|
||||
if (!m_uniqueNames && outputIndex < 0) {
|
||||
outputIndex = 0;
|
||||
}
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
SingleDataField* field = *it;
|
||||
if (partType != pt_any && field->getPartType() != partType) {
|
||||
if (outputIndex>=0 && !field->isIgnored())
|
||||
if (outputIndex >= 0 && !field->isIgnored()) {
|
||||
outputIndex++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false))
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
offset--;
|
||||
|
||||
}
|
||||
result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex);
|
||||
|
||||
if (result < RESULT_OK)
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
if (result != RESULT_EMPTY) {
|
||||
@@ -931,14 +922,16 @@ result_t DataFieldSet::read(const PartType partType,
|
||||
}
|
||||
if (findFieldIndex && fieldName == field->getName()) {
|
||||
if (fieldIndex == 0) {
|
||||
if (!found)
|
||||
if (!found) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fieldIndex--;
|
||||
}
|
||||
if (outputIndex>=0 && !field->isIgnored())
|
||||
if (outputIndex >= 0 && !field->isIgnored()) {
|
||||
outputIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
@@ -957,57 +950,54 @@ result_t DataFieldSet::read(const PartType partType,
|
||||
|
||||
result_t DataFieldSet::write(istringstream& input,
|
||||
const PartType partType, SymbolString& data,
|
||||
unsigned char offset, char separator, unsigned char* length)
|
||||
{
|
||||
unsigned char offset, char separator, unsigned char* length) {
|
||||
string token;
|
||||
|
||||
bool previousFullByteOffset = true;
|
||||
unsigned char baseOffset = offset;
|
||||
for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
|
||||
SingleDataField* field = *it;
|
||||
if (partType != pt_any && field->getPartType() != partType)
|
||||
if (partType != pt_any && field->getPartType() != partType) {
|
||||
continue;
|
||||
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false))
|
||||
}
|
||||
if (!previousFullByteOffset && !field->hasFullByteOffset(false)) {
|
||||
offset--;
|
||||
|
||||
}
|
||||
result_t result;
|
||||
unsigned char fieldLength;
|
||||
if (m_fields.size() > 1) {
|
||||
if (field->isIgnored())
|
||||
if (field->isIgnored()) {
|
||||
token.clear();
|
||||
else if (!getline(input, token, separator))
|
||||
} else if (!getline(input, token, separator)) {
|
||||
token.clear();
|
||||
|
||||
}
|
||||
istringstream single(token);
|
||||
result = (*it)->write(single, partType, data, offset, separator, &fieldLength);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
result = (*it)->write(input, partType, data, offset, separator, &fieldLength);
|
||||
|
||||
if (result != RESULT_OK)
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
offset = (unsigned char)(offset+fieldLength);
|
||||
previousFullByteOffset = field->hasFullByteOffset(true);
|
||||
}
|
||||
|
||||
if (length!=NULL)
|
||||
if (length != NULL) {
|
||||
*length = (unsigned char)(offset-baseOffset);
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
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++) {
|
||||
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++) {
|
||||
delete it->second;
|
||||
it->second = NULL;
|
||||
@@ -1015,58 +1005,55 @@ void DataFieldTemplates::clear()
|
||||
m_fieldsByName.clear();
|
||||
}
|
||||
|
||||
result_t DataFieldTemplates::add(DataField* field, string name, bool replace)
|
||||
{
|
||||
if (name.length() == 0)
|
||||
result_t DataFieldTemplates::add(DataField* field, string name, bool replace) {
|
||||
if (name.length() == 0) {
|
||||
name = field->getName();
|
||||
}
|
||||
map<string, DataField*>::iterator it = m_fieldsByName.find(name);
|
||||
if (it != m_fieldsByName.end()) {
|
||||
if (!replace)
|
||||
if (!replace) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
|
||||
}
|
||||
delete it->second;
|
||||
it->second = field;
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
m_fieldsByName[name] = field;
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t DataFieldTemplates::addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
|
||||
const string& filename, unsigned int lineNo)
|
||||
{
|
||||
const string& filename, unsigned int lineNo) {
|
||||
vector<string>::iterator restart = begin;
|
||||
DataField* field = NULL;
|
||||
string name;
|
||||
if (begin != end) {
|
||||
size_t colon = begin->find(':');
|
||||
if (colon!=string::npos) {
|
||||
if (colon != string::npos) {
|
||||
name = begin->substr(0, colon);
|
||||
begin->erase(0, colon+1);
|
||||
}
|
||||
}
|
||||
result_t result = DataField::create(begin, end, this, field, false, true, false);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
result = add(field, name, true);
|
||||
if (result==RESULT_ERR_DUPLICATE_NAME)
|
||||
if (result == RESULT_ERR_DUPLICATE_NAME) {
|
||||
begin = restart+1; // mark name as invalid
|
||||
if (result != RESULT_OK)
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
delete field;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DataField* DataFieldTemplates::get(const string name)
|
||||
{
|
||||
DataField* DataFieldTemplates::get(const string name) {
|
||||
map<string, DataField*>::const_iterator ref = m_fieldsByName.find(name);
|
||||
if (ref == m_fieldsByName.end())
|
||||
if (ref == m_fieldsByName.end()) {
|
||||
return NULL;
|
||||
|
||||
}
|
||||
return ref->second;
|
||||
}
|
||||
|
||||
+55
-74
@@ -16,19 +16,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_DATA_H_
|
||||
#define LIBEBUS_DATA_H_
|
||||
#ifndef LIB_EBUS_DATA_H_
|
||||
#define LIB_EBUS_DATA_H_
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "filereader.h"
|
||||
#include "datatype.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "filereader.h"
|
||||
#include "datatype.h"
|
||||
|
||||
/** @file data.h
|
||||
* Classes related to defining fields based on data types in symbols on the
|
||||
@@ -53,10 +53,8 @@ class SingleDataField;
|
||||
/**
|
||||
* Base class for all kinds of data fields.
|
||||
*/
|
||||
class DataField
|
||||
{
|
||||
public:
|
||||
|
||||
class DataField {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -93,7 +91,7 @@ public:
|
||||
DataFieldTemplates* templates, DataField*& returnField,
|
||||
const bool isWriteMessage,
|
||||
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.
|
||||
@@ -101,7 +99,7 @@ public:
|
||||
* @param str the @a string to dump.
|
||||
* @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.
|
||||
@@ -109,7 +107,7 @@ public:
|
||||
* @param maxLength the maximum length for calculating remainder of input.
|
||||
* @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.
|
||||
@@ -132,7 +130,7 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
virtual string getName(signed char fieldIndex=-1) { return m_name; }
|
||||
virtual string getName(signed char fieldIndex = -1) { return m_name; }
|
||||
|
||||
/**
|
||||
* Get the field comment.
|
||||
@@ -169,7 +167,7 @@ public:
|
||||
*/
|
||||
virtual result_t read(const PartType partType,
|
||||
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.
|
||||
@@ -188,8 +186,8 @@ public:
|
||||
*/
|
||||
virtual result_t read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1,
|
||||
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1) = 0;
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
|
||||
bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1) = 0;
|
||||
|
||||
/**
|
||||
* Writes the value to the master or slave @a SymbolString.
|
||||
@@ -203,26 +201,23 @@ public:
|
||||
*/
|
||||
virtual result_t write(istringstream& input,
|
||||
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:
|
||||
/** the field name. */
|
||||
const string m_name;
|
||||
|
||||
/** the field comment. */
|
||||
const string m_comment;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A single @a DataField holding a value.
|
||||
*/
|
||||
class SingleDataField : public DataField
|
||||
{
|
||||
public:
|
||||
|
||||
class SingleDataField : public DataField {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -287,7 +282,7 @@ public:
|
||||
PartType getPartType() const { return m_partType; }
|
||||
|
||||
// @copydoc
|
||||
virtual unsigned char getLength(PartType partType, unsigned char maxLength=MAX_LEN);
|
||||
virtual unsigned char getLength(PartType partType, unsigned char maxLength = MAX_LEN);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t derive(string name, string comment,
|
||||
@@ -312,21 +307,21 @@ public:
|
||||
// @copydoc
|
||||
virtual result_t read(const PartType partType,
|
||||
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
|
||||
virtual result_t read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1,
|
||||
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1);
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
|
||||
bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t write(istringstream& input,
|
||||
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:
|
||||
/**
|
||||
* Internal method for reading the field from a @a SymbolString.
|
||||
* @param input the unescaped @a SymbolString to read the binary value from.
|
||||
@@ -353,8 +348,6 @@ protected:
|
||||
const unsigned char offset,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
protected:
|
||||
|
||||
/** the value unit. */
|
||||
const string m_unit;
|
||||
|
||||
@@ -366,17 +359,14 @@ protected:
|
||||
|
||||
/** the number of symbols in the message part in which the field is stored. */
|
||||
const unsigned char m_length;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A numeric data field with a list of value=text assignments and a string representation.
|
||||
*/
|
||||
class ValueListDataField : public SingleDataField
|
||||
{
|
||||
public:
|
||||
|
||||
class ValueListDataField : public SingleDataField {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -410,8 +400,8 @@ public:
|
||||
// @copydoc
|
||||
virtual void dump(ostream& output);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
@@ -422,21 +412,18 @@ protected:
|
||||
const unsigned char offset,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the value=text assignments. */
|
||||
map<unsigned int, string> m_values;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A data field with a constant value.
|
||||
*/
|
||||
class ConstantDataField : public SingleDataField
|
||||
{
|
||||
public:
|
||||
|
||||
class ConstantDataField : public SingleDataField {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param name the field name.
|
||||
@@ -471,8 +458,8 @@ public:
|
||||
// @copydoc
|
||||
virtual void dump(ostream& output);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char offset,
|
||||
@@ -483,24 +470,21 @@ protected:
|
||||
const unsigned char offset,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the constant value. */
|
||||
const string m_value;
|
||||
|
||||
/** whether to verify the read value against the constant value. */
|
||||
const bool m_verify;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A set of @a DataField instances.
|
||||
*/
|
||||
class DataFieldSet : public DataField
|
||||
{
|
||||
public:
|
||||
|
||||
class DataFieldSet : public DataField {
|
||||
public:
|
||||
/**
|
||||
* Get the @a DataFieldSet for parsing the identification message (service 0x07 0x04).
|
||||
* @return the @a DataFieldSet for parsing the identification message. This is:<ul>
|
||||
@@ -522,15 +506,16 @@ public:
|
||||
DataFieldSet(const string name, const string comment,
|
||||
const vector<SingleDataField*> fields)
|
||||
: DataField(name, comment),
|
||||
m_fields(fields)
|
||||
{
|
||||
m_fields(fields) {
|
||||
bool uniqueNames = true;
|
||||
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;
|
||||
if (field->isIgnored()) continue;
|
||||
if (field->isIgnored()) {
|
||||
continue;
|
||||
}
|
||||
string name = field->getName();
|
||||
if (name.empty() || names.find(name)!=names.end()) {
|
||||
if (name.empty() || names.find(name) != names.end()) {
|
||||
uniqueNames = false;
|
||||
break;
|
||||
}
|
||||
@@ -548,10 +533,10 @@ public:
|
||||
virtual DataFieldSet* clone();
|
||||
|
||||
// @copydoc
|
||||
virtual unsigned char getLength(PartType partType, unsigned char maxLength=MAX_LEN);
|
||||
virtual unsigned char getLength(PartType partType, unsigned char maxLength = MAX_LEN);
|
||||
|
||||
// @copydoc
|
||||
virtual string getName(signed char fieldIndex=-1);
|
||||
virtual string getName(signed char fieldIndex = -1);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t derive(string name, string comment,
|
||||
@@ -564,14 +549,14 @@ public:
|
||||
* @param index the index of the @a SingleDataField to return.
|
||||
* @return the @a SingleDataField at the specified index, or NULL.
|
||||
*/
|
||||
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) return NULL; return m_fields[index]; }
|
||||
SingleDataField* operator[](const size_t index) { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
|
||||
|
||||
/**
|
||||
* Returns the @a SingleDataField at the specified index.
|
||||
* @param index the index of the @a SingleDataField to return.
|
||||
* @return the @a SingleDataField at the specified index, or NULL.
|
||||
*/
|
||||
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) return NULL; return m_fields[index]; }
|
||||
const SingleDataField* operator[](const size_t index) const { if (index >= m_fields.size()) { return NULL; } return m_fields[index]; }
|
||||
|
||||
/**
|
||||
* Returns the number of @a SingleDataFields instances in this set.
|
||||
@@ -588,21 +573,21 @@ public:
|
||||
// @copydoc
|
||||
virtual result_t read(const PartType partType,
|
||||
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
|
||||
virtual result_t read(const PartType partType,
|
||||
SymbolString& data, unsigned char offset,
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex=-1,
|
||||
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1);
|
||||
ostringstream& output, OutputFormat outputFormat, signed char outputIndex = -1,
|
||||
bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t write(istringstream& input,
|
||||
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:
|
||||
/** the @a DataFieldSet containing the ident message @a SingleDataField instances, or NULL. */
|
||||
static DataFieldSet* s_identFields;
|
||||
|
||||
@@ -611,17 +596,14 @@ private:
|
||||
|
||||
/** whether all fields have a unique name. */
|
||||
bool m_uniqueNames;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A map of template @a DataField instances.
|
||||
*/
|
||||
class DataFieldTemplates : public FileReader
|
||||
{
|
||||
public:
|
||||
|
||||
class DataFieldTemplates : public FileReader {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
@@ -653,7 +635,7 @@ public:
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
* 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
|
||||
virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
|
||||
@@ -668,11 +650,10 @@ public:
|
||||
*/
|
||||
DataField* get(string name);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the known template @a DataField instances by name. */
|
||||
map<string, DataField*> m_fieldsByName;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_DATA_H_
|
||||
#endif // LIB_EBUS_DATA_H_
|
||||
|
||||
+58
-75
@@ -21,13 +21,12 @@
|
||||
#endif
|
||||
|
||||
#include "datatype.h"
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONTRIB
|
||||
# include "contrib/contrib.h"
|
||||
#endif
|
||||
@@ -76,8 +75,7 @@ int parseSignedInt(const char* str, int base, const int minValue, const int maxV
|
||||
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) {
|
||||
pos--;
|
||||
}
|
||||
@@ -105,7 +103,7 @@ void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<st
|
||||
} else {
|
||||
i = item.find(FIELD_SEPARATOR);
|
||||
}
|
||||
if (i!=string::npos) {
|
||||
if (i != string::npos) {
|
||||
out << TEXT_SEPARATOR << item << TEXT_SEPARATOR;
|
||||
if (begin < pos) {
|
||||
cnt += 2;
|
||||
@@ -125,11 +123,10 @@ void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<st
|
||||
}
|
||||
|
||||
|
||||
bool DataType::dump(ostream& output, const unsigned char length) const
|
||||
{
|
||||
bool DataType::dump(ostream& output, const unsigned char length) const {
|
||||
output << m_id;
|
||||
if (isAdjustableLength()) {
|
||||
if (length==REMAIN_LEN) {
|
||||
if (length == REMAIN_LEN) {
|
||||
output << ":*";
|
||||
} else {
|
||||
output << ":" << static_cast<unsigned>(length);
|
||||
@@ -141,20 +138,18 @@ bool DataType::dump(ostream& output, const unsigned char length) const
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char baseOffset, const unsigned char length,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
size_t start = 0, count = length;
|
||||
int incr = 1;
|
||||
unsigned char ch;
|
||||
bool terminated = false;
|
||||
if (count==REMAIN_LEN && input.size()>baseOffset) {
|
||||
if (count == REMAIN_LEN && input.size() > baseOffset) {
|
||||
count = input.size()-baseOffset;
|
||||
} else if (baseOffset + count > input.size()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
@@ -200,10 +195,9 @@ result_t StringDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
|
||||
result_t StringDataType::writeSymbols(istringstream& input,
|
||||
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;
|
||||
bool remainder = count==REMAIN_LEN && hasFlag(ADJ);
|
||||
bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
|
||||
int incr = 1;
|
||||
unsigned int value = 0;
|
||||
string token;
|
||||
@@ -219,7 +213,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
}
|
||||
if (usedLength!=NULL) {
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)count;
|
||||
}
|
||||
return RESULT_OK;
|
||||
@@ -244,16 +238,18 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
return RESULT_ERR_INVALID_NUM; // too short hex value
|
||||
}
|
||||
value = parseInt(token.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid hex value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (input.eof()) {
|
||||
value = m_replacement;
|
||||
} else {
|
||||
value = input.get();
|
||||
if (input.eof() || value < 0x20)
|
||||
if (input.eof() || value < 0x20) {
|
||||
value = m_replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remainder && input.eof() && i > 0) {
|
||||
@@ -272,7 +268,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
if (!remainder && i < count) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
if (usedLength!=NULL) {
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)((offset-start)*incr);
|
||||
}
|
||||
return RESULT_OK;
|
||||
@@ -280,19 +276,17 @@ result_t StringDataType::writeSymbols(istringstream& input,
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char baseOffset, const unsigned char length,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
size_t start = 0, count = length;
|
||||
int incr = 1;
|
||||
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;
|
||||
} else if (baseOffset + count > input.size()) {
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
@@ -317,8 +311,7 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
}
|
||||
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
switch (type) {
|
||||
case 2: // date only
|
||||
if (!hasFlag(REQ) && ch == m_replacement) {
|
||||
if (i + 1 != length) {
|
||||
@@ -341,7 +334,7 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
int m = (int)((mjd-14956.1-(int)(y*365.25))/30.6001);
|
||||
int d = mjd-14956-(int)(y*365.25)-(int)(m*30.6001);
|
||||
m--;
|
||||
if (m>=13) {
|
||||
if (m >= 13) {
|
||||
y++;
|
||||
m -= 12;
|
||||
}
|
||||
@@ -402,8 +395,9 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
} else if (ch > 59 || (hour == 24 && ch > 0)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid time
|
||||
}
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
output << ":";
|
||||
}
|
||||
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch);
|
||||
break;
|
||||
}
|
||||
@@ -417,10 +411,9 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
|
||||
result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
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;
|
||||
bool remainder = count==REMAIN_LEN && hasFlag(ADJ);
|
||||
bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
|
||||
int incr = 1;
|
||||
unsigned int value = 0, last = 0, lastLast = 0;
|
||||
string token;
|
||||
@@ -436,7 +429,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
|
||||
output[baseOffset + offset] = (unsigned char)m_replacement; // fill up with replacement
|
||||
}
|
||||
if (usedLength!=NULL) {
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)count;
|
||||
}
|
||||
return RESULT_OK;
|
||||
@@ -445,13 +438,13 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
size_t i = 0, offset;
|
||||
int type = (m_hasDate?2:0) | (m_hasTime?1:0);
|
||||
bool skip = false;
|
||||
for (offset = start; i < count; offset += skip?0:incr, i++) {
|
||||
for (offset = start; i < count; offset += skip ? 0 : incr, i++) {
|
||||
skip = false;
|
||||
switch (type)
|
||||
{
|
||||
switch (type) {
|
||||
case 2: // date only
|
||||
if (length == 4 && i == 2)
|
||||
if (length == 4 && i == 2) {
|
||||
continue; // skip weekday in between
|
||||
}
|
||||
if (input.eof() || !getline(input, token, '.')) {
|
||||
return RESULT_ERR_EOF; // incomplete
|
||||
}
|
||||
@@ -469,11 +462,11 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
count++;
|
||||
} else if (i + 1 == count) {
|
||||
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);
|
||||
value = mjd - 15020; // 01.01.1900
|
||||
output[baseOffset + offset] = (unsigned char)(value&0xff);
|
||||
value >>= 8;
|
||||
value >>= 8;
|
||||
offset += incr;
|
||||
skip = false;
|
||||
break;
|
||||
@@ -483,13 +476,13 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
if (length == 4) {
|
||||
// calculate local week day
|
||||
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 daysSinceSunday = (mjd+3) % 7; // Sun=0
|
||||
if (hasFlag(BCD)) {
|
||||
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
|
||||
} 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) {
|
||||
@@ -535,7 +528,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
}
|
||||
value += last*60;
|
||||
output[baseOffset + offset] = (unsigned char)(value&0xff);
|
||||
value >>= 8;
|
||||
value >>= 8;
|
||||
offset += incr;
|
||||
} else if (length == 1) { // truncated time
|
||||
if (i == 0) {
|
||||
@@ -569,7 +562,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
|
||||
if (!remainder && i < count) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
}
|
||||
if (usedLength!=NULL) {
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = (unsigned char)((offset-start)*incr);
|
||||
}
|
||||
return RESULT_OK;
|
||||
@@ -588,8 +581,7 @@ unsigned char NumberDataType::calcPrecision(const int divisor) {
|
||||
return precision;
|
||||
}
|
||||
|
||||
bool NumberDataType::dump(ostream& output, unsigned char length) const
|
||||
{
|
||||
bool NumberDataType::dump(ostream& output, unsigned char length) const {
|
||||
if (m_bitCount < 8) {
|
||||
DataType::dump(output, m_bitCount);
|
||||
} else {
|
||||
@@ -600,15 +592,14 @@ bool NumberDataType::dump(ostream& output, unsigned char length) const
|
||||
output << static_cast<int>(m_divisor / m_baseType->m_divisor);
|
||||
return true;
|
||||
}
|
||||
} else if (m_divisor!=1) {
|
||||
} else if (m_divisor != 1) {
|
||||
output << static_cast<int>(m_divisor);
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
divisor = 1;
|
||||
}
|
||||
@@ -663,8 +654,7 @@ result_t NumberDataType::derive(int divisor, unsigned char bitCount, NumberDataT
|
||||
|
||||
result_t NumberDataType::readRawValue(SymbolString& input,
|
||||
unsigned char baseOffset, const unsigned char length,
|
||||
unsigned int& value)
|
||||
{
|
||||
unsigned int& value) {
|
||||
size_t start = 0, count = length;
|
||||
int incr = 1;
|
||||
unsigned char ch;
|
||||
@@ -687,21 +677,22 @@ result_t NumberDataType::readRawValue(SymbolString& input,
|
||||
return RESULT_OK;
|
||||
}
|
||||
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
|
||||
|
||||
}
|
||||
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
|
||||
} else if (ch > 0x63)
|
||||
} else if (ch > 0x63) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
|
||||
}
|
||||
value += ch * exp;
|
||||
exp *= 100;
|
||||
} else {
|
||||
value |= ch * exp;
|
||||
exp <<= 8;
|
||||
exp <<= 8;
|
||||
}
|
||||
}
|
||||
if (m_firstBit > 0) {
|
||||
value >>= m_firstBit;
|
||||
value >>= m_firstBit;
|
||||
}
|
||||
if (m_bitCount < 8) {
|
||||
value &= (1 << m_bitCount) - 1;
|
||||
@@ -711,8 +702,7 @@ result_t NumberDataType::readRawValue(SymbolString& input,
|
||||
|
||||
result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
const unsigned char baseOffset, const unsigned char length,
|
||||
ostringstream& output, OutputFormat outputFormat)
|
||||
{
|
||||
ostringstream& output, OutputFormat outputFormat) {
|
||||
unsigned int value = 0;
|
||||
int signedValue;
|
||||
|
||||
@@ -810,8 +800,7 @@ result_t NumberDataType::readSymbols(SymbolString& input, const bool isMaster,
|
||||
|
||||
result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
const unsigned char baseOffset, const unsigned char length,
|
||||
SymbolString& output, unsigned char* usedLength)
|
||||
{
|
||||
SymbolString& output, unsigned char* usedLength) {
|
||||
size_t start = 0, count = length;
|
||||
int incr = 1;
|
||||
unsigned char ch;
|
||||
@@ -820,7 +809,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
return RESULT_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
if (m_firstBit > 0) {
|
||||
value <<= m_firstBit;
|
||||
value <<= m_firstBit;
|
||||
}
|
||||
|
||||
if (hasFlag(REV)) { // reverted binary representation (most significant byte first)
|
||||
@@ -841,7 +830,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
exp *= 100;
|
||||
} else {
|
||||
ch = (value / exp) & 0xff;
|
||||
exp <<= 8;
|
||||
exp <<= 8;
|
||||
}
|
||||
if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size()) {
|
||||
output[baseOffset + offset] |= ch;
|
||||
@@ -849,7 +838,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
output[baseOffset + offset] = ch;
|
||||
}
|
||||
}
|
||||
if (usedLength!=NULL) {
|
||||
if (usedLength != NULL) {
|
||||
*usedLength = length;
|
||||
}
|
||||
return RESULT_OK;
|
||||
@@ -857,8 +846,7 @@ result_t NumberDataType::writeRawValue(unsigned int value,
|
||||
|
||||
result_t NumberDataType::writeSymbols(istringstream& input,
|
||||
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;
|
||||
|
||||
const char* str = input.str().c_str();
|
||||
@@ -972,8 +960,7 @@ bool DataTypeList::s_contrib_initialized = libebus_contrib_register();
|
||||
#endif
|
||||
|
||||
|
||||
DataTypeList::DataTypeList()
|
||||
{
|
||||
DataTypeList::DataTypeList() {
|
||||
add(new StringDataType("STR", MAX_LEN*8, ADJ, ' ')); // >= 1 byte character string filled up with space
|
||||
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1)); // unsigned decimal in BCD, 0000 - 9999 (fixed length)
|
||||
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
|
||||
@@ -1036,13 +1023,11 @@ DataTypeList::DataTypeList()
|
||||
add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7
|
||||
}
|
||||
|
||||
DataTypeList* DataTypeList::getInstance()
|
||||
{
|
||||
DataTypeList* DataTypeList::getInstance() {
|
||||
return &s_instance;
|
||||
}
|
||||
|
||||
void DataTypeList::clear()
|
||||
{
|
||||
void DataTypeList::clear() {
|
||||
for (list<DataType*>::iterator it = m_cleanupTypes.begin(); it != m_cleanupTypes.end(); it++) {
|
||||
delete *it;
|
||||
}
|
||||
@@ -1051,12 +1036,11 @@ void DataTypeList::clear()
|
||||
m_typesById.clear();
|
||||
}
|
||||
|
||||
result_t DataTypeList::add(DataType* dataType)
|
||||
{
|
||||
result_t DataTypeList::add(DataType* dataType) {
|
||||
if (!dataType->isAdjustableLength()) {
|
||||
ostringstream str;
|
||||
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());
|
||||
if (it != m_typesByIdLength.end()) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
@@ -1074,8 +1058,7 @@ result_t DataTypeList::add(DataType* dataType)
|
||||
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;
|
||||
if (length > 0) {
|
||||
ostringstream str;
|
||||
|
||||
+26
-41
@@ -16,12 +16,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_DATATYPE_H_
|
||||
#define LIBEBUS_DATATYPE_H_
|
||||
#ifndef LIB_EBUS_DATATYPE_H_
|
||||
#define LIB_EBUS_DATATYPE_H_
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "filereader.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -29,6 +26,9 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include "filereader.h"
|
||||
|
||||
/** @file datatype.h
|
||||
* 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.
|
||||
* @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.
|
||||
@@ -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.
|
||||
* @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.
|
||||
@@ -146,10 +146,8 @@ void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<st
|
||||
/**
|
||||
* Base class for all kinds of data types.
|
||||
*/
|
||||
class DataType
|
||||
{
|
||||
public:
|
||||
|
||||
class DataType {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -251,8 +249,8 @@ public:
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** the type identifier. */
|
||||
const string m_id;
|
||||
|
||||
@@ -264,17 +262,14 @@ protected:
|
||||
|
||||
/** the replacement value (fill-up value for @a StringDataType, no replacement if equal to @a NumberDataType#minValue). */
|
||||
const unsigned int m_replacement;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A string based @a DataType.
|
||||
*/
|
||||
class StringDataType : public DataType
|
||||
{
|
||||
public:
|
||||
|
||||
class StringDataType : public DataType {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -284,7 +279,7 @@ public:
|
||||
* @param isHex true for hex digits instead of characters.
|
||||
*/
|
||||
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) {}
|
||||
|
||||
/**
|
||||
@@ -307,21 +302,18 @@ public:
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** true for hex digits instead of characters. */
|
||||
const bool m_isHex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A date/time based @a DataType.
|
||||
*/
|
||||
class DateTimeDataType : public DataType
|
||||
{
|
||||
public:
|
||||
|
||||
class DateTimeDataType : public DataType {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param id the type identifier.
|
||||
@@ -371,8 +363,8 @@ public:
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** true if date part is present. */
|
||||
const bool m_hasDate;
|
||||
|
||||
@@ -381,17 +373,14 @@ private:
|
||||
|
||||
/** the resolution in minutes for time types, or 1. */
|
||||
const short m_resolution;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A number based @a DataType.
|
||||
*/
|
||||
class NumberDataType : public DataType
|
||||
{
|
||||
public:
|
||||
|
||||
class NumberDataType : public DataType {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance for multiple of 8 bits.
|
||||
* @param id the type identifier.
|
||||
@@ -494,15 +483,15 @@ public:
|
||||
*/
|
||||
virtual result_t writeRawValue(unsigned int value,
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, unsigned char* usedLength=NULL);
|
||||
SymbolString& output, unsigned char* usedLength = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t writeSymbols(istringstream& input,
|
||||
const unsigned char offset, const unsigned char length,
|
||||
SymbolString& output, const bool isMaster, unsigned char* usedLength);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the minimum raw value. */
|
||||
const unsigned int m_minValue;
|
||||
|
||||
@@ -520,17 +509,14 @@ private:
|
||||
|
||||
/** the base @a NumberDataType for derived instances. */
|
||||
NumberDataType* m_baseType;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A map of base @a DataType instances.
|
||||
*/
|
||||
class DataTypeList
|
||||
{
|
||||
public:
|
||||
|
||||
class DataTypeList {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance and registers the known base data types.
|
||||
*/
|
||||
@@ -575,10 +561,10 @@ public:
|
||||
* @return the @a DataType instance, or NULL if not available.
|
||||
* 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:
|
||||
/** the known @a DataType instances by ID only. */
|
||||
map<string, DataType*> m_typesById;
|
||||
|
||||
@@ -596,7 +582,6 @@ private:
|
||||
/** true when contributed datatypes were successfully initialized. */
|
||||
static bool s_contrib_initialized;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_DATATYPE_H_
|
||||
#endif // LIB_EBUS_DATATYPE_H_
|
||||
|
||||
+28
-42
@@ -21,47 +21,44 @@
|
||||
#endif
|
||||
|
||||
#include "device.h"
|
||||
#include "data.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include "data.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
Device::~Device() {
|
||||
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) {
|
||||
char* in = strdup(name);
|
||||
bool udp = false;
|
||||
char* addrpos = in;
|
||||
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;
|
||||
portpos = strchr(addrpos, ':');
|
||||
}
|
||||
if (portpos==NULL) {
|
||||
if (portpos == NULL) {
|
||||
free(in);
|
||||
return NULL; // invalid protocol or missing port
|
||||
}
|
||||
result_t result = RESULT_OK;
|
||||
unsigned int port = parseInt(portpos+1, 10, 1, 65535, result);
|
||||
if (result!=RESULT_OK) {
|
||||
if (result != RESULT_OK) {
|
||||
free(in);
|
||||
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);
|
||||
}
|
||||
|
||||
void Device::close()
|
||||
{
|
||||
void Device::close() {
|
||||
if (m_fd != -1) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::isValid()
|
||||
{
|
||||
bool Device::isValid() {
|
||||
if (m_fd == -1) {
|
||||
return false;
|
||||
}
|
||||
@@ -103,8 +98,7 @@ bool Device::isValid()
|
||||
return m_fd != -1;
|
||||
}
|
||||
|
||||
result_t Device::send(const unsigned char value)
|
||||
{
|
||||
result_t Device::send(const unsigned char value) {
|
||||
if (!isValid()) {
|
||||
return RESULT_ERR_DEVICE;
|
||||
}
|
||||
@@ -117,8 +111,7 @@ result_t Device::send(const unsigned char value)
|
||||
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()) {
|
||||
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) {
|
||||
close();
|
||||
}
|
||||
@@ -228,8 +220,7 @@ result_t SerialDevice::open()
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void SerialDevice::close()
|
||||
{
|
||||
void SerialDevice::close() {
|
||||
if (m_fd != -1) {
|
||||
// empty device buffer
|
||||
tcflush(m_fd, TCIOFLUSH);
|
||||
@@ -240,8 +231,7 @@ void SerialDevice::close()
|
||||
Device::close();
|
||||
}
|
||||
|
||||
void SerialDevice::checkDevice()
|
||||
{
|
||||
void SerialDevice::checkDevice() {
|
||||
int port;
|
||||
if (ioctl(m_fd, TIOCMGET, &port) == -1) {
|
||||
close();
|
||||
@@ -249,8 +239,7 @@ void SerialDevice::checkDevice()
|
||||
}
|
||||
|
||||
|
||||
result_t NetworkDevice::open()
|
||||
{
|
||||
result_t NetworkDevice::open() {
|
||||
if (m_fd != -1) {
|
||||
close();
|
||||
}
|
||||
@@ -269,7 +258,7 @@ result_t NetworkDevice::open()
|
||||
value = 1;
|
||||
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));
|
||||
}
|
||||
if (ret < 0) {
|
||||
@@ -280,9 +269,10 @@ result_t NetworkDevice::open()
|
||||
if (ioctl(m_fd, FIONREAD, &cnt) >= 0 && cnt > 1) {
|
||||
// skip buffered input
|
||||
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_buffer = (unsigned char*)malloc(m_bufSize);
|
||||
if (!m_buffer) {
|
||||
@@ -296,8 +286,7 @@ result_t NetworkDevice::open()
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void NetworkDevice::checkDevice()
|
||||
{
|
||||
void NetworkDevice::checkDevice() {
|
||||
unsigned char value;
|
||||
ssize_t c = ::recv(m_fd, &value, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
if (c == 0 || (c < 0 && errno != EAGAIN)) {
|
||||
@@ -306,28 +295,25 @@ void NetworkDevice::checkDevice()
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkDevice::available()
|
||||
{
|
||||
return m_buffer && m_bufLen>0;
|
||||
bool NetworkDevice::available() {
|
||||
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
|
||||
return Device::write(value);
|
||||
}
|
||||
|
||||
ssize_t NetworkDevice::read(unsigned char& value)
|
||||
{
|
||||
ssize_t NetworkDevice::read(unsigned char& value) {
|
||||
if (available()) {
|
||||
value = m_buffer[m_bufPos];
|
||||
m_bufPos = (unsigned char)((m_bufPos+1)%m_bufSize);
|
||||
m_bufLen--;
|
||||
return 1;
|
||||
}
|
||||
if (m_bufSize>0) {
|
||||
if (m_bufSize > 0) {
|
||||
ssize_t size = ::read(m_fd, m_buffer, m_bufSize);
|
||||
if (size<=0) {
|
||||
if (size <= 0) {
|
||||
return size;
|
||||
}
|
||||
value = m_buffer[0];
|
||||
|
||||
+25
-31
@@ -16,15 +16,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_DEVICE_H_
|
||||
#define LIBEBUS_DEVICE_H_
|
||||
#ifndef LIB_EBUS_DEVICE_H_
|
||||
#define LIB_EBUS_DEVICE_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "result.h"
|
||||
|
||||
/** @file device.h
|
||||
@@ -41,10 +41,8 @@ using namespace std;
|
||||
/**
|
||||
* Interface for listening to data received on/sent to a device.
|
||||
*/
|
||||
class DeviceListener
|
||||
{
|
||||
public:
|
||||
|
||||
class DeviceListener {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
@@ -56,17 +54,14 @@ public:
|
||||
* @param received @a true on reception, @a false on sending.
|
||||
*/
|
||||
virtual void notifyDeviceData(const unsigned char byte, bool received) = 0; // abstract
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The base class for accessing an eBUS.
|
||||
*/
|
||||
class Device
|
||||
{
|
||||
|
||||
public:
|
||||
class Device {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -92,7 +87,7 @@ public:
|
||||
* @return the new @a Device, or NULL on error.
|
||||
* Note: the caller needs to free the created instance.
|
||||
*/
|
||||
static Device* create(const char* name, const bool checkDevice=true, const bool readOnly=false, const bool initialSend=false);
|
||||
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, const bool initialSend = false);
|
||||
|
||||
/**
|
||||
* Get the transfer latency of this device.
|
||||
@@ -150,7 +145,8 @@ public:
|
||||
*/
|
||||
void setListener(DeviceListener* listener) { m_listener = listener; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Check if the device is still available and close it if not.
|
||||
*/
|
||||
@@ -176,7 +172,6 @@ protected:
|
||||
*/
|
||||
virtual ssize_t read(unsigned char& value) { return ::read(m_fd, &value, 1); }
|
||||
|
||||
protected:
|
||||
/** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */
|
||||
const char* m_name;
|
||||
|
||||
@@ -192,19 +187,17 @@ protected:
|
||||
/** the opened file descriptor, or -1. */
|
||||
int m_fd;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the @a DeviceListener, or NULL. */
|
||||
DeviceListener* m_listener;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The @a Device for directly connected serial interfaces (tty).
|
||||
*/
|
||||
class SerialDevice : public Device
|
||||
{
|
||||
public:
|
||||
class SerialDevice : public Device {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -221,22 +214,22 @@ public:
|
||||
// @copydoc
|
||||
virtual void close();
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void checkDevice();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the previous settings of the device for restoring. */
|
||||
termios m_oldSettings;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The @a Device for remote network interfaces.
|
||||
*/
|
||||
class NetworkDevice : public Device
|
||||
{
|
||||
public:
|
||||
class NetworkDevice : public Device {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network).
|
||||
@@ -256,7 +249,8 @@ public:
|
||||
// @copydoc
|
||||
virtual result_t open();
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void checkDevice();
|
||||
|
||||
@@ -269,7 +263,8 @@ protected:
|
||||
// @copydoc
|
||||
virtual ssize_t read(unsigned char& value);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the socket address of the device. */
|
||||
const struct sockaddr_in m_address;
|
||||
|
||||
@@ -287,7 +282,6 @@ private:
|
||||
|
||||
/** the buffer read position. */
|
||||
unsigned char m_bufPos;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_DEVICE_H_
|
||||
#endif // LIB_EBUS_DEVICE_H_
|
||||
|
||||
+51
-58
@@ -16,11 +16,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_FILEREADER_H_
|
||||
#define LIBEBUS_FILEREADER_H_
|
||||
#ifndef LIB_EBUS_FILEREADER_H_
|
||||
#define LIB_EBUS_FILEREADER_H_
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
@@ -28,6 +26,8 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
|
||||
/** @file filereader.h
|
||||
* Helper class and constants for reading configuration files.
|
||||
@@ -60,10 +60,8 @@ extern unsigned int parseInt(const char* str, int base, const unsigned int minVa
|
||||
/**
|
||||
* An abstract class that support reading definitions from a file.
|
||||
*/
|
||||
class FileReader
|
||||
{
|
||||
public:
|
||||
|
||||
class FileReader {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -84,9 +82,8 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
virtual result_t readFromFile(const string filename, bool verbose=false,
|
||||
string defaultDest = "", string defaultCircuit = "", string defaultSuffix = "")
|
||||
{
|
||||
virtual result_t readFromFile(const string filename, bool verbose = false,
|
||||
string defaultDest = "", string defaultCircuit = "", string defaultSuffix = "") {
|
||||
ifstream ifs;
|
||||
ifs.open(filename.c_str(), ifstream::in);
|
||||
if (!ifs.is_open()) {
|
||||
@@ -94,7 +91,7 @@ public:
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
size_t lastSep = filename.find_last_of('/');
|
||||
if (lastSep!=string::npos) { // potential destination address, matches "^ZZ."
|
||||
if (lastSep != string::npos) { // potential destination address, matches "^ZZ."
|
||||
// extract defaultDest, defaultCircuit, defaultSuffix from filename:
|
||||
// ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv
|
||||
unsigned char checkDest;
|
||||
@@ -114,9 +111,9 @@ public:
|
||||
vector<string> row;
|
||||
vector< vector<string> > defaults;
|
||||
while (splitFields(ifs, row, lineNo)) {
|
||||
if (row.empty())
|
||||
if (row.empty()) {
|
||||
continue;
|
||||
|
||||
}
|
||||
result_t result;
|
||||
vector<string>::iterator it = row.begin();
|
||||
const vector<string>::iterator end = row.end();
|
||||
@@ -124,31 +121,33 @@ public:
|
||||
if (row[0][0] == '*') {
|
||||
row[0] = row[0].substr(1);
|
||||
result = addDefaultFromFile(defaults, row, it, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
|
||||
if (result == RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
continue;
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
result = addFromFile(it, end, &defaults, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
result = addFromFile(it, end, NULL, defaultDest, defaultCircuit, defaultSuffix, filename, lineNo);
|
||||
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
if (!verbose) {
|
||||
ifs.close();
|
||||
ostringstream error;
|
||||
error << filename << ":" << static_cast<unsigned>(lineNo);
|
||||
if (m_lastError.length()>0) {
|
||||
if (m_lastError.length() > 0) {
|
||||
error << ": " << m_lastError;
|
||||
}
|
||||
m_lastError = error.str();
|
||||
return result;
|
||||
}
|
||||
if (m_lastError.length()>0) {
|
||||
if (m_lastError.length() > 0) {
|
||||
cout << m_lastError << endl;
|
||||
}
|
||||
printErrorPos(cout, row.begin(), end, it, filename, lineNo, result);
|
||||
} else if (!verbose)
|
||||
} else if (!verbose) {
|
||||
m_lastError = "";
|
||||
}
|
||||
}
|
||||
|
||||
ifs.close();
|
||||
@@ -175,8 +174,7 @@ public:
|
||||
*/
|
||||
virtual result_t addDefaultFromFile(vector< vector<string> >& defaults, vector<string>& row,
|
||||
vector<string>::iterator& begin, string defaultDest, string defaultCircuit, string defaultSuffix,
|
||||
const string& filename, unsigned int lineNo)
|
||||
{
|
||||
const string& filename, unsigned int lineNo) {
|
||||
defaults.push_back(row);
|
||||
begin = row.end();
|
||||
return RESULT_OK;
|
||||
@@ -202,14 +200,13 @@ public:
|
||||
* Left and right trim the string.
|
||||
* @param str the @a string to trim.
|
||||
*/
|
||||
static void trim(string& str)
|
||||
{
|
||||
static void trim(string& str) {
|
||||
size_t pos = str.find_first_not_of(" \t");
|
||||
if (pos!=string::npos) {
|
||||
if (pos != string::npos) {
|
||||
str.erase(0, pos);
|
||||
}
|
||||
pos = str.find_last_not_of(" \t");
|
||||
if (pos!=string::npos) {
|
||||
if (pos != string::npos) {
|
||||
str.erase(pos+1);
|
||||
}
|
||||
}
|
||||
@@ -218,8 +215,7 @@ public:
|
||||
* Convert all upper case characters in the string to lower case.
|
||||
* @param str the @a string to convert.
|
||||
*/
|
||||
static void tolower(string& str)
|
||||
{
|
||||
static void tolower(string& str) {
|
||||
transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
}
|
||||
|
||||
@@ -230,8 +226,7 @@ public:
|
||||
* @param lineNo the current line number (incremented with each line read).
|
||||
* @return true if there are more lines to read, false when there are no more lines left.
|
||||
*/
|
||||
static bool splitFields(istream& ifs, vector<string>& row, unsigned int& lineNo)
|
||||
{
|
||||
static bool splitFields(istream& ifs, vector<string>& row, unsigned int& lineNo) {
|
||||
row.clear();
|
||||
string line;
|
||||
bool quotedText = false, wasQuoted = false;
|
||||
@@ -244,13 +239,12 @@ public:
|
||||
trim(line);
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
for (size_t pos = 0; pos < length; pos++) {
|
||||
char ch = line[pos];
|
||||
switch (ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case FIELD_SEPARATOR:
|
||||
if (quotedText) {
|
||||
field << ch;
|
||||
@@ -278,10 +272,10 @@ public:
|
||||
case '\r':
|
||||
break;
|
||||
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
|
||||
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 << ch;
|
||||
@@ -289,8 +283,9 @@ public:
|
||||
}
|
||||
prev = ch;
|
||||
}
|
||||
if (!quotedText)
|
||||
if (!quotedText) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
string str = field.str();
|
||||
trim(str);
|
||||
@@ -314,55 +309,54 @@ public:
|
||||
* @return true if at least the address and the identification part were extracted, false otherwise.
|
||||
*/
|
||||
static bool extractDefaultsFromFilename(string name, unsigned char& dest, string& ident, string& circuit,
|
||||
string& suffix, unsigned int& software, unsigned int& hardware)
|
||||
{
|
||||
string& suffix, unsigned int& software, unsigned int& hardware) {
|
||||
ident = circuit = suffix = "";
|
||||
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 "."
|
||||
}
|
||||
size_t pos = name.find('.');
|
||||
if (pos!=2) {
|
||||
if (pos != 2) {
|
||||
return false; // missing "ZZ."
|
||||
}
|
||||
result_t result = RESULT_OK;
|
||||
dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL);
|
||||
if (result!=RESULT_OK || !isValidAddress(dest)) {
|
||||
if (result != RESULT_OK || !isValidAddress(dest)) {
|
||||
return false; // invalid "ZZ"
|
||||
}
|
||||
name.erase(0, pos);
|
||||
if (name.length()>1) {
|
||||
if (name.length() > 1) {
|
||||
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);
|
||||
if (result!=RESULT_OK) {
|
||||
if (result != RESULT_OK) {
|
||||
return false; // invalid "SWxxxx"
|
||||
}
|
||||
name.erase(pos, 7);
|
||||
}
|
||||
}
|
||||
if (name.length()>1) {
|
||||
if (name.length() > 1) {
|
||||
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);
|
||||
if (result!=RESULT_OK) {
|
||||
if (result != RESULT_OK) {
|
||||
return false; // invalid "HWxxxx"
|
||||
}
|
||||
name.erase(pos, 7);
|
||||
}
|
||||
}
|
||||
if (name.length()>1) {
|
||||
if (name.length() > 1) {
|
||||
pos = name.find('.', 1); // check for ".IDENT."
|
||||
if (pos!=string::npos && pos>=1 && pos<=6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".."
|
||||
if (pos != string::npos && pos >= 1 && pos <= 6) { // up to 5 chars between two "."s, immediately after "ZZ.", or ".."
|
||||
ident = circuit = name.substr(1, pos-1);
|
||||
name.erase(0, pos);
|
||||
pos = name.find('.', 1); // check for ".CIRCUIT."
|
||||
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);
|
||||
name.erase(0, pos);
|
||||
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);
|
||||
name.erase(0, pos);
|
||||
}
|
||||
@@ -371,16 +365,15 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** whether this instance supports rows with defaults (starting with a star). */
|
||||
bool m_supportsDefaults;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** a @a string describing the last error position. */
|
||||
string m_lastError;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_FILEREADER_H_
|
||||
#endif // LIB_EBUS_FILEREADER_H_
|
||||
|
||||
+468
-440
File diff suppressed because it is too large
Load Diff
+102
-131
@@ -16,16 +16,18 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_MESSAGE_H_
|
||||
#define LIBEBUS_MESSAGE_H_
|
||||
#ifndef LIB_EBUS_MESSAGE_H_
|
||||
#define LIB_EBUS_MESSAGE_H_
|
||||
|
||||
#include "data.h"
|
||||
#include "result.h"
|
||||
#include "symbol.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include "data.h"
|
||||
#include "result.h"
|
||||
#include "symbol.h"
|
||||
|
||||
/** @file message.h
|
||||
* Classes and functions for decoding and encoding of complete messages on the
|
||||
@@ -91,11 +93,9 @@ class MessageMap;
|
||||
/**
|
||||
* Defines parameters of a message sent or received on the bus.
|
||||
*/
|
||||
class Message
|
||||
{
|
||||
class Message {
|
||||
friend class MessageMap;
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param circuit the optional circuit name.
|
||||
@@ -117,10 +117,11 @@ public:
|
||||
const unsigned char srcAddress, const unsigned char dstAddress,
|
||||
const vector<unsigned char> id,
|
||||
DataField* data, const bool deleteData,
|
||||
const unsigned char pollPriority=0,
|
||||
Condition* condition=NULL);
|
||||
const unsigned char pollPriority = 0,
|
||||
Condition* condition = NULL);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Construct a new scan @a Message instance.
|
||||
* @param circuit the circuit name, or empty for not storing by name.
|
||||
@@ -138,11 +139,12 @@ private:
|
||||
const unsigned char pb, const unsigned char sb,
|
||||
DataField* data, const bool deleteData);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Message() { if (m_deleteData) delete m_data; }
|
||||
virtual ~Message() { if (m_deleteData) { delete m_data; } }
|
||||
|
||||
/**
|
||||
* Calculate the key for the ID.
|
||||
@@ -166,7 +168,7 @@ public:
|
||||
* @return the key for the ID, or -1LL if the data is invalid.
|
||||
*/
|
||||
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.
|
||||
@@ -222,7 +224,7 @@ public:
|
||||
* @param circuit the new circuit name, or empty to use the current circuit name.
|
||||
* @return the derived @a Message instance.
|
||||
*/
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress=SYN, const string circuit="");
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
|
||||
|
||||
/**
|
||||
* Derive a new @a Message from this message.
|
||||
@@ -313,7 +315,7 @@ public:
|
||||
* @param index the variable in which to store the message part index, or NULL to ignore.
|
||||
* @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.
|
||||
@@ -357,7 +359,7 @@ public:
|
||||
* Return whether 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).
|
||||
@@ -371,7 +373,7 @@ public:
|
||||
* @param numeric true for a numeric field, false for a string field.
|
||||
* @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.
|
||||
@@ -389,11 +391,11 @@ public:
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData,
|
||||
istringstream& input, char separator=UI_FIELD_SEPARATOR,
|
||||
const unsigned char dstAddress=SYN, unsigned char index=0);
|
||||
istringstream& input, char separator = UI_FIELD_SEPARATOR,
|
||||
const unsigned char dstAddress = SYN, unsigned char index = 0);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Prepare a part of the master data @a SymbolString for sending (everything including NN).
|
||||
* @param master the master data @a SymbolString for writing symbols to.
|
||||
@@ -404,8 +406,8 @@ protected:
|
||||
*/
|
||||
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Prepare the slave @a SymbolString for sending an answer to the bus.
|
||||
* @param input the @a istringstream to parse the formatted value(s) from.
|
||||
@@ -442,8 +444,8 @@ public:
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t decodeLastData(const PartType partType,
|
||||
ostringstream& output, OutputFormat outputFormat=0,
|
||||
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1);
|
||||
ostringstream& output, OutputFormat outputFormat = 0,
|
||||
bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat=0,
|
||||
bool leadingSeparator=false, const char* fieldName=NULL, signed char fieldIndex=-1);
|
||||
virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat = 0,
|
||||
bool leadingSeparator = false, const char* fieldName = NULL, signed char fieldIndex = -1);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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.
|
||||
@@ -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 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.
|
||||
@@ -517,10 +519,10 @@ public:
|
||||
* @param column the column index to write (see @p COLUMN_TYPE index constants).
|
||||
* @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:
|
||||
/** the optional circuit name. */
|
||||
const string m_circuit;
|
||||
|
||||
@@ -604,17 +606,14 @@ protected:
|
||||
|
||||
/** the system time when this message was last polled for, 0 for never. */
|
||||
time_t m_lastPollTime;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A chained @a Message that needs more than one read/write on the bus to collect/send the data.
|
||||
*/
|
||||
class ChainedMessage : public Message
|
||||
{
|
||||
public:
|
||||
|
||||
class ChainedMessage : public Message {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param circuit the optional circuit name.
|
||||
@@ -638,18 +637,18 @@ public:
|
||||
vector< vector<unsigned char> > ids, vector<unsigned char> lengths,
|
||||
DataField* data, const bool deleteData,
|
||||
const unsigned char pollPriority,
|
||||
Condition* condition=NULL);
|
||||
Condition* condition = NULL);
|
||||
|
||||
virtual ~ChainedMessage();
|
||||
|
||||
// @copydoc
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress=SYN, const string circuit="");
|
||||
virtual Message* derive(const unsigned char dstAddress, const unsigned char srcAddress = SYN, const string circuit = "");
|
||||
|
||||
// @copydoc
|
||||
virtual unsigned char getIdLength() const { return (unsigned char)(m_ids[0].size() - 2); }
|
||||
|
||||
// @copydoc
|
||||
virtual bool checkId(SymbolString& master, unsigned char* index=NULL);
|
||||
virtual bool checkId(SymbolString& master, unsigned char* index = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool checkId(Message& other);
|
||||
@@ -657,26 +656,26 @@ public:
|
||||
// @copydoc
|
||||
virtual unsigned char getCount() { return (unsigned char)m_ids.size(); }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual result_t prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
// @copydoc
|
||||
virtual result_t storeLastData(SymbolString& master, SymbolString& slave);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t storeLastData(const PartType partType, SymbolString& data, unsigned char index);
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual void dumpColumn(ostream& output, size_t column, bool withConditions=false);
|
||||
virtual void dumpColumn(ostream& output, size_t column, bool withConditions = false);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the primary, secondary, and optional further ID bytes for each part of the chain. */
|
||||
const vector< vector<unsigned char> > m_ids;
|
||||
|
||||
@@ -697,21 +696,20 @@ private:
|
||||
|
||||
/** array of the system times when the corresponding slave data was last updated, 0 for never. */
|
||||
time_t* m_lastSlaveUpdateTimes;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A function that compares the weighted poll priority of two @a Message instances.
|
||||
*/
|
||||
struct compareMessagePriority : binary_function <Message*,Message*,bool> {
|
||||
struct compareMessagePriority : binary_function <Message*, Message*, bool> {
|
||||
/**
|
||||
* Compare the weighted poll priority of the two @a Message instances.
|
||||
* @param x the first @a Message.
|
||||
* @param y the second @a Message.
|
||||
* @return whether @a x is smaller than @a y with regard to their weighted poll priority.
|
||||
*/
|
||||
bool operator() (Message* x, Message* y) const { return x->isLessPollWeight(y); };
|
||||
bool operator() (Message* x, Message* y) const { return x->isLessPollWeight(y); }
|
||||
};
|
||||
|
||||
|
||||
@@ -719,17 +717,15 @@ struct compareMessagePriority : binary_function <Message*,Message*,bool> {
|
||||
* Helper class extending @a priority_queue to hold distinct values only.
|
||||
*/
|
||||
class MessagePriorityQueue
|
||||
: public priority_queue<Message*, vector<Message*>, compareMessagePriority>
|
||||
{
|
||||
public:
|
||||
: public priority_queue<Message*, vector<Message*>, compareMessagePriority> {
|
||||
public:
|
||||
/**
|
||||
* Add data to the queue and ensure it is contained only once.
|
||||
* @param __x the element to add.
|
||||
*/
|
||||
void push(const value_type& __x)
|
||||
{
|
||||
void push(const value_type& __x) {
|
||||
for (vector<Message*>::iterator it = c.begin(); it != c.end(); it++) {
|
||||
if (*it==__x) {
|
||||
if (*it == __x) {
|
||||
c.erase(it);
|
||||
break;
|
||||
}
|
||||
@@ -742,10 +738,8 @@ public:
|
||||
/**
|
||||
* An abstract condition based on the value of one or more @a Message instances.
|
||||
*/
|
||||
class Condition
|
||||
{
|
||||
public:
|
||||
|
||||
class Condition {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -774,14 +768,14 @@ public:
|
||||
* @param valueList the @a string with the new list of values.
|
||||
* @return the derived @a SimpleCondition instance, or NULL if the value list is invalid.
|
||||
*/
|
||||
virtual SimpleCondition* derive(string valueList) { return NULL; };
|
||||
virtual SimpleCondition* derive(string valueList) { return NULL; }
|
||||
|
||||
/**
|
||||
* Write the condition definition or resolved expression to the @a ostream.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
@@ -797,7 +791,7 @@ public:
|
||||
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL) = 0;
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL) = 0;
|
||||
|
||||
/**
|
||||
* Check and return whether this condition is fulfilled.
|
||||
@@ -805,24 +799,21 @@ public:
|
||||
*/
|
||||
virtual bool isTrue() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** the system time when the condition was last checked, 0 for never. */
|
||||
time_t m_lastCheckTime;
|
||||
|
||||
/** whether the condition was @a true during the last check. */
|
||||
bool m_isTrue;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple @a Condition based on the value of one @a Message.
|
||||
*/
|
||||
class SimpleCondition : public Condition
|
||||
{
|
||||
public:
|
||||
|
||||
class SimpleCondition : public Condition {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
@@ -833,7 +824,7 @@ public:
|
||||
* @param field the field name.
|
||||
* @param hasValues whether a value has to be checked against.
|
||||
*/
|
||||
SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues=false)
|
||||
SimpleCondition(const string condName, const string refName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues = false)
|
||||
: Condition(),
|
||||
m_condName(condName), m_refName(refName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
|
||||
|
||||
@@ -846,13 +837,13 @@ public:
|
||||
virtual SimpleCondition* derive(string valueList);
|
||||
|
||||
// @copydoc
|
||||
virtual void dump(ostream& output, bool matched=false);
|
||||
virtual void dump(ostream& output, bool matched = false);
|
||||
|
||||
// @copydoc
|
||||
virtual CombinedCondition* combineAnd(Condition* other);
|
||||
|
||||
// @copydoc
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL);
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool isTrue();
|
||||
@@ -863,8 +854,8 @@ public:
|
||||
*/
|
||||
virtual bool isNumeric() { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Check the values against the field in the @a Message.
|
||||
* @param message the @a Message to check against.
|
||||
@@ -876,8 +867,8 @@ protected:
|
||||
/** the value that matched in @a checkValue. */
|
||||
string m_matchedValue;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the condition name. */
|
||||
const string m_condName;
|
||||
|
||||
@@ -901,17 +892,14 @@ private:
|
||||
|
||||
/** the resolved @a Message instance, or NULL. */
|
||||
Message* m_message;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple @a Condition based on the numeric value of one @a Message.
|
||||
*/
|
||||
class SimpleNumericCondition : public SimpleCondition
|
||||
{
|
||||
public:
|
||||
|
||||
class SimpleNumericCondition : public SimpleCondition {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
@@ -931,26 +919,23 @@ public:
|
||||
*/
|
||||
virtual ~SimpleNumericCondition() {}
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */
|
||||
const vector<unsigned int> m_valueRanges;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple @a Condition based on the string value of one @a Message.
|
||||
*/
|
||||
class SimpleStringCondition : public SimpleCondition
|
||||
{
|
||||
public:
|
||||
|
||||
class SimpleStringCondition : public SimpleCondition {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
@@ -973,26 +958,23 @@ public:
|
||||
// @copydoc
|
||||
virtual bool isNumeric() { return false; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the valid values. */
|
||||
const vector<string> m_values;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A @a Condition combining two or more @a SimpleCondition instances with a logical and.
|
||||
*/
|
||||
class CombinedCondition : public Condition
|
||||
{
|
||||
public:
|
||||
|
||||
class CombinedCondition : public Condition {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
@@ -1005,32 +987,29 @@ public:
|
||||
virtual ~CombinedCondition() {}
|
||||
|
||||
// @copydoc
|
||||
virtual void dump(ostream& output, bool matched=false);
|
||||
virtual void dump(ostream& output, bool matched = false);
|
||||
|
||||
// @copydoc
|
||||
virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; }
|
||||
|
||||
// @copydoc
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message)=NULL);
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, void (*readMessageFunc)(Message* message) = NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool isTrue();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the @a Condition instances used. */
|
||||
vector<Condition*> m_conditions;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An abstract instruction based on the value of one or more @a Message instances.
|
||||
*/
|
||||
class Instruction
|
||||
{
|
||||
public:
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
@@ -1090,16 +1069,16 @@ public:
|
||||
*/
|
||||
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition) = 0;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the @a Condition this instruction requires, or null. */
|
||||
Condition* m_condition;
|
||||
|
||||
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file. */
|
||||
bool m_singleton;
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/** the default destination address, or empty. */
|
||||
const string m_defaultDest;
|
||||
|
||||
@@ -1108,17 +1087,14 @@ protected:
|
||||
|
||||
/** the default circuit name suffix (starting with a "."), or empty. */
|
||||
const string m_defaultSuffix;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An @a Instruction allowing to load another file.
|
||||
*/
|
||||
class LoadInstruction : public Instruction
|
||||
{
|
||||
public:
|
||||
|
||||
class LoadInstruction : public Instruction {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
@@ -1139,28 +1115,24 @@ public:
|
||||
// @copydoc
|
||||
virtual result_t execute(MessageMap* messages, ostringstream& log, Condition* condition);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the name of the file to load. */
|
||||
const string m_filename;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Holds a map of all known @a Message instances.
|
||||
*/
|
||||
class MessageMap : public FileReader
|
||||
{
|
||||
public:
|
||||
|
||||
class MessageMap : public FileReader {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param addAll whether to add all messages, even if duplicate.
|
||||
*/
|
||||
MessageMap(const bool addAll=false) : FileReader::FileReader(true),
|
||||
m_addAll(addAll), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0)
|
||||
{
|
||||
MessageMap(const bool addAll = false) : FileReader::FileReader(true),
|
||||
m_addAll(addAll), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) {
|
||||
m_scanMessage = Message::createScanMessage();
|
||||
}
|
||||
|
||||
@@ -1179,7 +1151,7 @@ public:
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
* 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
|
||||
virtual result_t addDefaultFromFile(vector< vector<string> >& defaults, vector<string>& row,
|
||||
@@ -1205,14 +1177,14 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
Message* getScanMessage(const unsigned char dstAddress=SYN);
|
||||
Message* getScanMessage(const unsigned char dstAddress = SYN);
|
||||
|
||||
/**
|
||||
* Resolve all @a Condition instances.
|
||||
* @param verbose whether to verbosely add all problems to the error message.
|
||||
* @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.
|
||||
@@ -1220,7 +1192,7 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
@@ -1229,7 +1201,7 @@ public:
|
||||
* @a Message values from the bus required for singleton instructions, or NULL.
|
||||
* @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.
|
||||
@@ -1263,7 +1235,7 @@ public:
|
||||
* @return the @a Message instance, or NULL.
|
||||
* 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.
|
||||
@@ -1280,10 +1252,10 @@ public:
|
||||
* @param until the end time to which to add updates (exclusive, also removes messages with unset destination address), or 0 to ignore.
|
||||
* Note: the caller may not free the returned instances.
|
||||
*/
|
||||
deque<Message*> findAll(const string& circuit, const string& name, const bool completeMatch=true,
|
||||
const bool withRead=true, const bool withWrite=false, const bool withPassive=false,
|
||||
const bool completeMatchIgnoreCircuitSuffix=false, const bool onlyAvailable=true,
|
||||
const time_t since=0, const time_t until=0);
|
||||
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 completeMatchIgnoreCircuitSuffix = false, const bool onlyAvailable = true,
|
||||
const time_t since = 0, const time_t until = 0);
|
||||
|
||||
/**
|
||||
* Find the @a Message instance for the specified master data.
|
||||
@@ -1295,8 +1267,8 @@ public:
|
||||
* @return the @a Message instance, or NULL.
|
||||
* Note: the caller may not free the returned instance.
|
||||
*/
|
||||
Message* find(SymbolString& master, bool anyDestination=false,
|
||||
const bool withRead=true, const bool withWrite=true, const bool withPassive=true);
|
||||
Message* find(SymbolString& master, bool anyDestination = false,
|
||||
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.
|
||||
@@ -1309,7 +1281,7 @@ public:
|
||||
* @param message the @a Message to poll.
|
||||
* @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.
|
||||
@@ -1364,10 +1336,10 @@ public:
|
||||
* @param output the @a ostream to append the formatted messages to.
|
||||
* @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:
|
||||
/** whether to add all messages, even if duplicate. */
|
||||
const bool m_addAll;
|
||||
|
||||
@@ -1403,7 +1375,6 @@ private:
|
||||
|
||||
/** the list of @a Instruction instances by filename. */
|
||||
map<string, vector<Instruction*> > m_instructions;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_MESSAGE_H_
|
||||
#endif // LIB_EBUS_MESSAGE_H_
|
||||
|
||||
@@ -51,8 +51,9 @@ const char* getResultCode(result_t resultCode) {
|
||||
case RESULT_ERR_SYN: return "ERR: SYN received";
|
||||
|
||||
default:
|
||||
if (resultCode >= 0)
|
||||
if (resultCode >= 0) {
|
||||
return "done: unknown result code";
|
||||
}
|
||||
return "ERR: unknown result code";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_RESULT_H_
|
||||
#define LIBEBUS_RESULT_H_
|
||||
#ifndef LIB_EBUS_RESULT_H_
|
||||
#define LIB_EBUS_RESULT_H_
|
||||
|
||||
/** @file result.h
|
||||
* Functions, and constants related to execution results.
|
||||
@@ -70,4 +70,4 @@ enum result_t {
|
||||
*/
|
||||
const char* getResultCode(result_t resultCode);
|
||||
|
||||
#endif // LIBEBUS_RESULT_H_
|
||||
#endif // LIB_EBUS_RESULT_H_
|
||||
|
||||
+14
-18
@@ -17,17 +17,18 @@
|
||||
*/
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "result.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1.
|
||||
*/
|
||||
static const unsigned char CRC_LOOKUP_TABLE[] =
|
||||
{
|
||||
static const unsigned char CRC_LOOKUP_TABLE[] = {
|
||||
0x00, 0x9b, 0xad, 0x36, 0xc1, 0x5a, 0x6c, 0xf7, 0x19, 0x82, 0xb4, 0x2f, 0xd8, 0x43, 0x75, 0xee,
|
||||
0x32, 0xa9, 0x9f, 0x04, 0xf3, 0x68, 0x5e, 0xc5, 0x2b, 0xb0, 0x86, 0x1d, 0xea, 0x71, 0x47, 0xdc,
|
||||
0x64, 0xff, 0xc9, 0x52, 0xa5, 0x3e, 0x08, 0x93, 0x7d, 0xe6, 0xd0, 0x4b, 0xbc, 0x27, 0x11, 0x8a,
|
||||
@@ -47,13 +48,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 isEscaped = str.m_unescapeState == 0;
|
||||
vector<unsigned char> data = str.m_data;
|
||||
size_t end = data.size();
|
||||
if (end>0 && skipLastSymbol) {
|
||||
if (end > 0 && skipLastSymbol) {
|
||||
end--;
|
||||
}
|
||||
for (size_t i = 0; i < end; i++) {
|
||||
@@ -64,8 +64,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;
|
||||
for (size_t i = 0; i < str.size(); i += 2) {
|
||||
char* strEnd = NULL;
|
||||
@@ -83,8 +82,7 @@ result_t SymbolString::parseHex(const string& str, const bool isEscaped)
|
||||
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;
|
||||
bool previousEscape = false;
|
||||
|
||||
@@ -111,8 +109,7 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
|
||||
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 (!isEscaped && value == ESC) {
|
||||
m_data.push_back(ESC);
|
||||
@@ -196,8 +193,7 @@ void SymbolString::addCRC(const unsigned char value) {
|
||||
* @return the 1-based index of the upper or lower 4 bits of a master address (1 to 5), or 0.
|
||||
*/
|
||||
unsigned char getMasterPartIndex(unsigned char bits) {
|
||||
switch (bits)
|
||||
{
|
||||
switch (bits) {
|
||||
case 0x0:
|
||||
return 1;
|
||||
case 0x1:
|
||||
@@ -214,8 +210,8 @@ unsigned char getMasterPartIndex(unsigned char bits) {
|
||||
}
|
||||
|
||||
bool isMaster(unsigned char addr) {
|
||||
return getMasterPartIndex(addr & 0x0F)>0
|
||||
&& getMasterPartIndex((addr & 0xF0) >> 4)>0;
|
||||
return getMasterPartIndex(addr & 0x0F) > 0
|
||||
&& getMasterPartIndex((addr & 0xF0)>>4) > 0;
|
||||
}
|
||||
|
||||
bool isSlaveMaster(unsigned char addr) {
|
||||
@@ -245,11 +241,11 @@ unsigned char getMasterAddress(unsigned char addr) {
|
||||
|
||||
unsigned char getMasterNumber(unsigned char addr) {
|
||||
unsigned char priority = getMasterPartIndex(addr & 0x0F);
|
||||
if (priority==0) {
|
||||
if (priority == 0) {
|
||||
return 0;
|
||||
}
|
||||
unsigned char index = getMasterPartIndex((addr & 0xF0) >> 4);
|
||||
if (index==0) {
|
||||
if (index == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (unsigned char)(5*(priority-1) + index);
|
||||
|
||||
+33
-25
@@ -16,14 +16,18 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBEBUS_SYMBOL_H_
|
||||
#define LIBEBUS_SYMBOL_H_
|
||||
#ifndef LIB_EBUS_SYMBOL_H_
|
||||
#define LIB_EBUS_SYMBOL_H_
|
||||
|
||||
#include "result.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "result.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** @file symbol.h
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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 SYN = 0xAA; //!< synchronization symbol
|
||||
static const unsigned char ACK = 0x00; //!< positive acknowledge
|
||||
@@ -73,22 +75,20 @@ static const unsigned char BROADCAST = 0xFE; //!< the broadcast destination addr
|
||||
/**
|
||||
* A string of escaped or unescaped bus symbols.
|
||||
*/
|
||||
class SymbolString
|
||||
{
|
||||
|
||||
public:
|
||||
class SymbolString {
|
||||
public:
|
||||
/**
|
||||
* Creates a new empty escaped or unescaped 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.
|
||||
* @param str the @a SymbolString to copy from.
|
||||
* @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.
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
* @param isEscaped whether the hex string is escaped.
|
||||
* @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.
|
||||
@@ -104,28 +104,28 @@ public:
|
||||
* @param skipLastSymbol whether to skip the last symbol (probably the CRC).
|
||||
* @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.
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the reference to the symbol at the specified index.
|
||||
*/
|
||||
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) m_data.resize(index+1, 0); return m_data[index]; }
|
||||
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) { m_data.resize(index+1, 0); } return m_data[index]; }
|
||||
|
||||
/**
|
||||
* Return whether this instance is equal to the other instance.
|
||||
* @param other the other instance.
|
||||
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols).
|
||||
*/
|
||||
bool operator==(SymbolString& other) { return m_unescapeState==other.m_unescapeState && m_data==other.m_data; }
|
||||
bool operator == (SymbolString& other) { return m_unescapeState == other.m_unescapeState && m_data == other.m_data; }
|
||||
|
||||
/**
|
||||
* Return whether this instance is different from the other instance.
|
||||
* @param other the other instance.
|
||||
* @return true if this instance is different from the other instance.
|
||||
*/
|
||||
bool operator!=(SymbolString& other) { return m_unescapeState!=other.m_unescapeState || m_data!=other.m_data; }
|
||||
bool operator != (SymbolString& other) { return m_unescapeState != other.m_unescapeState || m_data != other.m_data; }
|
||||
|
||||
/**
|
||||
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master address and ending with the CRC).
|
||||
@@ -135,10 +135,18 @@ public:
|
||||
* 2 if this instance only differs from the other instance in the first byte (the master address).
|
||||
*/
|
||||
int compareMaster(SymbolString& other) {
|
||||
if (m_unescapeState!=other.m_unescapeState || m_data.size()!=other.m_data.size()) return 1;
|
||||
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;
|
||||
if (m_unescapeState != other.m_unescapeState || m_data.size() != other.m_data.size()) {
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -151,7 +159,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_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.
|
||||
@@ -168,7 +176,7 @@ public:
|
||||
/**
|
||||
* 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.
|
||||
@@ -176,8 +184,8 @@ public:
|
||||
*/
|
||||
void clear(const bool escape) { m_data.clear(); m_unescapeState = escape ? 0 : 1; m_crc = 0; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param str the @a SymbolString to copy from.
|
||||
@@ -247,6 +255,6 @@ unsigned char getMasterNumber(unsigned char addr);
|
||||
* @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.
|
||||
*/
|
||||
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_
|
||||
|
||||
+247
-248
@@ -16,17 +16,18 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "data.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool error = false;
|
||||
|
||||
void verify(bool expectFailMatch, string type, string input,
|
||||
bool match, string expectStr, string gotStr)
|
||||
{
|
||||
bool match, string expectStr, string gotStr) {
|
||||
match = match && expectStr == gotStr;
|
||||
if (expectFailMatch) {
|
||||
if (match) {
|
||||
@@ -45,8 +46,7 @@ void verify(bool expectFailMatch, string type, string input,
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
string checks[][5] = {
|
||||
// entry: definition, decoded value, master data, slave data, flags
|
||||
// definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
|
||||
@@ -86,45 +86,45 @@ int main()
|
||||
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe070005ababababab", "00", "rW"},
|
||||
{"x,,hex:5,=48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
|
||||
{"x,,hex:5,==48 61 6c 6c 6f", "", "10fe07000548616c6c6f", "00", ""},
|
||||
{"x,,bda", "26.10.2014","10fe07000426100614", "00", ""}, // Sunday
|
||||
{"x,,bda", "01.01.2000","10fe07000401010500", "00", ""}, // Saturday
|
||||
{"x,,bda", "31.12.2099","10fe07000431120399", "00", ""}, // Thursday
|
||||
{"x,,bda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,bda", "", "10fe07000432100014", "00", "rw"},
|
||||
{"x,,bda:3", "26.10.2014","10fe070003261014", "00", ""},
|
||||
{"x,,bda:3", "01.01.2000","10fe070003010100", "00", ""},
|
||||
{"x,,bda:3", "31.12.2099","10fe070003311299", "00", ""},
|
||||
{"x,,bda:3", "-.-.-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,bda:3", "", "10fe070003321299", "00", "rw"},
|
||||
{"x,,bda,2", "", "", "", "c"},
|
||||
{"x,,hda", "26.10.2014","10fe0700041a0a070e", "00", ""}, // Sunday
|
||||
{"x,,hda", "01.01.2000","10fe07000401010600", "00", ""}, // Saturday
|
||||
{"x,,hda", "31.12.2099","10fe0700041f0c0463", "00", ""}, // Thursday
|
||||
{"x,,hda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,hda", "", "10fe070004200c0463", "00", "rw"},
|
||||
{"x,,hda:3", "26.10.2014","10fe0700031a0a0e", "00", ""},
|
||||
{"x,,hda:3", "01.01.2000","10fe070003010100", "00", ""},
|
||||
{"x,,hda:3", "31.12.2099","10fe0700031f0c63", "00", ""},
|
||||
{"x,,hda:3", "-.-.-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,hda:3", "", "10fe070003200c63", "00", "rw"},
|
||||
{"x,,hda,2", "", "", "", "c"},
|
||||
{"x,,day", "26.10.2014","10fe070002d0a3", "00", ""},
|
||||
{"x,,day", "01.01.2000","10fe070002ac8e", "00", ""},
|
||||
{"x,,day", "31.12.2078","10fe07000262ff", "00", ""},
|
||||
{"x,,day", "-.-.-", "10fe070002ffff", "00", ""},
|
||||
{"x,,day", "", "10fe0700020000", "00", "Rw"},
|
||||
{"x,,bti", "21:04:58", "10fe070003580421", "00", ""},
|
||||
{"x,,bti", "00:00:00", "10fe070003000000", "00", ""},
|
||||
{"x,,bti", "23:59:59", "10fe070003595923", "00", ""},
|
||||
{"x,,bti", "-:-:-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,bti", "", "10fe070003605923", "00", "rw"},
|
||||
{"x,,bti,2", "", "", "", "c"},
|
||||
{"x,,hti", "21:04:58", "10fe07000315043a", "00", ""},
|
||||
{"x,,hti", "-:-:-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,hti,2", "", "", "", "c"},
|
||||
{"x,,vti", "21:04:58", "10fe0700033a0415", "00", ""},
|
||||
{"x,,vti", "-:-:-", "10fe070003636363", "00", ""},
|
||||
{"x,,vti,2", "", "", "", "c"},
|
||||
{"x,,bda", "26.10.2014", "10fe07000426100614", "00", ""}, // Sunday
|
||||
{"x,,bda", "01.01.2000", "10fe07000401010500", "00", ""}, // Saturday
|
||||
{"x,,bda", "31.12.2099", "10fe07000431120399", "00", ""}, // Thursday
|
||||
{"x,,bda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,bda", "", "10fe07000432100014", "00", "rw"},
|
||||
{"x,,bda:3", "26.10.2014", "10fe070003261014", "00", ""},
|
||||
{"x,,bda:3", "01.01.2000", "10fe070003010100", "00", ""},
|
||||
{"x,,bda:3", "31.12.2099", "10fe070003311299", "00", ""},
|
||||
{"x,,bda:3", "-.-.-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,bda:3", "", "10fe070003321299", "00", "rw"},
|
||||
{"x,,bda,2", "", "", "", "c"},
|
||||
{"x,,hda", "26.10.2014", "10fe0700041a0a070e", "00", ""}, // Sunday
|
||||
{"x,,hda", "01.01.2000", "10fe07000401010600", "00", ""}, // Saturday
|
||||
{"x,,hda", "31.12.2099", "10fe0700041f0c0463", "00", ""}, // Thursday
|
||||
{"x,,hda", "-.-.-", "10fe070004ffff00ff", "00", ""},
|
||||
{"x,,hda", "", "10fe070004200c0463", "00", "rw"},
|
||||
{"x,,hda:3", "26.10.2014", "10fe0700031a0a0e", "00", ""},
|
||||
{"x,,hda:3", "01.01.2000", "10fe070003010100", "00", ""},
|
||||
{"x,,hda:3", "31.12.2099", "10fe0700031f0c63", "00", ""},
|
||||
{"x,,hda:3", "-.-.-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,hda:3", "", "10fe070003200c63", "00", "rw"},
|
||||
{"x,,hda,2", "", "", "", "c"},
|
||||
{"x,,day", "26.10.2014", "10fe070002d0a3", "00", ""},
|
||||
{"x,,day", "01.01.2000", "10fe070002ac8e", "00", ""},
|
||||
{"x,,day", "31.12.2078", "10fe07000262ff", "00", ""},
|
||||
{"x,,day", "-.-.-", "10fe070002ffff", "00", ""},
|
||||
{"x,,day", "", "10fe0700020000", "00", "Rw"},
|
||||
{"x,,bti", "21:04:58", "10fe070003580421", "00", ""},
|
||||
{"x,,bti", "00:00:00", "10fe070003000000", "00", ""},
|
||||
{"x,,bti", "23:59:59", "10fe070003595923", "00", ""},
|
||||
{"x,,bti", "-:-:-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,bti", "", "10fe070003605923", "00", "rw"},
|
||||
{"x,,bti,2", "", "", "", "c"},
|
||||
{"x,,hti", "21:04:58", "10fe07000315043a", "00", ""},
|
||||
{"x,,hti", "-:-:-", "10fe070003ffffff", "00", ""},
|
||||
{"x,,hti,2", "", "", "", "c"},
|
||||
{"x,,vti", "21:04:58", "10fe0700033a0415", "00", ""},
|
||||
{"x,,vti", "-:-:-", "10fe070003636363", "00", ""},
|
||||
{"x,,vti,2", "", "", "", "c"},
|
||||
{"x,,btm", "21:04", "10fe0700020421", "00", ""},
|
||||
{"x,,btm", "00:00", "10fe0700020000", "00", ""},
|
||||
{"x,,btm", "23:59", "10fe0700025923", "00", ""},
|
||||
@@ -191,9 +191,9 @@ int main()
|
||||
{"x,,hdy", "Mon", "10fe07000101", "00", ""},
|
||||
{"x,,hdy", "Sun", "10fe07000107", "00", ""},
|
||||
{"x,,hdy", "8", "10fe07000108", "00", "w"},
|
||||
{"x,,pin","1234", "10feffff021234", "00", ""},
|
||||
{"x,,pin","0000", "10feffff020000", "00", ""},
|
||||
{"x,,pin","9999", "10feffff029999", "00", ""},
|
||||
{"x,,pin", "1234", "10feffff021234", "00", ""},
|
||||
{"x,,pin", "0000", "10feffff020000", "00", ""},
|
||||
{"x,,pin", "9999", "10feffff029999", "00", ""},
|
||||
{"x,,pin", "", "10feffff020000", "00", "Rw"},
|
||||
{"x,,pin", "100", "10feffff020100", "00", "R"},
|
||||
{"x,,bcd", "26", "10feffff0126", "00", ""},
|
||||
@@ -202,194 +202,194 @@ int main()
|
||||
{"x,,bcd", "100", "10feffff0199", "00", "Rw"},
|
||||
{"x,,bcd", "-", "10feffff01ff", "00", ""},
|
||||
{"x,,bcd", "", "10feffff019a", "00", "rw"},
|
||||
{"x,,bcd:1","26", "10feffff0126", "00", ""},
|
||||
{"x,,bcd:1","0", "10feffff0100", "00", ""},
|
||||
{"x,,bcd:1","99", "10feffff0199", "00", ""},
|
||||
{"x,,bcd:1","100", "10feffff0199", "00", "Rw"},
|
||||
{"x,,bcd:1","-", "10feffff01ff", "00", ""},
|
||||
{"x,,bcd:1","", "10feffff019a", "00", "rw"},
|
||||
{"x,,bcd:2","126", "10feffff022601", "00", ""},
|
||||
{"x,,bcd:2","0", "10feffff020000", "00", ""},
|
||||
{"x,,bcd:2","9999", "10feffff029999", "00", ""},
|
||||
{"x,,bcd:2","10000","10feffff029999", "00", "Rw"},
|
||||
{"x,,bcd:2","-", "10feffff02ffff", "00", ""},
|
||||
{"x,,bcd:2","", "10feffff029a00", "00", "rw"},
|
||||
{"x,,bcd:3","12346", "10feffff03462301", "00", ""},
|
||||
{"x,,bcd:3","0", "10feffff03000000", "00", ""},
|
||||
{"x,,bcd:3","999999", "10feffff03999999", "00", ""},
|
||||
{"x,,bcd:3","1000000","10feffff03999999", "00", "Rw"},
|
||||
{"x,,bcd:3","-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,bcd:3","", "10feffff03009a00", "00", "rw"},
|
||||
{"x,,bcd:4","1234567", "10feffff0467452301", "00", ""},
|
||||
{"x,,bcd:4","0", "10feffff0400000000", "00", ""},
|
||||
{"x,,bcd:4","99999999", "10feffff0499999999", "00", ""},
|
||||
{"x,,bcd:4","100000000","10feffff0499999999", "00", "Rw"},
|
||||
{"x,,bcd:4","-", "10feffff04ffffffff", "00", ""},
|
||||
{"x,,bcd:4","", "10feffff0400009a00", "00", "rw"},
|
||||
{"x,,hcd:1", "26", "10feffff011a", "00", ""},
|
||||
{"x,,hcd:1", "0", "10feffff0100", "00", ""},
|
||||
{"x,,hcd:1", "99", "10feffff0163", "00", ""},
|
||||
{"x,,hcd:1", "100", "10feffff0163", "00", "Rw"},
|
||||
{"x,,hcd:1", "", "10feffff019a", "00", "rw"},
|
||||
{"x,,hcd:2", "126", "10feffff021a01", "00", ""},
|
||||
{"x,,hcd:2", "0", "10feffff020000", "00", ""},
|
||||
{"x,,hcd:2", "9999", "10feffff026363", "00", ""},
|
||||
{"x,,hcd:2", "10000", "10feffff026363", "00", "Rw"},
|
||||
{"x,,hcd:2", "", "10feffff029a00", "00", "rw"},
|
||||
{"x,,hcd:3","12346", "10feffff032e1701", "00", ""},
|
||||
{"x,,hcd:3","0", "10feffff03000000", "00", ""},
|
||||
{"x,,hcd:3","999999", "10feffff03636363", "00", ""},
|
||||
{"x,,hcd:3","1000000", "10feffff03636363", "00", "Rw"},
|
||||
{"x,,hcd:3","", "10feffff03009a00", "00", "rw"},
|
||||
{"x,,hcd:4","1234567", "10feffff04432d1701", "00", ""},
|
||||
{"x,,hcd:4","0", "10feffff0400000000", "00", ""},
|
||||
{"x,,hcd:4","99999999", "10feffff0463636363", "00", ""},
|
||||
{"x,,hcd:4","100000000","10feffff0463636363", "00", "Rw"},
|
||||
{"x,,hcd","", "10feffff0400006400", "00", "rw"},
|
||||
{"x,,hcd","1234567", "10feffff04432d1701", "00", ""},
|
||||
{"x,,hcd","0", "10feffff0400000000", "00", ""},
|
||||
{"x,,hcd","99999999", "10feffff0463636363", "00", ""},
|
||||
{"x,,hcd","100000000", "10feffff0463636363", "00", "Rw"},
|
||||
{"x,,hcd","", "10feffff0400006400", "00", "rw"},
|
||||
{"x,,str:16", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""},
|
||||
{"x,,uch:17", "", "10feffff00", "00", "c"},
|
||||
{"x,s,uch", "0", "1025ffff0310111213", "0300010203", "W"},
|
||||
{"x,s,uch", "0", "1025ffff00", "0100", ""},
|
||||
{"x,s,uch,,,,y,m,uch", "3;2","1025ffff0103", "0102", ""},
|
||||
{"x,,uch", "38", "10feffff0126", "00", ""},
|
||||
{"x,,uch", "38.5", "10feffff0126", "00", "R"},
|
||||
{"x,,uch", "0", "10feffff0100", "00", ""},
|
||||
{"x,,uch", "254", "10feffff01fe", "00", ""},
|
||||
{"x,,uch", "-", "10feffff01ff", "00", ""},
|
||||
{"x,,uch,10", "3.8", "10feffff0126", "00", ""},
|
||||
{"x,,uch,-10", "380","10feffff0126", "00", ""},
|
||||
{"x,,uch,=48", "", "10feffff01ab", "00", "W"},
|
||||
{"x,,bcd:1", "26", "10feffff0126", "00", ""},
|
||||
{"x,,bcd:1", "0", "10feffff0100", "00", ""},
|
||||
{"x,,bcd:1", "99", "10feffff0199", "00", ""},
|
||||
{"x,,bcd:1", "100", "10feffff0199", "00", "Rw"},
|
||||
{"x,,bcd:1", "-", "10feffff01ff", "00", ""},
|
||||
{"x,,bcd:1", "", "10feffff019a", "00", "rw"},
|
||||
{"x,,bcd:2", "126", "10feffff022601", "00", ""},
|
||||
{"x,,bcd:2", "0", "10feffff020000", "00", ""},
|
||||
{"x,,bcd:2", "9999", "10feffff029999", "00", ""},
|
||||
{"x,,bcd:2", "10000", "10feffff029999", "00", "Rw"},
|
||||
{"x,,bcd:2", "-", "10feffff02ffff", "00", ""},
|
||||
{"x,,bcd:2", "", "10feffff029a00", "00", "rw"},
|
||||
{"x,,bcd:3", "12346", "10feffff03462301", "00", ""},
|
||||
{"x,,bcd:3", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,bcd:3", "999999", "10feffff03999999", "00", ""},
|
||||
{"x,,bcd:3", "1000000", "10feffff03999999", "00", "Rw"},
|
||||
{"x,,bcd:3", "-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,bcd:3", "", "10feffff03009a00", "00", "rw"},
|
||||
{"x,,bcd:4", "1234567", "10feffff0467452301", "00", ""},
|
||||
{"x,,bcd:4", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,bcd:4", "99999999", "10feffff0499999999", "00", ""},
|
||||
{"x,,bcd:4", "100000000", "10feffff0499999999", "00", "Rw"},
|
||||
{"x,,bcd:4", "-", "10feffff04ffffffff", "00", ""},
|
||||
{"x,,bcd:4", "", "10feffff0400009a00", "00", "rw"},
|
||||
{"x,,hcd:1", "26", "10feffff011a", "00", ""},
|
||||
{"x,,hcd:1", "0", "10feffff0100", "00", ""},
|
||||
{"x,,hcd:1", "99", "10feffff0163", "00", ""},
|
||||
{"x,,hcd:1", "100", "10feffff0163", "00", "Rw"},
|
||||
{"x,,hcd:1", "", "10feffff019a", "00", "rw"},
|
||||
{"x,,hcd:2", "126", "10feffff021a01", "00", ""},
|
||||
{"x,,hcd:2", "0", "10feffff020000", "00", ""},
|
||||
{"x,,hcd:2", "9999", "10feffff026363", "00", ""},
|
||||
{"x,,hcd:2", "10000", "10feffff026363", "00", "Rw"},
|
||||
{"x,,hcd:2", "", "10feffff029a00", "00", "rw"},
|
||||
{"x,,hcd:3", "12346", "10feffff032e1701", "00", ""},
|
||||
{"x,,hcd:3", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,hcd:3", "999999", "10feffff03636363", "00", ""},
|
||||
{"x,,hcd:3", "1000000", "10feffff03636363", "00", "Rw"},
|
||||
{"x,,hcd:3", "", "10feffff03009a00", "00", "rw"},
|
||||
{"x,,hcd:4", "1234567", "10feffff04432d1701", "00", ""},
|
||||
{"x,,hcd:4", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,hcd:4", "99999999", "10feffff0463636363", "00", ""},
|
||||
{"x,,hcd:4", "100000000", "10feffff0463636363", "00", "Rw"},
|
||||
{"x,,hcd", "", "10feffff0400006400", "00", "rw"},
|
||||
{"x,,hcd", "1234567", "10feffff04432d1701", "00", ""},
|
||||
{"x,,hcd", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,hcd", "99999999", "10feffff0463636363", "00", ""},
|
||||
{"x,,hcd", "100000000", "10feffff0463636363", "00", "Rw"},
|
||||
{"x,,hcd", "", "10feffff0400006400", "00", "rw"},
|
||||
{"x,,str:16", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""},
|
||||
{"x,,uch:17", "", "10feffff00", "00", "c"},
|
||||
{"x,s,uch", "0", "1025ffff0310111213", "0300010203", "W"},
|
||||
{"x,s,uch", "0", "1025ffff00", "0100", ""},
|
||||
{"x,s,uch,,,,y,m,uch", "3;2", "1025ffff0103", "0102", ""},
|
||||
{"x,,uch", "38", "10feffff0126", "00", ""},
|
||||
{"x,,uch", "38.5", "10feffff0126", "00", "R"},
|
||||
{"x,,uch", "0", "10feffff0100", "00", ""},
|
||||
{"x,,uch", "254", "10feffff01fe", "00", ""},
|
||||
{"x,,uch", "-", "10feffff01ff", "00", ""},
|
||||
{"x,,uch,10", "3.8", "10feffff0126", "00", ""},
|
||||
{"x,,uch,-10", "380", "10feffff0126", "00", ""},
|
||||
{"x,,uch,=48", "", "10feffff01ab", "00", "W"},
|
||||
{"x,,uch,==48", "", "10feffff01ab", "00", "rW"},
|
||||
{"x,,uch,=48", "", "10feffff0130", "00", ""},
|
||||
{"x,,uch,=48", "", "10feffff0130", "00", ""},
|
||||
{"x,,uch,==48", "", "10feffff0130", "00", ""},
|
||||
{"x,,sch", "-90", "10feffff01a6", "00", ""},
|
||||
{"x,,sch", "0", "10feffff0100", "00", ""},
|
||||
{"x,,sch", "-1", "10feffff01ff", "00", ""},
|
||||
{"x,,sch", "-", "10feffff0180", "00", ""},
|
||||
{"x,,sch", "-127", "10feffff0181", "00", ""},
|
||||
{"x,,sch", "127", "10feffff017f", "00", ""},
|
||||
{"x,,sch,10", "-9.0","10feffff01a6", "00", ""},
|
||||
{"x,,sch,-10","-900","10feffff01a6", "00", ""},
|
||||
{"x,,d1b", "-90", "10feffff01a6", "00", ""},
|
||||
{"x,,d1b", "0", "10feffff0100", "00", ""},
|
||||
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
|
||||
{"x,,d1b", "-", "10feffff0180", "00", ""},
|
||||
{"x,,d1b", "-127", "10feffff0181", "00", ""},
|
||||
{"x,,d1b", "127", "10feffff017f", "00", ""},
|
||||
{"x,,d1b,-10","-900","10feffff01a6", "00", ""},
|
||||
{"x,,sch", "-90", "10feffff01a6", "00", ""},
|
||||
{"x,,sch", "0", "10feffff0100", "00", ""},
|
||||
{"x,,sch", "-1", "10feffff01ff", "00", ""},
|
||||
{"x,,sch", "-", "10feffff0180", "00", ""},
|
||||
{"x,,sch", "-127", "10feffff0181", "00", ""},
|
||||
{"x,,sch", "127", "10feffff017f", "00", ""},
|
||||
{"x,,sch,10", "-9.0", "10feffff01a6", "00", ""},
|
||||
{"x,,sch,-10", "-900", "10feffff01a6", "00", ""},
|
||||
{"x,,d1b", "-90", "10feffff01a6", "00", ""},
|
||||
{"x,,d1b", "0", "10feffff0100", "00", ""},
|
||||
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
|
||||
{"x,,d1b", "-", "10feffff0180", "00", ""},
|
||||
{"x,,d1b", "-127", "10feffff0181", "00", ""},
|
||||
{"x,,d1b", "127", "10feffff017f", "00", ""},
|
||||
{"x,,d1b,-10", "-900", "10feffff01a6", "00", ""},
|
||||
{"x,,d1c", "19.5", "10feffff0127", "00", ""},
|
||||
{"x,,d1c", "0.0", "10feffff0100", "00", ""},
|
||||
{"x,,d1c", "100.0", "10feffff01c8", "00", ""},
|
||||
{"x,,d1c", "-", "10feffff01ff", "00", ""},
|
||||
{"x,,uin", "38", "10feffff022600", "00", ""},
|
||||
{"x,,uin", "0", "10feffff020000", "00", ""},
|
||||
{"x,,uin", "65534", "10feffff02feff", "00", ""},
|
||||
{"x,,uin", "-", "10feffff02ffff", "00", ""},
|
||||
{"x,,uin,10", "3.8", "10feffff022600", "00", ""},
|
||||
{"x,,uin,-10","380", "10feffff022600", "00", ""},
|
||||
{"x,,uir", "38", "10feffff020026", "00", ""},
|
||||
{"x,,uir", "0", "10feffff020000", "00", ""},
|
||||
{"x,,uir", "65534", "10feffff02fffe", "00", ""},
|
||||
{"x,,uir", "-", "10feffff02ffff", "00", ""},
|
||||
{"x,,uir,10", "3.8", "10feffff020026", "00", ""},
|
||||
{"x,,uir,-10","380", "10feffff020026", "00", ""},
|
||||
{"uin10,uin,-10","", "", "", "t"}, // template
|
||||
{"x,,uin10","380", "10feffff022600", "00", ""}, // template reference
|
||||
{"x,,uin10,-10","3800","10feffff022600", "00", ""}, // template reference, valid divider product
|
||||
{"x,,uin10,10","","", "", "c"}, // template reference, invalid divider product
|
||||
{"x,,sin", "-90", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sin", "0", "10feffff020000", "00", ""},
|
||||
{"x,,sin", "-1", "10feffff02ffff", "00", ""},
|
||||
{"x,,sin", "-", "10feffff020080", "00", ""},
|
||||
{"x,,sin", "-32767", "10feffff020180", "00", ""},
|
||||
{"x,,sin", "32767", "10feffff02ff7f", "00", ""},
|
||||
{"x,,sin,10","-9.0", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sin,-10","-900","10feffff02a6ff", "00", ""},
|
||||
{"x,,sir", "-90", "10feffff02ffa6", "00", ""},
|
||||
{"x,,sir", "0", "10feffff020000", "00", ""},
|
||||
{"x,,sir", "-1", "10feffff02ffff", "00", ""},
|
||||
{"x,,sir", "-", "10feffff028000", "00", ""},
|
||||
{"x,,sir", "-32767", "10feffff028001", "00", ""},
|
||||
{"x,,sir", "32767", "10feffff027fff", "00", ""},
|
||||
{"x,,sir,10","-9.0", "10feffff02ffa6", "00", ""},
|
||||
{"x,,sir,-10","-900","10feffff02ffa6", "00", ""},
|
||||
{"x,,u3n", "38", "10feffff03260000", "00", ""},
|
||||
{"x,,u3n", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,uin", "38", "10feffff022600", "00", ""},
|
||||
{"x,,uin", "0", "10feffff020000", "00", ""},
|
||||
{"x,,uin", "65534", "10feffff02feff", "00", ""},
|
||||
{"x,,uin", "-", "10feffff02ffff", "00", ""},
|
||||
{"x,,uin,10", "3.8", "10feffff022600", "00", ""},
|
||||
{"x,,uin,-10", "380", "10feffff022600", "00", ""},
|
||||
{"x,,uir", "38", "10feffff020026", "00", ""},
|
||||
{"x,,uir", "0", "10feffff020000", "00", ""},
|
||||
{"x,,uir", "65534", "10feffff02fffe", "00", ""},
|
||||
{"x,,uir", "-", "10feffff02ffff", "00", ""},
|
||||
{"x,,uir,10", "3.8", "10feffff020026", "00", ""},
|
||||
{"x,,uir,-10", "380", "10feffff020026", "00", ""},
|
||||
{"uin10,uin,-10", "", "", "", "t"}, // template
|
||||
{"x,,uin10", "380", "10feffff022600", "00", ""}, // template reference
|
||||
{"x,,uin10,-10", "3800", "10feffff022600", "00", ""}, // template reference, valid divider product
|
||||
{"x,,uin10,10", "", "", "", "c"}, // template reference, invalid divider product
|
||||
{"x,,sin", "-90", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sin", "0", "10feffff020000", "00", ""},
|
||||
{"x,,sin", "-1", "10feffff02ffff", "00", ""},
|
||||
{"x,,sin", "-", "10feffff020080", "00", ""},
|
||||
{"x,,sin", "-32767", "10feffff020180", "00", ""},
|
||||
{"x,,sin", "32767", "10feffff02ff7f", "00", ""},
|
||||
{"x,,sin,10", "-9.0", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sin,-10", "-900", "10feffff02a6ff", "00", ""},
|
||||
{"x,,sir", "-90", "10feffff02ffa6", "00", ""},
|
||||
{"x,,sir", "0", "10feffff020000", "00", ""},
|
||||
{"x,,sir", "-1", "10feffff02ffff", "00", ""},
|
||||
{"x,,sir", "-", "10feffff028000", "00", ""},
|
||||
{"x,,sir", "-32767", "10feffff028001", "00", ""},
|
||||
{"x,,sir", "32767", "10feffff027fff", "00", ""},
|
||||
{"x,,sir,10", "-9.0", "10feffff02ffa6", "00", ""},
|
||||
{"x,,sir,-10", "-900", "10feffff02ffa6", "00", ""},
|
||||
{"x,,u3n", "38", "10feffff03260000", "00", ""},
|
||||
{"x,,u3n", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,u3n", "16777214", "10feffff03feffff", "00", ""},
|
||||
{"x,,u3n", "-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,u3n,10", "3.8", "10feffff03260000", "00", ""},
|
||||
{"x,,u3n,-10","380", "10feffff03260000", "00", ""},
|
||||
{"x,,u3r", "38", "10feffff03000026", "00", ""},
|
||||
{"x,,u3r", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,u3n", "-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,u3n,10", "3.8", "10feffff03260000", "00", ""},
|
||||
{"x,,u3n,-10", "380", "10feffff03260000", "00", ""},
|
||||
{"x,,u3r", "38", "10feffff03000026", "00", ""},
|
||||
{"x,,u3r", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,u3r", "16777214", "10feffff03fffffe", "00", ""},
|
||||
{"x,,u3r", "-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,u3r,10", "3.8", "10feffff03000026", "00", ""},
|
||||
{"x,,u3r,-10","380", "10feffff03000026", "00", ""},
|
||||
{"x,,s3n", "-90", "10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3n", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,s3n", "-1", "10feffff03ffffff", "00", ""},
|
||||
{"x,,s3n", "-", "10feffff03000080", "00", ""},
|
||||
{"x,,u3r", "-", "10feffff03ffffff", "00", ""},
|
||||
{"x,,u3r,10", "3.8", "10feffff03000026", "00", ""},
|
||||
{"x,,u3r,-10", "380", "10feffff03000026", "00", ""},
|
||||
{"x,,s3n", "-90", "10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3n", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,s3n", "-1", "10feffff03ffffff", "00", ""},
|
||||
{"x,,s3n", "-", "10feffff03000080", "00", ""},
|
||||
{"x,,s3n", "-8388607", "10feffff03010080", "00", ""},
|
||||
{"x,,s3n", "8388607", "10feffff03ffff7f", "00", ""},
|
||||
{"x,,s3n,10","-9.0", "10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3n,-10","-900","10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3r", "-90", "10feffff03ffffa6", "00", ""},
|
||||
{"x,,s3r", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,s3r", "-1", "10feffff03ffffff", "00", ""},
|
||||
{"x,,s3r", "-", "10feffff03800000", "00", ""},
|
||||
{"x,,s3n,10", "-9.0", "10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3n,-10", "-900", "10feffff03a6ffff", "00", ""},
|
||||
{"x,,s3r", "-90", "10feffff03ffffa6", "00", ""},
|
||||
{"x,,s3r", "0", "10feffff03000000", "00", ""},
|
||||
{"x,,s3r", "-1", "10feffff03ffffff", "00", ""},
|
||||
{"x,,s3r", "-", "10feffff03800000", "00", ""},
|
||||
{"x,,s3r", "-8388607", "10feffff03800001", "00", ""},
|
||||
{"x,,s3r", "8388607", "10feffff037fffff", "00", ""},
|
||||
{"x,,s3r,10","-9.0", "10feffff03ffffa6", "00", ""},
|
||||
{"x,,s3r,-10","-900","10feffff03ffffa6", "00", ""},
|
||||
{"x,,s3r,10", "-9.0", "10feffff03ffffa6", "00", ""},
|
||||
{"x,,s3r,-10", "-900", "10feffff03ffffa6", "00", ""},
|
||||
{"x,,flt", "-0.090", "10feffff02a6ff", "00", ""},
|
||||
{"x,,flt", "0.000", "10feffff020000", "00", ""},
|
||||
{"x,,flt", "-0.001", "10feffff02ffff", "00", ""},
|
||||
{"x,,flt", "-", "10feffff020080", "00", ""},
|
||||
{"x,,flt","-32.767", "10feffff020180", "00", ""},
|
||||
{"x,,flt", "-32.767", "10feffff020180", "00", ""},
|
||||
{"x,,flt", "32.767", "10feffff02ff7f", "00", ""},
|
||||
{"x,,flr", "-0.090", "10feffff02ffa6", "00", ""},
|
||||
{"x,,flr", "0.000", "10feffff020000", "00", ""},
|
||||
{"x,,flr", "-0.001", "10feffff02ffff", "00", ""},
|
||||
{"x,,flr", "-", "10feffff028000", "00", ""},
|
||||
{"x,,flr","-32.767", "10feffff028001", "00", ""},
|
||||
{"x,,flr", "-32.767", "10feffff028001", "00", ""},
|
||||
{"x,,flr", "32.767", "10feffff027fff", "00", ""},
|
||||
{"x,,exp", "-0.09", "10feffff04ec51b8bd", "00", ""},
|
||||
{"x,,exp", "0.0", "10feffff0400000000", "00", ""},
|
||||
{"x,,exp", "-0.001", "10feffff046f1283ba", "00", ""},
|
||||
{"x,,exp", "-", "10feffff040000807f", "00", ""},
|
||||
{"x,,exp","-32.767", "10feffff04681103c2", "00", ""},
|
||||
{"x,,exp", "-32.767", "10feffff04681103c2", "00", ""},
|
||||
{"x,,exp,1000", "-0.000090000", "10feffff04ec51b8bd", "00", ""},
|
||||
{"x,,exp,-100", "-9", "10feffff04ec51b8bd", "00", ""},
|
||||
{"x,,exr", "-0.09", "10feffff04bdb851ec", "00", ""},
|
||||
{"x,,exr", "0.0", "10feffff0400000000", "00", ""},
|
||||
{"x,,exr", "-0.001", "10feffff04ba83126f", "00", ""},
|
||||
{"x,,exr", "-", "10feffff047f800000", "00", ""},
|
||||
{"x,,exr","-32.767", "10feffff04c2031168", "00", ""},
|
||||
{"x,,exr,1000", "-0.000090000", "10feffff04bdb851ec", "00", ""},
|
||||
{"x,,exr", "-32.767", "10feffff04c2031168", "00", ""},
|
||||
{"x,,exr,1000", "-0.000090000", "10feffff04bdb851ec", "00", ""},
|
||||
{"x,,exr,-100", "-9", "10feffff04bdb851ec", "00", ""},
|
||||
{"x,,d2b", "18.004", "10fe0700090112", "00", ""},
|
||||
{"x,,d2b", "0.000", "10feffff020000", "00", ""},
|
||||
{"x,,d2b", "-0.004", "10feffff02ffff", "00", ""},
|
||||
{"x,,d2b", "-", "10feffff020080", "00", ""},
|
||||
{"x,,d2b","-127.996","10feffff020180", "00", ""},
|
||||
{"x,,d2b", "127.996","10feffff02ff7f", "00", ""},
|
||||
{"x,,d2c", "288.06", "10fe0700090112", "00", ""},
|
||||
{"x,,d2c", "0.00", "10feffff020000", "00", ""},
|
||||
{"x,,d2c", "-0.06", "10feffff02ffff", "00", ""},
|
||||
{"x,,d2c", "-", "10feffff020080", "00", ""},
|
||||
{"x,,d2c","-2047.94","10feffff020180", "00", ""},
|
||||
{"x,,d2c", "2047.94","10feffff02ff7f", "00", ""},
|
||||
{"x,,d2b", "18.004", "10fe0700090112", "00", ""},
|
||||
{"x,,d2b", "0.000", "10feffff020000", "00", ""},
|
||||
{"x,,d2b", "-0.004", "10feffff02ffff", "00", ""},
|
||||
{"x,,d2b", "-", "10feffff020080", "00", ""},
|
||||
{"x,,d2b", "-127.996", "10feffff020180", "00", ""},
|
||||
{"x,,d2b", "127.996", "10feffff02ff7f", "00", ""},
|
||||
{"x,,d2c", "288.06", "10fe0700090112", "00", ""},
|
||||
{"x,,d2c", "0.00", "10feffff020000", "00", ""},
|
||||
{"x,,d2c", "-0.06", "10feffff02ffff", "00", ""},
|
||||
{"x,,d2c", "-", "10feffff020080", "00", ""},
|
||||
{"x,,d2c", "-2047.94", "10feffff020180", "00", ""},
|
||||
{"x,,d2c", "2047.94", "10feffff02ff7f", "00", ""},
|
||||
{"x,,ulg", "38", "10feffff0426000000", "00", ""},
|
||||
{"x,,ulg", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,ulg", "4294967294", "10feffff04feffffff", "00", ""},
|
||||
{"x,,ulg", "-", "10feffff04ffffffff", "00", ""},
|
||||
{"x,,ulg,10","3.8", "10feffff0426000000", "00", ""},
|
||||
{"x,,ulg,-10","380", "10feffff0426000000", "00", ""},
|
||||
{"x,,ulg,10", "3.8", "10feffff0426000000", "00", ""},
|
||||
{"x,,ulg,-10", "380", "10feffff0426000000", "00", ""},
|
||||
{"x,,ulg,0x0FF0F00F = VRT 350 ;0x33CCCC33=VRT 360;0x3CC3C33C=SD 17;0x66999966=SD 37;0x69969669=VRT 360+",
|
||||
"VRT 350", "10feffff040FF0F00F", "00", ""},
|
||||
{"x,,ulg,0x=test", "", "10feffff040FF0F00F", "00", "c"},
|
||||
@@ -397,8 +397,8 @@ int main()
|
||||
{"x,,ulr", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,ulr", "4294967294", "10feffff04fffffffe", "00", ""},
|
||||
{"x,,ulr", "-", "10feffff04ffffffff", "00", ""},
|
||||
{"x,,ulr,10","3.8", "10feffff0400000026", "00", ""},
|
||||
{"x,,ulr,-10","380", "10feffff0400000026", "00", ""},
|
||||
{"x,,ulr,10", "3.8", "10feffff0400000026", "00", ""},
|
||||
{"x,,ulr,-10", "380", "10feffff0400000026", "00", ""},
|
||||
{"x,,slg", "-90", "10feffff04a6ffffff", "00", ""},
|
||||
{"x,,slg", "0", "10feffff0400000000", "00", ""},
|
||||
{"x,,slg", "-1", "10feffff04ffffffff", "00", ""},
|
||||
@@ -409,53 +409,53 @@ int main()
|
||||
{"x,,slr", "-1", "10feffff04ffffffff", "00", ""},
|
||||
{"x,,slr,10", "-9.0", "10feffff04ffffffa6", "00", ""},
|
||||
{"x,,slr,-10", "-900", "10feffff04ffffffa6", "00", ""},
|
||||
{"x,,bi3", "1", "10feffff0108", "00", ""},
|
||||
{"x,,bi3", "0", "10feffff0100", "00", ""},
|
||||
{"x,,bi3,0=off;1=on","on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3,0=off;1=on","off","10feffff0100", "00", ""},
|
||||
{"x,,bi3", "1", "10feffff0108", "00", ""},
|
||||
{"x,,bi3", "0", "10feffff0100", "00", ""},
|
||||
{"x,,bi3,0=off;1=on", "on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3,0=off;1=on", "off", "10feffff0100", "00", ""},
|
||||
{"x,,bi3:2", "1", "10feffff0108", "00", ""},
|
||||
{"x,,bi3:2", "1", "10feffff01ef", "00", "W"},
|
||||
{"x,,bi3:2", "0", "10feffff0100", "00", ""},
|
||||
{"x,,bi3:2", "3", "10feffff0118", "00", ""},
|
||||
{"x,,bi3:2,1=on","on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3:2,1=on","-", "10feffff0100", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on;2=auto;3=eco","auto", "10feffff0110", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on;2=auto;3=eco","2.5", "10feffff0110", "00", "R"},
|
||||
{"x,,bi3:2,0=off;1=on","on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on","off","10feffff0100", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on","1", "10feffff0108", "00", "n"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvv"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvvn"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "j"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1}", "10feffff0108", "00", "vnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00", "nj"},
|
||||
{"x,,uch,1=test;2=high;3=off;0x10=on","on","10feffff0110", "00", ""},
|
||||
{"x,s,uch","3","1050ffff00", "0103", ""},
|
||||
{"x,,d2b,,°C,Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "vvv"},
|
||||
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610061406", "00", ""}, // combination
|
||||
{"x,,bi3:2,1=on", "on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3:2,1=on", "-", "10feffff0100", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on;2=auto;3=eco", "auto", "10feffff0110", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on;2=auto;3=eco", "2.5", "10feffff0110", "00", "R"},
|
||||
{"x,,bi3:2,0=off;1=on", "on", "10feffff0108", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on", "off", "10feffff0100", "00", ""},
|
||||
{"x,,bi3:2,0=off;1=on", "1", "10feffff0108", "00", "n"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvv"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvvn"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "vj"},
|
||||
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "j"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1}", "10feffff0108", "00", "vnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvnj"},
|
||||
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00", "nj"},
|
||||
{"x,,uch,1=test;2=high;3=off;0x10=on", "on", "10feffff0110", "00", ""},
|
||||
{"x,s,uch", "3", "1050ffff00", "0103", ""},
|
||||
{"x,,d2b,,°C,Aussentemperatur", "x=18.004 °C [Aussentemperatur]", "10fe0700090112", "00", "vvv"},
|
||||
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun", "10fe0700085804212610061406", "00", ""}, // combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;1", "10feffff0120", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi5", "0;0", "10feffff0100", "00", ""}, // bit combination
|
||||
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9","10feffff020009", "00", ""}, // bit combination
|
||||
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9","10feffff03800109", "00", ""}, // bit combination
|
||||
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0","ff75b50900", "0104", ""}, // bits
|
||||
{"temp,d2b,,°C,Aussentemperatur","","", "", "t"}, // template with relative pos
|
||||
{"x,,temp","18.004","10fe0700020112", "00", ""}, // reference to template
|
||||
{"x,,temp,10","1.8004","10fe0700020112", "00", ""}, // reference to template, valid divider product
|
||||
{"x,,temp,-10","","", "", "c"}, // reference to template, invalid divider product
|
||||
{"relrel,d2b,,,,y,d1c","","", "", "t"}, // template struct with relative pos
|
||||
{"x,,relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct
|
||||
{"trelrel,temp;temp","","", "", "t"}, // template struct with relative pos and ref to templates
|
||||
{"x,,trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct
|
||||
{"x,,temp,,,,y,,d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def
|
||||
{"x,,temp;HEX:2","18.004;13 14","10fe07000401121314", "00", ""}, // reference to template and base type
|
||||
{"x,,temp;HEX:2","temp=18.004;=13 14","10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
{"x,,temp:degrees;HEX:2","degrees=18.004;=13 14","10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
{"x,,bi3,,,,y,,bi7,,,,t,,uch", "0;0;9", "10feffff020009", "00", ""}, // bit combination
|
||||
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9", "10feffff03800109", "00", ""}, // bit combination
|
||||
{"x,,BI0;BI1;BI2;BI3;BI4;BI5;BI6;BI7", "0;0;1;0;0;0;0;0", "ff75b50900", "0104", ""}, // bits
|
||||
{"temp,d2b,,°C,Aussentemperatur", "", "", "", "t"}, // template with relative pos
|
||||
{"x,,temp", "18.004", "10fe0700020112", "00", ""}, // reference to template
|
||||
{"x,,temp,10", "1.8004", "10fe0700020112", "00", ""}, // reference to template, valid divider product
|
||||
{"x,,temp,-10", "", "", "", "c"}, // reference to template, invalid divider product
|
||||
{"relrel,d2b,,,,y,d1c", "", "", "", "t"}, // template struct with relative pos
|
||||
{"x,,relrel", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template struct
|
||||
{"trelrel,temp;temp", "", "", "", "t"}, // template struct with relative pos and ref to templates
|
||||
{"x,,trelrel", "18.004;19.008", "10fe07000401120213", "00", ""}, // reference to template struct
|
||||
{"x,,temp,,,,y,,d1c", "18.004;9.5", "10fe070003011213", "00", ""}, // reference to template, normal def
|
||||
{"x,,temp;HEX:2", "18.004;13 14", "10fe07000401121314", "00", ""}, // reference to template and base type
|
||||
{"x,,temp;HEX:2", "temp=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
{"x,,temp:degrees;HEX:2", "degrees=18.004;=13 14", "10fe07000401121314", "00", "v"}, // reference to template and base type
|
||||
};
|
||||
DataFieldTemplates* templates = new DataFieldTemplates();
|
||||
DataField* fields = NULL;
|
||||
@@ -510,7 +510,7 @@ int main()
|
||||
fields = NULL;
|
||||
}
|
||||
vector<string>::iterator it = entries.begin();
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1]==BROADCAST || isMaster(mstr[1])));
|
||||
result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate, !isTemplate && (mstr[1] == BROADCAST || isMaster(mstr[1])));
|
||||
if (failedCreate) {
|
||||
if (result == RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
|
||||
@@ -568,7 +568,7 @@ int main()
|
||||
if (result >= RESULT_OK) {
|
||||
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) {
|
||||
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< error: unexpectedly succeeded" << endl;
|
||||
@@ -577,21 +577,21 @@ int main()
|
||||
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< OK" << endl;
|
||||
}
|
||||
else if (result < RESULT_OK) {
|
||||
} else if (result < RESULT_OK) {
|
||||
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3]
|
||||
<< "< error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0;
|
||||
verify(failedReadMatch, "read", check[2], match, expectStr, output.str());
|
||||
}
|
||||
|
||||
if (verbosity==0) {
|
||||
if (verbosity == 0) {
|
||||
istringstream input(expectStr);
|
||||
result = fields->write(input, pt_masterData, writeMstr, 0);
|
||||
if (result >= RESULT_OK)
|
||||
if (result >= RESULT_OK) {
|
||||
result = fields->write(input, pt_slaveData, writeSstr, 0);
|
||||
}
|
||||
if (failedWrite) {
|
||||
if (result >= RESULT_OK) {
|
||||
cout << " failed write " << fields->getName() << " >"
|
||||
@@ -601,8 +601,7 @@ int main()
|
||||
cout << " failed write " << fields->getName() << " >"
|
||||
<< expectStr << "< OK" << endl;
|
||||
}
|
||||
}
|
||||
else if (result < RESULT_OK) {
|
||||
} else if (result < RESULT_OK) {
|
||||
cout << " write " << fields->getName() << " >" << expectStr
|
||||
<< "< error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "device.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main ()
|
||||
{
|
||||
int main() {
|
||||
Device* device = Device::create("/dev/ttyUSB20", true, false, false);
|
||||
if (device == NULL) {
|
||||
cout << "unable to create device" << endl;
|
||||
@@ -33,26 +32,27 @@ int main ()
|
||||
if (result != RESULT_OK) {
|
||||
cout << "open failed: " << getResultCode(result) << endl;
|
||||
} else {
|
||||
if (!device->isValid())
|
||||
if (!device->isValid()) {
|
||||
cout << "device not available." << endl;
|
||||
|
||||
}
|
||||
int count = 0;
|
||||
|
||||
while (1) {
|
||||
unsigned char byte = 0;
|
||||
result = device->recv(0, byte);
|
||||
|
||||
if (result == RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
cout << hex << setw(2) << setfill('0')
|
||||
<< static_cast<unsigned>(byte) << endl;
|
||||
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
device->close();
|
||||
|
||||
if (!device->isValid())
|
||||
if (!device->isValid()) {
|
||||
cout << "close successful." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
delete device;
|
||||
|
||||
@@ -16,17 +16,18 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "filereader.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "filereader.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool error = false;
|
||||
|
||||
void verify(bool expectFailMatch, string type, string input,
|
||||
bool match, string expectStr, string gotStr)
|
||||
{
|
||||
bool match, string expectStr, string gotStr) {
|
||||
match = match && expectStr == gotStr;
|
||||
if (expectFailMatch) {
|
||||
if (match) {
|
||||
@@ -45,8 +46,7 @@ void verify(bool expectFailMatch, string type, string input,
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
istringstream ifs(
|
||||
"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"
|
||||
|
||||
@@ -16,41 +16,43 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "message.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "message.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void verify(bool expectFailMatch, string type, string input,
|
||||
bool match, string expectStr, string gotStr)
|
||||
{
|
||||
bool match, string expectStr, string gotStr) {
|
||||
if (expectFailMatch) {
|
||||
if (match)
|
||||
if (match) {
|
||||
cout << " failed " << type << " match >" << input
|
||||
<< "< error: unexpectedly succeeded" << endl;
|
||||
else
|
||||
} else {
|
||||
cout << " failed " << type << " match >" << input << "< OK" << endl;
|
||||
}
|
||||
else if (match)
|
||||
}
|
||||
} else if (match) {
|
||||
cout << " " << type << " match >" << input << "< OK" << endl;
|
||||
else
|
||||
} else {
|
||||
cout << " " << type << " match >" << input << "< error: got >"
|
||||
<< gotStr << "<, expected >" << expectStr << "<" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
DataFieldTemplates* templates = NULL;
|
||||
|
||||
DataFieldTemplates* getTemplates(const string filename)
|
||||
{
|
||||
if (filename=="") // avoid compiler warning
|
||||
DataFieldTemplates* getTemplates(const string filename) {
|
||||
if (filename == "") { // avoid compiler warning
|
||||
return templates;
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
// message: [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields...
|
||||
// field: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
|
||||
// template: name,type[:len][,[divisor|values][,[unit][,[comment]]]]
|
||||
@@ -69,7 +71,7 @@ int main()
|
||||
{"pumpstate,UCH,0=off;1=on;2=overrun,,Pumpenstatus", "", "", "", "template"},
|
||||
{"tempsensor,temp;sensor,,Temperatursensor", "", "", "", "template"},
|
||||
{"tempsensorc,temp;sensorc,,Temperatursensor", "", "", "", "template"},
|
||||
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate","28.0;24.0;4.938;35.0;41.0;4","ff08b5110101","093830f00446520400ff","d"},
|
||||
{"r,,Status01,VL/RL/AussenTemp/VLWW/SpeicherTemp/Status,,08,B511,01,,,temp1;temp1;temp2;temp1;temp1;pumpstate", "28.0;24.0;4.938;35.0;41.0;4", "ff08b5110101", "093830f00446520400ff", "d"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor", "temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"},
|
||||
{"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "\n \"temp\": {\"value\": -14.00},\n \"sensor\": {\"value\": \"ok\"}", "ff25b509030d2800", "0320ff00", "mj"},
|
||||
@@ -97,8 +99,8 @@ int main()
|
||||
{"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f", "mD"},
|
||||
{"u,ehp,ActualEnvironmentPower,Energiebezug,,08,B509,29BA00,,s,IGN:2,,,,,s,power", "8", "1008b5090329ba00", "03ba0008", "pm"},
|
||||
{"uw,ehp,test,Test,,08,B5de,ab,,,power,,,,,s,hex:1", "8;39", "1008b5de02ab08", "0139", "pm"},
|
||||
{"u,ehp,hwTankTemp,Speichertemperatur IST,,25,B509,290000,,,IGN:2,,,,,,tempsensor", "","","","M"},
|
||||
{"", "55.50;ok","1025b50903290000","050000780300","d"},
|
||||
{"u,ehp,hwTankTemp,Speichertemperatur IST,,25,B509,290000,,,IGN:2,,,,,,tempsensor", "", "", "", "M"},
|
||||
{"", "55.50;ok", "1025b50903290000", "050000780300", "d"},
|
||||
{"r,ehp,datetime,Datum Uhrzeit,,50,B504,00,,,dcfstate,,,,time,,BTI,,,,date,,BDA,,,,temp,,temp2", "valid;08:24:51;31.12.2014;-0.875", "1050b5040100", "0a035124083112031420ff", "md" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,000102,,m,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
|
||||
{"r,ehp,bad,invalid pos,,50,B5ff,,,s,HEX:8;tempsensor;tempsensor;tempsensor;tempsensor;tempsensor;power;power,,,", "", "", "", "c" },
|
||||
@@ -167,17 +169,16 @@ int main()
|
||||
DataField* fields = NULL;
|
||||
vector<string>::iterator it = entries.begin();
|
||||
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;
|
||||
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;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": create template OK" << endl;
|
||||
result = templates->add(fields, "", true);
|
||||
if (result == RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
cout << " store template OK" << endl;
|
||||
else {
|
||||
} else {
|
||||
cout << " store template error: " << getResultCode(result) << endl;
|
||||
delete fields;
|
||||
}
|
||||
@@ -189,21 +190,22 @@ int main()
|
||||
vector<string>::iterator it = entries.begin();
|
||||
size_t oldSize = conditions.size();
|
||||
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;
|
||||
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;
|
||||
else {
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": read defaults OK" << endl;
|
||||
if (isCondition) {
|
||||
if (conditions.size()==oldSize) {
|
||||
if (conditions.size() == oldSize) {
|
||||
cout << " create condition error" << endl;
|
||||
} else {
|
||||
result = messages->resolveConditions();
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
cout << " resolve conditions error: " << getResultCode(result) << " " << messages->getLastError() << endl;
|
||||
else
|
||||
} else {
|
||||
cout << " resolve conditions OK" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,10 +216,11 @@ int main()
|
||||
string token;
|
||||
istringstream stream(check[2]);
|
||||
while (getline(stream, token, VALUE_SEPARATOR)) {
|
||||
if (pos >= mstrs.size())
|
||||
if (pos >= mstrs.size()) {
|
||||
mstrs.resize(pos+1);
|
||||
else if (mstrs[pos]!=NULL)
|
||||
} else if (mstrs[pos] != NULL) {
|
||||
delete mstrs[pos];
|
||||
}
|
||||
mstrs[pos] = new SymbolString(false);
|
||||
result = mstrs[pos]->parseHex(token);
|
||||
if (result != RESULT_OK) {
|
||||
@@ -230,10 +233,11 @@ int main()
|
||||
stream.str(check[3]);
|
||||
stream.clear();
|
||||
while (getline(stream, token, VALUE_SEPARATOR)) {
|
||||
if (pos >= sstrs.size())
|
||||
if (pos >= sstrs.size()) {
|
||||
sstrs.resize(pos+1);
|
||||
else if (sstrs[pos]!=NULL)
|
||||
} else if (sstrs[pos] != NULL) {
|
||||
delete sstrs[pos];
|
||||
}
|
||||
sstrs[pos] = new SymbolString(false);
|
||||
result = sstrs[pos]->parseHex(token);
|
||||
if (result != RESULT_OK) {
|
||||
@@ -242,19 +246,22 @@ int main()
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (mstrs[0]!=NULL)
|
||||
if (mstrs[0] != NULL) {
|
||||
delete mstrs[0];
|
||||
}
|
||||
mstrs[0] = new SymbolString(false);
|
||||
result = mstrs[0]->parseHex(check[2]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
|
||||
continue;
|
||||
}
|
||||
if (sstrs[0]!=NULL)
|
||||
if (sstrs[0] != NULL) {
|
||||
delete sstrs[0];
|
||||
}
|
||||
sstrs[0] = new SymbolString(false);
|
||||
result = sstrs[0]->parseHex(check[3]);
|
||||
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++) {
|
||||
Message* deleteMessage = *it;
|
||||
delete deleteMessage;
|
||||
@@ -282,15 +289,16 @@ int main()
|
||||
string types = *it;
|
||||
Condition* condition = NULL;
|
||||
result = messages->readConditions(types, "no file", condition);
|
||||
if (result==RESULT_OK) {
|
||||
if (result == RESULT_OK) {
|
||||
*it = types;
|
||||
result = Message::create(it, entries.end(), &defaultsRows, condition, "no file", templates, deleteMessages);
|
||||
}
|
||||
if (failedCreate) {
|
||||
if (result == RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
|
||||
else
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": failed create OK" << endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (result != RESULT_OK) {
|
||||
@@ -299,7 +307,7 @@ int main()
|
||||
printErrorPos(cout, entries.begin(), entries.end(), it, "", 0, result);
|
||||
continue;
|
||||
}
|
||||
if (deleteMessages.size()==0) {
|
||||
if (deleteMessages.size() == 0) {
|
||||
cout << "\"" << check[0] << "\": create error: NULL" << endl;
|
||||
continue;
|
||||
}
|
||||
@@ -307,11 +315,11 @@ int main()
|
||||
cout << "\"" << check[0] << "\": create error: trailing input " << static_cast<unsigned>(entries.end()-it) << endl;
|
||||
continue;
|
||||
}
|
||||
if (multi && deleteMessages.size()==1) {
|
||||
if (multi && deleteMessages.size() == 1) {
|
||||
cout << "\"" << check[0] << "\": create error: single message instead of multiple" << endl;
|
||||
continue;
|
||||
}
|
||||
if (!multi && deleteMessages.size()>1) {
|
||||
if (!multi && deleteMessages.size() > 1) {
|
||||
cout << "\"" << check[0] << "\": create error: multiple messages instead of single" << endl;
|
||||
continue;
|
||||
}
|
||||
@@ -327,28 +335,31 @@ int main()
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
continue;
|
||||
}
|
||||
cout << " map OK" << endl;
|
||||
message = deleteMessages.front();
|
||||
deleteMessages.clear();
|
||||
if (onlyMap)
|
||||
if (onlyMap) {
|
||||
continue;
|
||||
}
|
||||
Message* foundMessage = messages->find(*mstrs[0]);
|
||||
if (foundMessage == message)
|
||||
if (foundMessage == message) {
|
||||
cout << " find OK" << endl;
|
||||
else if (foundMessage == NULL)
|
||||
} else if (foundMessage == NULL) {
|
||||
cout << " find error: NULL" << endl;
|
||||
else
|
||||
} else {
|
||||
cout << " find error: different" << endl;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
message = deleteMessages.front();
|
||||
}
|
||||
}
|
||||
|
||||
if (message->isPassive() || decode) {
|
||||
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]);
|
||||
}
|
||||
if (withMessageDump && !decodeJson) {
|
||||
@@ -370,10 +381,11 @@ int main()
|
||||
SymbolString writeMstr(false);
|
||||
result = message->prepareMaster(0xff, writeMstr, input);
|
||||
if (failedPrepare) {
|
||||
if (result == RESULT_OK)
|
||||
if (result == RESULT_OK) {
|
||||
cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl;
|
||||
else
|
||||
} else {
|
||||
cout << " \"" << inputStr << "\": failed prepare OK" << endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -384,12 +396,12 @@ int main()
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteMessages.size()>0) {
|
||||
if (deleteMessages.size() > 0) {
|
||||
for (vector<Message*>::iterator it = deleteMessages.begin(); it != deleteMessages.end(); it++) {
|
||||
Message* deleteMessage = *it;
|
||||
delete deleteMessage;
|
||||
@@ -399,12 +411,11 @@ int main()
|
||||
|
||||
delete templates;
|
||||
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;
|
||||
}
|
||||
for (vector<SymbolString*>::iterator it = sstrs.begin(); it!=sstrs.end(); it++) {
|
||||
for (vector<SymbolString*>::iterator it = sstrs.begin(); it != sstrs.end(); it++) {
|
||||
delete *it;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "symbol.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include "symbol.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool error = false;
|
||||
|
||||
void verify(bool expectFailMatch, string type, string input,
|
||||
bool match, string expectStr, string gotStr)
|
||||
{
|
||||
bool match, string expectStr, string gotStr) {
|
||||
match = match && expectStr == gotStr;
|
||||
if (expectFailMatch) {
|
||||
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);
|
||||
|
||||
if (argc>1) {
|
||||
if (argc > 1) {
|
||||
result_t result = sstr.parseHex(argv[1], true);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "parse escaped error: " << getResultCode(result) << endl;
|
||||
@@ -76,7 +75,7 @@ int main(int argc, char** argv)
|
||||
ostr.str("");
|
||||
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc);
|
||||
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";
|
||||
verify(false, "unescape", "10feb5050427a915aa", true, expectStr, gotStr);
|
||||
|
||||
@@ -27,8 +27,7 @@ static bool clockInitialized = false;
|
||||
static clock_serv_t clockServ;
|
||||
#endif
|
||||
|
||||
void clockGettime(struct timespec* t)
|
||||
{
|
||||
void clockGettime(struct timespec* t) {
|
||||
#ifdef __MACH__
|
||||
if (!clockInitialized) {
|
||||
clockInitialized = true;
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_CLOCK_H_
|
||||
#define LIBUTILS_CLOCK_H_
|
||||
#ifndef LIB_UTILS_CLOCK_H_
|
||||
#define LIB_UTILS_CLOCK_H_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
*/
|
||||
void clockGettime(struct timespec* t);
|
||||
|
||||
#endif // LIBUTILS_CLOCK_H_
|
||||
#endif // LIB_UTILS_CLOCK_H_
|
||||
|
||||
+14
-24
@@ -57,8 +57,7 @@ static LogLevel s_logLevel = ll_notice;
|
||||
/** the current log FILE. */
|
||||
static FILE* s_logFile = stdout;
|
||||
|
||||
bool setLogFacilities(const char* facilities)
|
||||
{
|
||||
bool setLogFacilities(const char* facilities) {
|
||||
char *input = strdup(facilities);
|
||||
char *opt = (char*)input, *value = NULL;
|
||||
int newFacilites = 0;
|
||||
@@ -80,14 +79,13 @@ bool setLogFacilities(const char* facilities)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getLogFacilities(char* buffer)
|
||||
{
|
||||
if (s_logFacilites==LF_ALL) {
|
||||
bool getLogFacilities(char* buffer) {
|
||||
if (s_logFacilites == LF_ALL) {
|
||||
return strcpy(buffer, facilityNames[lf_COUNT]) != NULL;
|
||||
}
|
||||
*buffer = 0; // for strcat to work
|
||||
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 (found) {
|
||||
strcat(buffer, ",");
|
||||
@@ -99,8 +97,7 @@ bool getLogFacilities(char* buffer)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setLogLevel(const char* level)
|
||||
{
|
||||
bool setLogLevel(const char* level) {
|
||||
char *input = strdup(level);
|
||||
char *opt = (char*)input, *value = NULL;
|
||||
int newLevel = 0;
|
||||
@@ -117,24 +114,21 @@ bool setLogLevel(const char* level)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* getLogLevel()
|
||||
{
|
||||
const char* getLogLevel() {
|
||||
return levelNames[s_logLevel];
|
||||
}
|
||||
|
||||
bool setLogFile(const char* filename)
|
||||
{
|
||||
bool setLogFile(const char* filename) {
|
||||
FILE* newFile = fopen(filename, "a");
|
||||
if (newFile == NULL)
|
||||
if (newFile == NULL) {
|
||||
return false;
|
||||
|
||||
}
|
||||
closeLogFile();
|
||||
s_logFile = newFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
void closeLogFile()
|
||||
{
|
||||
void closeLogFile() {
|
||||
if (s_logFile != NULL) {
|
||||
if (s_logFile != stdout) {
|
||||
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)
|
||||
&& (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 tm* tm;
|
||||
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_start(ap, message);
|
||||
logWrite(facilityNames[facility], levelNames[level], message, 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_start(ap, message);
|
||||
logWrite(facility, levelNames[level], message, ap);
|
||||
|
||||
+15
-15
@@ -16,19 +16,19 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_LOG_H_
|
||||
#define LIBUTILS_LOG_H_
|
||||
#ifndef LIB_UTILS_LOG_H_
|
||||
#define LIB_UTILS_LOG_H_
|
||||
|
||||
/** \file log.h */
|
||||
|
||||
/** the available log facilities. */
|
||||
enum LogFacility {
|
||||
lf_main=0, //!< main loop
|
||||
lf_network, //!< network related
|
||||
lf_bus, //!< eBUS related
|
||||
lf_update, //!< updates found while listening to the bus
|
||||
lf_other, //!< all other log facilities
|
||||
lf_COUNT=5 //!< number of available log facilities
|
||||
lf_main = 0, //!< main loop
|
||||
lf_network, //!< network related
|
||||
lf_bus, //!< eBUS related
|
||||
lf_update, //!< updates found while listening to the bus
|
||||
lf_other, //!< all other log facilities
|
||||
lf_COUNT = 5 //!< number of available log facilities
|
||||
};
|
||||
|
||||
/** macro for enabling all log facilities. */
|
||||
@@ -36,12 +36,12 @@ enum LogFacility {
|
||||
|
||||
/** the available log levels. */
|
||||
enum LogLevel {
|
||||
ll_none=0, //!< no level at all
|
||||
ll_error, //!< error message
|
||||
ll_notice, //!< important message
|
||||
ll_info, //!< informational message
|
||||
ll_debug, //!< debugging message (normally suppressed)
|
||||
ll_COUNT=5 //!< number of available log levels
|
||||
ll_none = 0, //!< no level at all
|
||||
ll_error, //!< error message
|
||||
ll_notice, //!< important message
|
||||
ll_info, //!< informational message
|
||||
ll_debug, //!< debugging message (normally suppressed)
|
||||
ll_COUNT = 5 //!< number of available log levels
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -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. */
|
||||
#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_
|
||||
|
||||
+8
-12
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_NOTIFY_H_
|
||||
#define LIBUTILS_NOTIFY_H_
|
||||
#ifndef LIB_UTILS_NOTIFY_H_
|
||||
#define LIB_UTILS_NOTIFY_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -27,15 +27,12 @@
|
||||
/**
|
||||
* class to notify other thread per pipe.
|
||||
*/
|
||||
class Notify
|
||||
{
|
||||
|
||||
public:
|
||||
class Notify {
|
||||
public:
|
||||
/**
|
||||
* constructs a new instance and do notifying.
|
||||
*/
|
||||
Notify()
|
||||
{
|
||||
Notify() {
|
||||
int pipefd[2];
|
||||
int ret = pipe(pipefd);
|
||||
|
||||
@@ -62,17 +59,16 @@ public:
|
||||
* write notify event to file descriptor.
|
||||
* @return result of writing notification.
|
||||
*/
|
||||
int notify() const { return write(m_sendfd,"1",1); }
|
||||
int notify() const { return write(m_sendfd, "1", 1); }
|
||||
|
||||
private:
|
||||
private:
|
||||
/** file descriptor to watch */
|
||||
int m_recvfd;
|
||||
|
||||
/** file descriptor to notify */
|
||||
int m_sendfd;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBUTILS_NOTIFY_H_
|
||||
#endif // LIB_UTILS_NOTIFY_H_
|
||||
|
||||
|
||||
|
||||
+24
-30
@@ -16,12 +16,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_QUEUE_H_
|
||||
#define LIBUTILS_QUEUE_H_
|
||||
#ifndef LIB_UTILS_QUEUE_H_
|
||||
#define LIB_UTILS_QUEUE_H_
|
||||
|
||||
#include <list>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <list>
|
||||
#include "clock.h"
|
||||
|
||||
/** \file queue.h */
|
||||
@@ -33,15 +33,12 @@ using namespace std;
|
||||
* @param T the item type.
|
||||
*/
|
||||
template <typename T>
|
||||
class Queue
|
||||
{
|
||||
|
||||
public:
|
||||
class Queue {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
Queue()
|
||||
{
|
||||
Queue() {
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
}
|
||||
@@ -49,28 +46,26 @@ public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Queue()
|
||||
{
|
||||
~Queue() {
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
*/
|
||||
Queue(const Queue& src);
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Add an item to the end of queue.
|
||||
* @param item the item to add.
|
||||
*/
|
||||
void push(T item)
|
||||
{
|
||||
void push(T item) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_queue.push_back(item);
|
||||
pthread_cond_broadcast(&m_cond);
|
||||
@@ -82,22 +77,22 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
T pop(int timeout=0)
|
||||
{
|
||||
T pop(int timeout = 0) {
|
||||
T item;
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
if (timeout>0) {
|
||||
if (timeout > 0) {
|
||||
struct timespec t;
|
||||
clockGettime(&t);
|
||||
t.tv_sec += timeout;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_queue.empty())
|
||||
if (m_queue.empty()) {
|
||||
item = NULL;
|
||||
else {
|
||||
} else {
|
||||
item = m_queue.front();
|
||||
m_queue.pop_front();
|
||||
}
|
||||
@@ -111,8 +106,7 @@ public:
|
||||
* @param wait true to wait for the item to appear in the queue.
|
||||
* @return whether the item was removed.
|
||||
*/
|
||||
bool remove(T item, bool wait=false)
|
||||
{
|
||||
bool remove(T item, bool wait = false) {
|
||||
bool ret = false;
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
do {
|
||||
@@ -134,19 +128,20 @@ public:
|
||||
* Return the first item in the queue without removing it.
|
||||
* @return the item, or NULL if no item is available.
|
||||
*/
|
||||
T peek()
|
||||
{
|
||||
T peek() {
|
||||
T item;
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
if (m_queue.empty())
|
||||
if (m_queue.empty()) {
|
||||
item = NULL;
|
||||
else
|
||||
} else {
|
||||
item = m_queue.front();
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return item;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the queue itself */
|
||||
list<T> m_queue;
|
||||
|
||||
@@ -155,7 +150,6 @@ private:
|
||||
|
||||
/** condition variable for exclusive lock */
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBUTILS_QUEUE_H_
|
||||
#endif // LIB_UTILS_QUEUE_H_
|
||||
|
||||
@@ -17,28 +17,27 @@
|
||||
*/
|
||||
|
||||
#include "rotatefile.h"
|
||||
#include "clock.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "clock.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
RotateFile::~RotateFile()
|
||||
{
|
||||
RotateFile::~RotateFile() {
|
||||
if (m_stream) {
|
||||
fclose(m_stream);
|
||||
m_stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool RotateFile::setEnabled(bool enabled)
|
||||
{
|
||||
if (enabled==m_enabled) {
|
||||
bool RotateFile::setEnabled(bool enabled) {
|
||||
if (enabled == m_enabled) {
|
||||
return false;
|
||||
}
|
||||
m_enabled = enabled;
|
||||
@@ -53,8 +52,7 @@ bool RotateFile::setEnabled(bool enabled)
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
@@ -66,9 +64,8 @@ void RotateFile::write(unsigned char* value, unsigned int size, bool received)
|
||||
fprintf(m_stream, "%04d-%02d-%02d %02d:%02d:%02d.%03ld %c",
|
||||
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, ts.tv_nsec/1000000,
|
||||
received ? '<' : '>'
|
||||
);
|
||||
for (unsigned int pos=0; pos<size; pos++) {
|
||||
received ? '<' : '>');
|
||||
for (unsigned int pos = 0; pos < size; pos++) {
|
||||
fprintf(m_stream, "%2.2x ", value[pos]);
|
||||
}
|
||||
fprintf(m_stream, "\n");
|
||||
|
||||
+11
-11
@@ -16,12 +16,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_ROTATEFILE_H_
|
||||
#define LIBUTILS_ROTATEFILE_H_
|
||||
#ifndef LIB_UTILS_ROTATEFILE_H_
|
||||
#define LIB_UTILS_ROTATEFILE_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
/** @file rotatefile.h
|
||||
* Helpers for writing to rotating files.
|
||||
@@ -32,16 +33,15 @@ using namespace std;
|
||||
/**
|
||||
* Helper class for writing to a rotating file with maximum size.
|
||||
*/
|
||||
class RotateFile
|
||||
{
|
||||
public:
|
||||
class RotateFile {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param fileName the name of the file 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.
|
||||
*/
|
||||
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) {}
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
bool setEnabled(bool enabled=true);
|
||||
bool setEnabled(bool enabled = true);
|
||||
|
||||
/**
|
||||
* Return whether writing to the file is enabled.
|
||||
@@ -68,9 +68,10 @@ public:
|
||||
* @param size the number of bytes to write.
|
||||
* @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. */
|
||||
bool m_enabled;
|
||||
|
||||
@@ -88,8 +89,7 @@ private:
|
||||
|
||||
/** the number of bytes already written to the @a m_file. */
|
||||
unsigned long m_fileSize;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBUTILS_ROTATEFILE_H_
|
||||
#endif // LIB_UTILS_ROTATEFILE_H_
|
||||
|
||||
|
||||
@@ -17,30 +17,27 @@
|
||||
*/
|
||||
|
||||
#include "tcpsocket.h"
|
||||
#include <cstdlib>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
|
||||
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];
|
||||
inet_ntop(AF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, (socklen_t)sizeof(ip)-1);
|
||||
m_ip = ip;
|
||||
m_port = (uint16_t)ntohs(address->sin_port);
|
||||
}
|
||||
|
||||
bool TCPSocket::isValid()
|
||||
{
|
||||
bool TCPSocket::isValid() {
|
||||
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;
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
@@ -109,8 +105,7 @@ int TCPServer::start()
|
||||
return result;
|
||||
}
|
||||
|
||||
TCPSocket* TCPServer::newSocket()
|
||||
{
|
||||
TCPSocket* TCPServer::newSocket() {
|
||||
if (!m_listening) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+14
-21
@@ -16,13 +16,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_TCPSOCKET_H_
|
||||
#define LIBUTILS_TCPSOCKET_H_
|
||||
#ifndef LIB_UTILS_TCPSOCKET_H_
|
||||
#define LIB_UTILS_TCPSOCKET_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
/** \file tcpsocket.h */
|
||||
|
||||
@@ -37,10 +37,8 @@ using namespace std;
|
||||
/**
|
||||
* class for low level tcp socket operations. (open, close, send, receive).
|
||||
*/
|
||||
class TCPSocket
|
||||
{
|
||||
|
||||
public:
|
||||
class TCPSocket {
|
||||
public:
|
||||
/** grant access for friend class TCPClient */
|
||||
friend class TCPClient;
|
||||
|
||||
@@ -92,7 +90,8 @@ public:
|
||||
*/
|
||||
bool isValid();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** file descriptor from tcp socket */
|
||||
int m_sfd;
|
||||
|
||||
@@ -108,16 +107,13 @@ private:
|
||||
* @param address struct which holds the ip address.
|
||||
*/
|
||||
TCPSocket(int sfd, struct sockaddr_in* address);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* class to initiate a tcp socket connection to a listening server.
|
||||
*/
|
||||
class TCPClient
|
||||
{
|
||||
|
||||
public:
|
||||
class TCPClient {
|
||||
public:
|
||||
/**
|
||||
* initiate a tcp socket connection to a listening server.
|
||||
* @param server the server name or ip address to connect.
|
||||
@@ -125,16 +121,13 @@ public:
|
||||
* @return pointer to an opened tcp socket.
|
||||
*/
|
||||
TCPSocket* connect(const string& server, const uint16_t& port);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* class for a tcp based network server.
|
||||
*/
|
||||
class TCPServer
|
||||
{
|
||||
|
||||
public:
|
||||
class TCPServer {
|
||||
public:
|
||||
/**
|
||||
* creates a new instance of a listening tcp server.
|
||||
* @param port the tcp port.
|
||||
@@ -166,7 +159,8 @@ public:
|
||||
*/
|
||||
int getFD() const { return m_lfd; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** file descriptor from listening tcp socket */
|
||||
int m_lfd;
|
||||
|
||||
@@ -178,8 +172,7 @@ private:
|
||||
|
||||
/** true if object is already listening */
|
||||
bool m_listening;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBUTILS_TCPSOCKET_H_
|
||||
#endif // LIB_UTILS_TCPSOCKET_H_
|
||||
|
||||
|
||||
@@ -23,54 +23,41 @@
|
||||
#include "thread.h"
|
||||
#include "clock.h"
|
||||
|
||||
void* Thread::runThread(void* arg)
|
||||
{
|
||||
void* Thread::runThread(void* arg) {
|
||||
((Thread*)arg)->enter();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
Thread::~Thread() {
|
||||
if (m_started) {
|
||||
pthread_cancel(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);
|
||||
|
||||
if (result == 0) {
|
||||
|
||||
#ifdef HAVE_PTHREAD_SETNAME_NP
|
||||
#ifndef __MACH__
|
||||
pthread_setname_np(m_threadid, name);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
m_started = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Thread::join()
|
||||
{
|
||||
bool Thread::join() {
|
||||
int result = -1;
|
||||
|
||||
if (m_started) {
|
||||
m_stopped = true;
|
||||
result = pthread_join(m_threadid, NULL);
|
||||
|
||||
if (result == 0) {
|
||||
m_started = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
@@ -82,36 +69,31 @@ void Thread::enter() {
|
||||
|
||||
|
||||
WaitThread::WaitThread()
|
||||
: Thread()
|
||||
{
|
||||
: Thread() {
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
}
|
||||
|
||||
WaitThread::~WaitThread()
|
||||
{
|
||||
WaitThread::~WaitThread() {
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
void WaitThread::stop()
|
||||
{
|
||||
void WaitThread::stop() {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_cond_signal(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
Thread::stop();
|
||||
}
|
||||
|
||||
bool WaitThread::join()
|
||||
{
|
||||
bool WaitThread::join() {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_cond_signal(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return Thread::join();
|
||||
}
|
||||
|
||||
bool WaitThread::Wait(int seconds)
|
||||
{
|
||||
bool WaitThread::Wait(int seconds) {
|
||||
struct timespec t;
|
||||
clockGettime(&t);
|
||||
t.tv_sec += seconds;
|
||||
|
||||
+11
-16
@@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBUTILS_THREAD_H_
|
||||
#define LIBUTILS_THREAD_H_
|
||||
#ifndef LIB_UTILS_THREAD_H_
|
||||
#define LIB_UTILS_THREAD_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -26,10 +26,8 @@
|
||||
/**
|
||||
* wrapper class for pthread.
|
||||
*/
|
||||
class Thread
|
||||
{
|
||||
|
||||
public:
|
||||
class Thread {
|
||||
public:
|
||||
/**
|
||||
* constructor.
|
||||
*/
|
||||
@@ -77,15 +75,15 @@ public:
|
||||
*/
|
||||
pthread_t self() { return m_threadid; }
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Thread entry method to be overridden by derived class.
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Enter the Thread loop by calling run().
|
||||
*/
|
||||
@@ -102,17 +100,14 @@ private:
|
||||
|
||||
/** Whether the thread was stopped by @a stop() or @a join(). */
|
||||
bool m_stopped;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A @a Thread that can be waited on.
|
||||
*/
|
||||
class WaitThread : public Thread
|
||||
{
|
||||
|
||||
public:
|
||||
class WaitThread : public Thread {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -136,13 +131,13 @@ public:
|
||||
*/
|
||||
bool Wait(int seconds);
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
/** the mutex for waiting. */
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
/** the condition for waiting. */
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBUTILS_THREAD_H_
|
||||
#endif // LIB_UTILS_THREAD_H_
|
||||
|
||||
+36
-42
@@ -21,22 +21,22 @@
|
||||
#endif
|
||||
|
||||
#include <argp.h>
|
||||
#include "tcpsocket.h"
|
||||
#include <string.h>
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
#endif
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "tcpsocket.h"
|
||||
|
||||
#ifdef HAVE_PPOLL
|
||||
# include <poll.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options
|
||||
{
|
||||
struct options {
|
||||
const char* server; //!< ebusd server host (name or ip) [localhost]
|
||||
uint16_t port; //!< ebusd server port [8888]
|
||||
|
||||
@@ -84,8 +84,7 @@ static const struct argp_option argpoptions[] = {
|
||||
* @param arg the option argument, or NULL.
|
||||
* @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;
|
||||
char* strEnd = NULL;
|
||||
unsigned int port;
|
||||
@@ -116,8 +115,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
string fetchData(TCPSocket* socket, bool& listening)
|
||||
{
|
||||
string fetchData(TCPSocket* socket, bool& listening) {
|
||||
char data[1024];
|
||||
ssize_t datalen;
|
||||
ostringstream ostream;
|
||||
@@ -150,13 +148,13 @@ string fetchData(TCPSocket* socket, bool& listening)
|
||||
FD_SET(STDIN_FILENO, &checkfds);
|
||||
FD_SET(socket->getFD(), &checkfds);
|
||||
maxfd = STDIN_FILENO;
|
||||
if (socket->getFD()>maxfd)
|
||||
if (socket->getFD() > maxfd) {
|
||||
maxfd = socket->getFD();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while(true) {
|
||||
|
||||
#ifdef HAVE_PPOLL
|
||||
// wait for new fd event
|
||||
ret = ppoll(fds, nfds, &tdiff, NULL);
|
||||
@@ -198,19 +196,20 @@ string fetchData(TCPSocket* socket, bool& listening)
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < datalen; i++)
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
ostream << data[i];
|
||||
|
||||
}
|
||||
string str = ostream.str();
|
||||
if (listening)
|
||||
if (listening) {
|
||||
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;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
else if (newInput) {
|
||||
}
|
||||
} else if (newInput) {
|
||||
getline(cin, message);
|
||||
sendmessage = message+'\n';
|
||||
socket->send(sendmessage.c_str(), sendmessage.size());
|
||||
@@ -221,7 +220,6 @@ string fetchData(TCPSocket* socket, bool& listening)
|
||||
exit(EXIT_SUCCESS);
|
||||
return "";
|
||||
}
|
||||
|
||||
message.clear();
|
||||
}
|
||||
}
|
||||
@@ -229,9 +227,7 @@ string fetchData(TCPSocket* socket, bool& listening)
|
||||
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();
|
||||
TCPSocket* socket = client->connect(host, port);
|
||||
|
||||
@@ -244,17 +240,19 @@ void connect(const char* host, uint16_t port, char* const *args, int argCount)
|
||||
if (!once) {
|
||||
cout << host << ": ";
|
||||
getline(cin, message);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
message += " ";
|
||||
}
|
||||
bool quote = strchr(args[i], ' ') != NULL && strchr(args[i], '"') == NULL;
|
||||
if (quote)
|
||||
if (quote) {
|
||||
message += "\"";
|
||||
}
|
||||
message += args[i];
|
||||
if (quote)
|
||||
if (quote) {
|
||||
message += "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,32 +271,28 @@ void connect(const char* host, uint16_t port, char* const *args, int argCount)
|
||||
while (listening && !cin.eof()) {
|
||||
string result(fetchData(socket, listening));
|
||||
cout << result;
|
||||
if (strcasecmp(result.c_str(), "LISTEN STOPPED") == 0)
|
||||
if (strcasecmp(result.c_str(), "LISTEN STOPPED") == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
cout << fetchData(socket, listening);
|
||||
}
|
||||
}
|
||||
|
||||
} while (!once && !cin.eof());
|
||||
|
||||
delete socket;
|
||||
|
||||
}
|
||||
else
|
||||
} else {
|
||||
cout << "error connecting to " << host << ":" << port << endl;
|
||||
|
||||
}
|
||||
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 };
|
||||
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;
|
||||
|
||||
}
|
||||
connect(opt.server, opt.port, opt.args, opt.argCount);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
+17
-24
@@ -21,19 +21,18 @@
|
||||
#endif
|
||||
|
||||
#include <argp.h>
|
||||
#include "device.h"
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include "device.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** A structure holding all program options. */
|
||||
struct options
|
||||
{
|
||||
struct options {
|
||||
const char* device; //!< device to write to [/dev/ttyUSB60]
|
||||
unsigned int time; //!< delay between bytes in us [10000]
|
||||
|
||||
@@ -85,8 +84,7 @@ static const struct argp_option argpoptions[] = {
|
||||
* @param arg the option argument, or NULL.
|
||||
* @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;
|
||||
char* strEnd = NULL;
|
||||
switch (key) {
|
||||
@@ -112,8 +110,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
return EINVAL;
|
||||
}
|
||||
opt->dumpFile = arg;
|
||||
} else
|
||||
} else {
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
@@ -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 };
|
||||
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;
|
||||
|
||||
}
|
||||
Device* device = Device::create(opt.device, false, false, NULL);
|
||||
if (device == NULL) {
|
||||
cout << "unable to create device " << opt.device << endl;
|
||||
return EINVAL;
|
||||
}
|
||||
result_t result = device->open();
|
||||
if (result != RESULT_OK)
|
||||
if (result != RESULT_OK) {
|
||||
cout << "unable to open " << opt.device << ": " << getResultCode(result) << endl;
|
||||
|
||||
if (!device->isValid())
|
||||
}
|
||||
if (!device->isValid()) {
|
||||
cout << "device " << opt.device << " not available" << endl;
|
||||
else {
|
||||
} else {
|
||||
cout << "device opened" << endl;
|
||||
|
||||
fstream file(opt.dumpFile, ios::in | ios::binary);
|
||||
|
||||
if (file.is_open()) {
|
||||
|
||||
while (true) {
|
||||
unsigned char byte = (unsigned char)file.get();
|
||||
if (file.eof())
|
||||
if (file.eof()) {
|
||||
break;
|
||||
}
|
||||
cout << hex << setw(2) << setfill('0')
|
||||
<< static_cast<unsigned>(byte) << endl;
|
||||
|
||||
device->send(byte);
|
||||
usleep(opt.time);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
} else {
|
||||
cout << "error opening file " << opt.dumpFile << endl;
|
||||
}
|
||||
}
|
||||
|
||||
delete device;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user