made SymbolString master/slave aware and contain only unescaped data, moved CRC tracking and escpaing/enscaping to BusHandler, moved parseInt/parseSignedInt from datatype.h to symbol.h, added new error code for retrival of unexpted symbol after a send to the bus

This commit is contained in:
john30
2017-02-26 16:31:32 +01:00
parent 5087ece9a4
commit 1a878694d2
17 changed files with 586 additions and 565 deletions
+166 -85
View File
@@ -46,13 +46,17 @@ const char* getStateCode(BusState state) {
case bs_skip: return "skip"; case bs_skip: return "skip";
case bs_ready: return "ready"; case bs_ready: return "ready";
case bs_sendCmd: return "send command"; case bs_sendCmd: return "send command";
case bs_recvCmdCrc: return "receive command CRC";
case bs_recvCmdAck: return "receive command ACK"; case bs_recvCmdAck: return "receive command ACK";
case bs_recvRes: return "receive response"; case bs_recvRes: return "receive response";
case bs_recvResCrc: return "receive response CRC";
case bs_sendResAck: return "send response ACK"; case bs_sendResAck: return "send response ACK";
case bs_recvCmd: return "receive command"; case bs_recvCmd: return "receive command";
case bs_recvResAck: return "receive response ACK"; case bs_recvResAck: return "receive response ACK";
case bs_sendCmdCrc: return "send command CRC";
case bs_sendCmdAck: return "send command ACK"; case bs_sendCmdAck: return "send command ACK";
case bs_sendRes: return "send response"; case bs_sendRes: return "send response";
case bs_sendResCrc: return "send response CRC";
case bs_sendSyn: return "send SYN"; case bs_sendSyn: return "send SYN";
default: return "unknown"; default: return "unknown";
} }
@@ -181,22 +185,22 @@ bool ActiveBusRequest::notify(result_t result, SymbolString& slave) {
logDebug(lf_bus, "read res: %s", slave.getDataStr().c_str()); logDebug(lf_bus, "read res: %s", slave.getDataStr().c_str());
} }
m_result = result; m_result = result;
m_slave.addAll(slave, true); m_slave = slave;
return false; return false;
} }
void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) { void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) {
m_lastMaster.clear(false); m_lastMaster.clear();
m_lastMaster.addAll(master); m_lastMaster = master;
m_lastSlave.clear(false); m_lastSlave.clear();
m_lastSlave.addAll(slave); m_lastSlave = slave;
m_count++; m_count++;
} }
/** /**
* Decode the input @a SymbolString with the specified @a DataType and length. * Decode the input @a SymbolString with the specified @a DataType and length.
* @param type the @a DataType. * @param type the @a DataType.
* @param input the unescaped @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param isMaster whether the @a SymbolString is the master part. * @param isMaster whether the @a SymbolString is the master part.
* @param baseOffset the base offset in the @a SymbolString. * @param baseOffset the base offset in the @a SymbolString.
* @param length the number of symbols to read. * @param length the number of symbols to read.
@@ -208,7 +212,7 @@ void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) {
bool decodeType(DataType* type, SymbolString *input, bool isMaster, unsigned char baseOffset, unsigned char length, bool decodeType(DataType* type, SymbolString *input, bool isMaster, unsigned char baseOffset, unsigned char length,
unsigned char offsets, ostringstream& output, bool firstOnly = false) { unsigned char offsets, ostringstream& output, bool firstOnly = false) {
bool first = true; bool first = true;
string in = input->getDataStr(true, true, baseOffset); string in = input->getDataStr(baseOffset);
for (unsigned char offset = 0; offset <= offsets; offset++) { for (unsigned char offset = 0; offset <= offsets; offset++) {
ostringstream out; ostringstream out;
result_t result = type->readSymbols(*input, isMaster, (unsigned char)(baseOffset+offset), (unsigned char)length, result_t result = type->readSymbols(*input, isMaster, (unsigned char)(baseOffset+offset), (unsigned char)length,
@@ -352,7 +356,7 @@ result_t BusHandler::readFromBus(Message* message, string inputStr, const unsign
unsigned char masterAddress = srcAddress == SYN ? m_ownMasterAddress : srcAddress; unsigned char masterAddress = srcAddress == SYN ? m_ownMasterAddress : srcAddress;
result_t ret = RESULT_EMPTY; result_t ret = RESULT_EMPTY;
SymbolString master(true); SymbolString master(true);
SymbolString slave(false); SymbolString slave;
for (unsigned char index = 0; index < message->getCount(); index++) { for (unsigned char index = 0; index < message->getCount(); index++) {
istringstream input(inputStr); istringstream input(inputStr);
ret = message->prepareMaster(masterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index); ret = message->prepareMaster(masterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index);
@@ -463,11 +467,13 @@ result_t BusHandler::handleSymbol() {
break; break;
case bs_recvCmd: case bs_recvCmd:
case bs_recvCmdCrc:
case bs_recvCmdAck: case bs_recvCmdAck:
timeout = m_slaveRecvTimeout; timeout = m_slaveRecvTimeout;
break; break;
case bs_recvRes: case bs_recvRes:
case bs_recvResCrc:
if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) { if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) {
timeout = m_slaveRecvTimeout; timeout = m_slaveRecvTimeout;
} else { } else {
@@ -481,28 +487,42 @@ result_t BusHandler::handleSymbol() {
case bs_sendCmd: case bs_sendCmd:
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // unescaped command
sending = true;
}
break;
case bs_sendCmdCrc:
if (m_currentRequest != NULL) {
sendSymbol = m_crc;
sending = true; sending = true;
} }
break; break;
case bs_sendResAck: case bs_sendResAck:
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
sendSymbol = m_responseCrcValid ? ACK : NAK; sendSymbol = m_crcValid ? ACK : NAK;
sending = true; sending = true;
} }
break; break;
case bs_sendCmdAck: case bs_sendCmdAck:
if (m_answer) { if (m_answer) {
sendSymbol = m_commandCrcValid ? ACK : NAK; sendSymbol = m_crcValid ? ACK : NAK;
sending = true; sending = true;
} }
break; break;
case bs_sendRes: case bs_sendRes:
if (m_answer) { if (m_answer) {
sendSymbol = m_response[m_nextSendPos]; // escaped response sendSymbol = m_response[m_nextSendPos]; // unescaped response
sending = true;
}
break;
case bs_sendResCrc:
if (m_currentRequest != NULL) {
sendSymbol = m_crc;
sending = true; sending = true;
} }
break; break;
@@ -516,6 +536,14 @@ result_t BusHandler::handleSymbol() {
// send symbol if necessary // send symbol if necessary
result_t result; result_t result;
if (sending) { if (sending) {
if (m_state != bs_sendSyn && (sendSymbol == ESC || sendSymbol == SYN)) {
if (m_escape) {
sendSymbol = sendSymbol == ESC ? 0x00 : 0x01;
} else {
m_escape = sendSymbol;
sendSymbol = ESC;
}
}
result = m_device->send(sendSymbol); result = m_device->send(sendSymbol);
if (result == RESULT_OK) { if (result == RESULT_OK) {
if (m_state == bs_ready) { if (m_state == bs_ready) {
@@ -587,7 +615,39 @@ result_t BusHandler::handleSymbol() {
return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN); return setState(bs_ready, m_state == bs_skip ? RESULT_OK : RESULT_ERR_SYN);
} }
unsigned int headerLen, crcPos; switch (m_state) {
case bs_ready:
case bs_recvCmd:
case bs_recvRes:
case bs_sendCmd:
case bs_sendRes:
SymbolString::updateCrc(m_crc, recvSymbol);
break;
default:
break;
}
if (m_escape) {
// check escape/unescape state
if (sending) {
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
if (sendSymbol == ESC) {
return RESULT_OK;
}
sendSymbol = recvSymbol = m_escape;
} else {
if (recvSymbol > 0x01) {
return setState(bs_skip, RESULT_ERR_ESC);
}
recvSymbol = recvSymbol == 0x00 ? ESC : SYN;
}
m_escape = 0;
} else if (!sending && recvSymbol == ESC) {
m_escape = ESC;
return RESULT_OK;
}
switch (m_state) { switch (m_state) {
case bs_noSignal: case bs_noSignal:
@@ -617,59 +677,55 @@ result_t BusHandler::handleSymbol() {
} }
setState(m_state, RESULT_ERR_BUS_LOST); // try again later setState(m_state, RESULT_ERR_BUS_LOST); // try again later
} }
result = m_command.push_back(recvSymbol, false); // expect no escaping for master address m_command.push_back(recvSymbol);
if (result < RESULT_OK) {
return setState(bs_skip, result);
}
m_repeat = false; m_repeat = false;
return setState(bs_recvCmd, RESULT_OK); return setState(bs_recvCmd, RESULT_OK);
case bs_recvCmd: case bs_recvCmd:
headerLen = 4; m_command.push_back(recvSymbol);
// header symbols are never escaped if (m_command.isComplete()) { // all data received
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff; return setState(bs_recvCmdCrc, RESULT_OK);
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
if (result < RESULT_OK) {
return setState(bs_skip, result);
} }
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received return RESULT_OK;
unsigned char dstAddress = m_command[1];
// header symbols are never escaped case bs_recvCmdCrc:
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC(); m_crcValid = recvSymbol == m_crc;
if (m_commandCrcValid) { if (m_command[1] == BROADCAST) {
if (dstAddress == BROADCAST) { if (m_crcValid) {
receiveCompleted(); receiveCompleted();
return setState(bs_skip, RESULT_OK); return setState(bs_skip, RESULT_OK);
} }
addSeenAddress(m_command[0]);
if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
return setState(bs_sendCmdAck, RESULT_OK);
}
return setState(bs_recvCmdAck, RESULT_OK);
}
if (dstAddress == BROADCAST) {
return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC);
} }
if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) { if (m_answer) {
unsigned char dstAddress = m_command[1];
if (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress) {
if (m_crcValid) {
addSeenAddress(m_command[0]);
return setState(bs_sendCmdAck, RESULT_OK);
}
return setState(bs_sendCmdAck, RESULT_ERR_CRC); return setState(bs_sendCmdAck, RESULT_ERR_CRC);
} }
}
if (m_crcValid) {
addSeenAddress(m_command[0]);
return setState(bs_recvCmdAck, RESULT_OK);
}
if (m_repeat) { if (m_repeat) {
return setState(bs_skip, RESULT_ERR_CRC); return setState(bs_skip, RESULT_ERR_CRC);
} }
return setState(bs_recvCmdAck, RESULT_ERR_CRC); return setState(bs_recvCmdAck, RESULT_ERR_CRC);
}
return RESULT_OK;
case bs_recvCmdAck: case bs_recvCmdAck:
if (recvSymbol == ACK) { if (recvSymbol == ACK) {
if (!m_commandCrcValid) { if (!m_crcValid) {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
} }
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
if (isMaster(m_currentRequest->m_master[1])) { if (isMaster(m_currentRequest->m_master[1])) {
return setState(bs_sendSyn, RESULT_OK); return setState(bs_sendSyn, RESULT_OK);
} }
} else if (isMaster(m_command[1])) { // header symbols are never escaped } else if (isMaster(m_command[1])) {
receiveCompleted(); receiveCompleted();
return setState(bs_skip, RESULT_OK); return setState(bs_skip, RESULT_OK);
} }
@@ -680,6 +736,7 @@ result_t BusHandler::handleSymbol() {
if (recvSymbol == NAK) { if (recvSymbol == NAK) {
if (!m_repeat) { if (!m_repeat) {
m_repeat = true; m_repeat = true;
m_crc = 0;
m_nextSendPos = 0; m_nextSendPos = 0;
m_command.clear(); m_command.clear();
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
@@ -692,15 +749,15 @@ result_t BusHandler::handleSymbol() {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
case bs_recvRes: case bs_recvRes:
headerLen = 0; m_response.push_back(recvSymbol);
crcPos = m_response.size() > headerLen ? headerLen + 1 + m_response[headerLen] : 0xff; if (m_response.isComplete()) { // all data received
result = m_response.push_back(recvSymbol, true, m_response.size() < crcPos); return setState(bs_recvResCrc, RESULT_OK);
if (result < RESULT_OK) {
return setState(bs_skip, result);
} }
if (result == RESULT_OK && crcPos != 0xff && m_response.size() == crcPos + 1) { // CRC received return RESULT_OK;
m_responseCrcValid = m_response[headerLen + 1 + m_response[headerLen]] == m_response.getCRC();
if (m_responseCrcValid) { case bs_recvResCrc:
m_crcValid = recvSymbol == m_crc;
if (m_crcValid) {
if (m_currentRequest != NULL) { if (m_currentRequest != NULL) {
return setState(bs_sendResAck, RESULT_OK); return setState(bs_sendResAck, RESULT_OK);
} }
@@ -716,12 +773,10 @@ result_t BusHandler::handleSymbol() {
return setState(bs_sendResAck, RESULT_ERR_CRC); return setState(bs_sendResAck, RESULT_ERR_CRC);
} }
return setState(bs_recvResAck, RESULT_ERR_CRC); return setState(bs_recvResAck, RESULT_ERR_CRC);
}
return RESULT_OK;
case bs_recvResAck: case bs_recvResAck:
if (recvSymbol == ACK) { if (recvSymbol == ACK) {
if (!m_responseCrcValid) { if (!m_crcValid) {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
} }
receiveCompleted(); receiveCompleted();
@@ -738,25 +793,33 @@ result_t BusHandler::handleSymbol() {
return setState(bs_skip, RESULT_ERR_ACK); return setState(bs_skip, RESULT_ERR_ACK);
case bs_sendCmd: case bs_sendCmd:
if (m_currentRequest != NULL && sending && recvSymbol == sendSymbol) { if (!sending || m_currentRequest == NULL) {
// successfully sent return setState(bs_skip, RESULT_ERR_INVALID_ARG);
}
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
m_nextSendPos++; m_nextSendPos++;
if (m_nextSendPos >= m_currentRequest->m_master.size()) { if (m_nextSendPos >= m_currentRequest->m_master.size()) {
// master data completely sent return setState(bs_sendCmdCrc, RESULT_OK);
}
return RESULT_OK;
case bs_sendCmdCrc:
if (m_currentRequest->m_master[1] == BROADCAST) { if (m_currentRequest->m_master[1] == BROADCAST) {
return setState(bs_sendSyn, RESULT_OK); return setState(bs_sendSyn, RESULT_OK);
} }
m_commandCrcValid = true; m_crcValid = true;
return setState(bs_recvCmdAck, RESULT_OK); return setState(bs_recvCmdAck, RESULT_OK);
}
return RESULT_OK;
}
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
case bs_sendResAck: case bs_sendResAck:
if (m_currentRequest != NULL && sending && recvSymbol == sendSymbol) { if (!sending || m_currentRequest == NULL) {
// successfully sent return setState(bs_skip, RESULT_ERR_INVALID_ARG);
if (!m_responseCrcValid) { }
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
if (!m_crcValid) {
if (!m_repeat) { if (!m_repeat) {
m_repeat = true; m_repeat = true;
m_response.clear(); m_response.clear();
@@ -765,15 +828,18 @@ result_t BusHandler::handleSymbol() {
return setState(bs_sendSyn, RESULT_ERR_ACK); return setState(bs_sendSyn, RESULT_ERR_ACK);
} }
return setState(bs_sendSyn, RESULT_OK); return setState(bs_sendSyn, RESULT_OK);
}
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
case bs_sendCmdAck: case bs_sendCmdAck:
if (sending && m_answer && recvSymbol == sendSymbol) { if (!sending || !m_answer) {
// successfully sent return setState(bs_skip, RESULT_ERR_INVALID_ARG);
if (!m_commandCrcValid) { }
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
if (!m_crcValid) {
if (!m_repeat) { if (!m_repeat) {
m_repeat = true; m_repeat = true;
m_crc = 0;
m_command.clear(); m_command.clear();
return setState(bs_recvCmd, RESULT_ERR_NAK, true); return setState(bs_recvCmd, RESULT_ERR_NAK, true);
} }
@@ -786,6 +852,7 @@ result_t BusHandler::handleSymbol() {
m_nextSendPos = 0; m_nextSendPos = 0;
m_repeat = false; m_repeat = false;
{
Message* message; Message* message;
istringstream input; // TODO create input from database of internal variables istringstream input; // TODO create input from database of internal variables
message = m_messages->find(m_command); message = m_messages->find(m_command);
@@ -803,34 +870,46 @@ result_t BusHandler::handleSymbol() {
input.str(SCAN_ANSWER); input.str(SCAN_ANSWER);
} }
// build response and store in m_response for sending back to requesting master // build response and store in m_response for sending back to requesting master
m_response.clear(true); // escape while sending response m_response.clear();
result = message->prepareSlave(input, m_response); result = message->prepareSlave(input, m_response);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
} }
return setState(bs_sendRes, RESULT_OK);
} }
return setState(bs_skip, RESULT_ERR_INVALID_ARG); return setState(bs_sendRes, RESULT_OK);
case bs_sendRes: case bs_sendRes:
if (sending && m_answer && recvSymbol == sendSymbol) { if (!sending || !m_answer) {
// successfully sent return setState(bs_skip, RESULT_ERR_INVALID_ARG);
}
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
m_nextSendPos++; m_nextSendPos++;
if (m_nextSendPos >= m_response.size()) { if (m_nextSendPos >= m_response.size()) {
// slave data completely sent // slave data completely sent
return setState(bs_recvResAck, RESULT_OK); return setState(bs_sendResCrc, RESULT_OK);
} }
return RESULT_OK; return RESULT_OK;
}
case bs_sendResCrc:
if (!sending || m_currentRequest == NULL) {
return setState(bs_skip, RESULT_ERR_INVALID_ARG); return setState(bs_skip, RESULT_ERR_INVALID_ARG);
}
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
return setState(bs_recvResAck, RESULT_OK);
case bs_sendSyn: case bs_sendSyn:
if (sending && recvSymbol == sendSymbol) { if (!sending) {
// successfully sent
return setState(bs_skip, RESULT_OK);
}
return setState(bs_skip, RESULT_ERR_INVALID_ARG); return setState(bs_skip, RESULT_ERR_INVALID_ARG);
} }
if (recvSymbol != sendSymbol) {
return setState(bs_skip, RESULT_ERR_SYMBOL);
}
return setState(bs_skip, RESULT_OK);
}
return RESULT_OK; return RESULT_OK;
} }
@@ -863,7 +942,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
} }
if (state == bs_noSignal) { // notify all requests if (state == bs_noSignal) { // notify all requests
m_response.clear(false); // notify with empty response m_response.clear(); // notify with empty response
while ((m_currentRequest = m_nextRequests.pop()) != NULL) { while ((m_currentRequest = m_nextRequests.pop()) != NULL) {
bool restart = m_currentRequest->notify(RESULT_ERR_NO_SIGNAL, m_response); bool restart = m_currentRequest->notify(RESULT_ERR_NO_SIGNAL, m_response);
if (restart) { // should not occur with no signal if (restart) { // should not occur with no signal
@@ -877,6 +956,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
} }
} }
m_escape = 0;
if (state == m_state) { if (state == m_state) {
return result; return result;
} }
@@ -895,12 +975,13 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
if (state == bs_ready || state == bs_skip) { if (state == bs_ready || state == bs_skip) {
m_command.clear(); m_command.clear();
m_commandCrcValid = false; m_crc = 0;
m_response.clear(false); // unescape while receiving response m_crcValid = false;
m_responseCrcValid = false; m_response.clear();
m_nextSendPos = 0; m_nextSendPos = 0;
} else if (state == bs_recvRes || state == bs_sendRes) {
m_crc = 0;
} }
return result; return result;
} }
@@ -1182,7 +1263,7 @@ result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
istringstream input; istringstream input;
SymbolString master; SymbolString master(true);
result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress); result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress);
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = sendAndWait(master, slave); result = sendAndWait(master, slave);
+27 -21
View File
@@ -66,13 +66,17 @@ enum BusState {
bs_skip, //!< skip all symbols until next @a SYN bs_skip, //!< skip all symbols until next @a SYN
bs_ready, //!< ready for next master (after @a SYN symbol, send/receive QQ) bs_ready, //!< ready for next master (after @a SYN symbol, send/receive QQ)
bs_recvCmd, //!< receive command (ZZ, PBSB, master data) [passive set] bs_recvCmd, //!< receive command (ZZ, PBSB, master data) [passive set]
bs_recvCmdCrc, //!< receive command CRC [passive set]
bs_recvCmdAck, //!< receive command ACK/NACK [passive set + active set+get] bs_recvCmdAck, //!< receive command ACK/NACK [passive set + active set+get]
bs_recvRes, //!< receive response (slave data) [passive set + active get] bs_recvRes, //!< receive response (slave data) [passive set + active get]
bs_recvResCrc, //!< receive response CRC [passive set + active get]
bs_recvResAck, //!< receive response ACK/NACK [passive set] bs_recvResAck, //!< receive response ACK/NACK [passive set]
bs_sendCmd, //!< send command (ZZ, PBSB, master data) [active set+get] bs_sendCmd, //!< send command (ZZ, PBSB, master data) [active set+get]
bs_sendCmdCrc, //!< send command CRC [active set+get]
bs_sendResAck, //!< send response ACK/NACK [active get] bs_sendResAck, //!< send response ACK/NACK [active get]
bs_sendCmdAck, //!< send command ACK/NACK [passive get] bs_sendCmdAck, //!< send command ACK/NACK [passive get]
bs_sendRes, //!< send response (slave data) [passive get] bs_sendRes, //!< send response (slave data) [passive get]
bs_sendResCrc, //!< send response CRC [passive get]
bs_sendSyn, //!< send SYN for completed transfer [active set+get] bs_sendSyn, //!< send SYN for completed transfer [active set+get]
}; };
@@ -102,7 +106,7 @@ class BusRequest {
public: public:
/** /**
* Constructor. * Constructor.
* @param master the escaped master data @a SymbolString to send. * @param master the master data @a SymbolString to send.
* @param deleteOnFinish whether to automatically delete this @a BusRequest when finished. * @param deleteOnFinish whether to automatically delete this @a BusRequest when finished.
*/ */
BusRequest(SymbolString& master, const bool deleteOnFinish) BusRequest(SymbolString& master, const bool deleteOnFinish)
@@ -124,7 +128,7 @@ class BusRequest {
protected: protected:
/** the escaped master data @a SymbolString to send. */ /** the master data @a SymbolString to send. */
SymbolString& m_master; SymbolString& m_master;
/** the number of times a send is repeated due to lost arbitration. */ /** the number of times a send is repeated due to lost arbitration. */
@@ -166,8 +170,8 @@ class PollRequest : public BusRequest {
private: private:
/** the escaped master data @a SymbolString. */ /** the master data @a SymbolString. */
SymbolString m_master; SymbolString m_master{true};
/** the associated @a Message. */ /** the associated @a Message. */
Message* m_message; Message* m_message;
@@ -218,8 +222,8 @@ class ScanRequest : public BusRequest {
/** the @a MessageMap instance. */ /** the @a MessageMap instance. */
MessageMap* m_messageMap; MessageMap* m_messageMap;
/** the escaped master data @a SymbolString. */ /** the master data @a SymbolString. */
SymbolString m_master; SymbolString m_master{true};
/** the currently queried @a Message. */ /** the currently queried @a Message. */
Message* m_message; Message* m_message;
@@ -253,7 +257,7 @@ class ActiveBusRequest : public BusRequest {
public: public:
/** /**
* Constructor. * Constructor.
* @param master the escaped master data @a SymbolString to send. * @param master the master data @a SymbolString to send.
* @param slave reference to @a SymbolString for filling in the received slave data. * @param slave reference to @a SymbolString for filling in the received slave data.
*/ */
ActiveBusRequest(SymbolString& master, SymbolString& slave) ActiveBusRequest(SymbolString& master, SymbolString& slave)
@@ -292,8 +296,8 @@ class GrabbedMessage {
* @param other the @a GrabbedMessage to copy from. * @param other the @a GrabbedMessage to copy from.
*/ */
GrabbedMessage(const GrabbedMessage& other) : m_count(other.m_count) { GrabbedMessage(const GrabbedMessage& other) : m_count(other.m_count) {
m_lastMaster.addAll(other.m_lastMaster); m_lastMaster = other.m_lastMaster;
m_lastSlave.addAll(other.m_lastSlave); m_lastSlave = other.m_lastSlave;
} }
/** /**
@@ -364,8 +368,7 @@ class BusHandler : public WaitThread {
m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0), m_pollInterval(pollInterval), m_lastReceive(0), m_lastPoll(0),
m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0), m_currentRequest(NULL), m_runningScans(0), m_nextSendPos(0),
m_symPerSec(0), m_maxSymPerSec(0), m_symPerSec(0), m_maxSymPerSec(0),
m_state(bs_noSignal), m_repeat(false), m_state(bs_noSignal), m_escape(0), m_crc(0), m_crcValid(false), 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)); memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
} }
@@ -398,7 +401,7 @@ class BusHandler : public WaitThread {
/** /**
* Send a message on the bus and wait for the answer. * Send a message on the bus and wait for the answer.
* @param master the escaped @a SymbolString with the master data to send. * @param master the @a SymbolString with the master data to send.
* @param slave the @a SymbolString that will be filled with retrieved slave data. * @param slave the @a SymbolString that will be filled with retrieved slave data.
* @return the result code. * @return the result code.
*/ */
@@ -632,21 +635,24 @@ class BusHandler : public WaitThread {
/** the current @a BusState. */ /** the current @a BusState. */
BusState m_state; BusState m_state;
/** 0 when not escaping/unescaping, or @a ESC when receiving, or the original value when sending. */
unsigned char m_escape;
/** the calculated CRC. */
unsigned char m_crc;
/** whether the CRC matched. */
bool m_crcValid;
/** whether the current message part is being repeated. */ /** whether the current message part is being repeated. */
bool m_repeat; bool m_repeat;
/** the unescaped received command. */ /** the received command. */
SymbolString m_command; SymbolString m_command{true};
/** whether the command CRC is valid. */ /** the received response or response to send. */
bool m_commandCrcValid;
/** the unescaped received response or escaped response to send. */
SymbolString m_response; SymbolString m_response;
/** whether the response CRC is valid. */
bool m_responseCrcValid;
/** the participating bus addresses seen so far (0 if not seen yet, or combination of @a SEEN bits). */ /** the participating bus addresses seen so far (0 if not seen yet, or combination of @a SEEN bits). */
unsigned char m_seenAddresses[256]; unsigned char m_seenAddresses[256];
+31 -36
View File
@@ -233,7 +233,7 @@ void MainLoop::run() {
result = m_busHandler->startScan(true, "*"); result = m_busHandler->startScan(true, "*");
} else { } else {
logNotice(lf_main, "starting initial scan for %2.2x", m_initialScan); logNotice(lf_main, "starting initial scan for %2.2x", m_initialScan);
SymbolString slave(false); SymbolString slave;
result = m_busHandler->scanAndWait(m_initialScan, slave); result = m_busHandler->scanAndWait(m_initialScan, slave);
Message* message = m_messages->getScanMessage(m_initialScan); Message* message = m_messages->getScanMessage(m_initialScan);
if (result == RESULT_OK && message != NULL) { if (result == RESULT_OK && message != NULL) {
@@ -257,7 +257,7 @@ void MainLoop::run() {
taskDelay = 5; taskDelay = 5;
lastScanAddress = 0; lastScanAddress = 0;
} else { } else {
SymbolString slave(false); SymbolString slave;
if (scanned) { if (scanned) {
Message* message = m_messages->getScanMessage(lastScanAddress); Message* message = m_messages->getScanMessage(lastScanAddress);
slave = message->getLastSlaveData(); slave = message->getLastSlaveData();
@@ -486,13 +486,14 @@ result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, SymbolStr
} }
result_t ret; result_t ret;
unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, ret); unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, ret);
if (ret == RESULT_OK && (4+length)*2 != msg.str().size()) { if (ret != RESULT_OK) {
return ret;
}
if ((4+length)*2 != msg.str().size()) {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
ret = master.push_back(srcAddress == SYN ? m_address : srcAddress, false); master.push_back(srcAddress == SYN ? m_address : srcAddress);
if (ret == RESULT_OK) {
ret = master.parseHex(msg.str()); ret = master.parseHex(msg.str());
}
if (ret == RESULT_OK && !isValidAddress(master[1])) { if (ret == RESULT_OK && !isValidAddress(master[1])) {
ret = RESULT_ERR_INVALID_ADDR; ret = RESULT_ERR_INVALID_ADDR;
} }
@@ -613,18 +614,18 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
time(&now); time(&now);
if (hex && argPos > 0) { if (hex && argPos > 0) {
SymbolString cacheMaster(false); SymbolString master(true);
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress); result_t ret = parseHexMaster(args, argPos, master, srcAddress);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
if (cacheMaster[1] == BROADCAST || isMaster(cacheMaster[1])) { if (master[1] == BROADCAST || isMaster(master[1])) {
return getResultCode(RESULT_ERR_INVALID_ARG); return getResultCode(RESULT_ERR_INVALID_ARG);
} }
logNotice(lf_main, "read hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); logNotice(lf_main, "read hex cmd: %s", master.getDataStr().c_str());
// find message // find message
Message* message = m_messages->find(cacheMaster, false, true, false, false); Message* message = m_messages->find(master, false, true, false, false);
if (message == NULL) { if (message == NULL) {
return getResultCode(RESULT_ERR_NOTFOUND); return getResultCode(RESULT_ERR_NOTFOUND);
@@ -643,17 +644,15 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
|| (message->isPassive() && message->getLastUpdateTime() != 0))) { || (message->isPassive() && message->getLastUpdateTime() != 0))) {
SymbolString& slave = message->getLastSlaveData(); SymbolString& slave = message->getLastSlaveData();
logNotice(lf_main, "hex read %s %s from cache", message->getCircuit().c_str(), message->getName().c_str()); logNotice(lf_main, "hex read %s %s from cache", message->getCircuit().c_str(), message->getName().c_str());
return slave.getDataStr(true, false); return slave.getDataStr();
} }
// send message // send message
SymbolString master(true); SymbolString slave;
master.addAll(cacheMaster);
SymbolString slave(false);
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->storeLastData(cacheMaster, slave); ret = message->storeLastData(master, slave);
ostringstream result; ostringstream result;
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->decodeLastData(result); ret = message->decodeLastData(result);
@@ -665,7 +664,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret)); getResultCode(ret));
} }
return slave.getDataStr(true, false); return slave.getDataStr();
} }
logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret)); getResultCode(ret));
@@ -822,15 +821,15 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
} }
if (hex && argPos > 0) { if (hex && argPos > 0) {
SymbolString cacheMaster(false); SymbolString master(true);
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress); result_t ret = parseHexMaster(args, argPos, master, srcAddress);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
logNotice(lf_main, "write hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); logNotice(lf_main, "write hex cmd: %s", master.getDataStr().c_str());
// find message // find message
Message* message = m_messages->find(cacheMaster, false, false, true, false); Message* message = m_messages->find(master, false, false, true, false);
if (message == NULL) { if (message == NULL) {
return getResultCode(RESULT_ERR_NOTFOUND); return getResultCode(RESULT_ERR_NOTFOUND);
@@ -845,14 +844,12 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit
} }
// send message // send message
SymbolString master(true); SymbolString slave;
master.addAll(cacheMaster);
SymbolString slave(false);
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
// also update read messages // also update read messages
ret = message->storeLastData(cacheMaster, slave); ret = message->storeLastData(master, slave);
ostringstream result; ostringstream result;
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->decodeLastData(result); ret = message->decodeLastData(result);
@@ -870,7 +867,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
if (isMaster(master[1])) { if (isMaster(master[1])) {
return getResultCode(RESULT_OK); return getResultCode(RESULT_OK);
} }
return slave.getDataStr(true, false); return slave.getDataStr();
} }
logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret)); getResultCode(ret));
@@ -959,17 +956,15 @@ string MainLoop::executeHex(vector<string> &args) {
} }
if (argPos > 0) { if (argPos > 0) {
SymbolString cacheMaster(false); SymbolString master(true);
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress); result_t ret = parseHexMaster(args, argPos, master, srcAddress);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
logNotice(lf_main, "hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); logNotice(lf_main, "hex cmd: %s", master.getDataStr().c_str());
// send message // send message
SymbolString master(true); SymbolString slave;
master.addAll(cacheMaster);
SymbolString slave(false);
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
@@ -979,7 +974,7 @@ string MainLoop::executeHex(vector<string> &args) {
if (isMaster(master[1])) { if (isMaster(master[1])) {
return getResultCode(RESULT_OK); return getResultCode(RESULT_OK);
} }
return slave.getDataStr(true, false); return slave.getDataStr();
} }
logError(lf_main, "hex: %s", getResultCode(ret)); logError(lf_main, "hex: %s", getResultCode(ret));
return getResultCode(ret); return getResultCode(ret);
@@ -1171,13 +1166,13 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
result << "no data stored"; result << "no data stored";
} else if (hexFormat) { } else if (hexFormat) {
result << message->getLastMasterData().getDataStr() result << message->getLastMasterData().getDataStr()
<< " / " << message->getLastSlaveData().getDataStr(true, false); << " / " << message->getLastSlaveData().getDataStr();
} else { } else {
result_t ret = message->decodeLastData(result, verbosity); result_t ret = message->decodeLastData(result, verbosity);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
result << " (" << getResultCode(ret) result << " (" << getResultCode(ret)
<< " for " << message->getLastMasterData().getDataStr() << " for " << message->getLastMasterData().getDataStr()
<< " / " << message->getLastSlaveData().getDataStr(true, false) << ")"; << " / " << message->getLastSlaveData().getDataStr() << ")";
} }
} }
if (verbosity == (OF_NAMES|OF_UNITS|OF_COMMENTS)) { if (verbosity == (OF_NAMES|OF_UNITS|OF_COMMENTS)) {
@@ -1310,7 +1305,7 @@ string MainLoop::executeScan(vector<string> &args, string levels) {
if (result != RESULT_OK) { if (result != RESULT_OK) {
return getResultCode(result); return getResultCode(result);
} }
SymbolString slave(false); SymbolString slave;
result = m_busHandler->scanAndWait(dstAddress, slave); result = m_busHandler->scanAndWait(dstAddress, slave);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return getResultCode(result); return getResultCode(result);
Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 92 KiB

+10 -10
View File
@@ -77,14 +77,14 @@ int main() {
string check[5] = checks[i]; string check[5] = checks[i];
istringstream isstr(check[0]); istringstream isstr(check[0]);
string expectStr = check[1]; string expectStr = check[1];
SymbolString mstr(false); SymbolString mstr(true);
result_t result = mstr.parseHex(check[2]); result_t result = mstr.parseHex(check[2]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
error = true; error = true;
continue; continue;
} }
SymbolString sstr(false); SymbolString sstr;
result = sstr.parseHex(check[3]); result = sstr.parseHex(check[3]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
@@ -130,17 +130,17 @@ int main() {
cout << "\": create OK" << endl; cout << "\": create OK" << endl;
ostringstream output; ostringstream output;
SymbolString writeMstr(false); SymbolString writeMstr(true);
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10)); result = writeMstr.parseHex(mstr.getDataStr().substr(0, 10));
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) cout << " parse \"" << mstr.getDataStr().substr(0, 10) << "\" error: " << getResultCode(result)
<< endl; << endl;
error = true; error = true;
} }
SymbolString writeSstr(false); SymbolString writeSstr;
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2)); result = writeSstr.parseHex(sstr.getDataStr().substr(0, 2));
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) cout << " parse \"" << sstr.getDataStr().substr(0, 2) << "\" error: " << getResultCode(result)
<< endl; << endl;
error = true; error = true;
} }
@@ -186,8 +186,8 @@ int main() {
error = true; error = true;
} else { } else {
bool match = mstr == writeMstr && sstr == writeSstr; bool match = mstr == writeMstr && sstr == writeSstr;
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr() + " "
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false)); + sstr.getDataStr(), writeMstr.getDataStr() + " " + writeSstr.getDataStr());
} }
delete fields; delete fields;
fields = NULL; fields = NULL;
+4 -4
View File
@@ -163,7 +163,7 @@ class DataField {
/** /**
* Reads the numeric value from the @a SymbolString. * Reads the numeric value from the @a SymbolString.
* @param partType the @a PartType of the data. * @param partType the @a PartType of the data.
* @param data the unescaped data @a SymbolString for reading binary data. * @param data the data @a SymbolString for reading binary data.
* @param offset the additional offset to add for reading binary data. * @param offset the additional offset to add for reading binary data.
* @param output the variable in which to store the numeric value. * @param output the variable in which to store the numeric value.
* @param fieldName the name of the field to read, or NULL for the first field. * @param fieldName the name of the field to read, or NULL for the first field.
@@ -180,7 +180,7 @@ class DataField {
/** /**
* Reads the value from the @a SymbolString. * Reads the value from the @a SymbolString.
* @param partType the @a PartType of the data. * @param partType the @a PartType of the data.
* @param data the unescaped data @a SymbolString for reading binary data. * @param data the data @a SymbolString for reading binary data.
* @param offset the additional offset to add for reading binary data. * @param offset the additional offset to add for reading binary data.
* @param output the @a ostringstream to append the formatted value to. * @param output the @a ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
@@ -332,7 +332,7 @@ class SingleDataField : public DataField {
protected: protected:
/** /**
* Internal method for reading the field from a @a SymbolString. * Internal method for reading the field from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param isMaster whether the @a SymbolString is the master part. * @param isMaster whether the @a SymbolString is the master part.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param output the ostringstream to append the formatted value to. * @param output the ostringstream to append the formatted value to.
@@ -347,7 +347,7 @@ class SingleDataField : public DataField {
* Internal method for writing the field to a @a SymbolString. * Internal method for writing the field to a @a SymbolString.
* @param input the @a istringstream to parse the formatted value from. * @param input the @a istringstream to parse the formatted value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param output the unescaped @a SymbolString to write the binary value to. * @param output the @a SymbolString to write the binary value to.
* @param isMaster whether the @a SymbolString is the master part. * @param isMaster whether the @a SymbolString is the master part.
* @param usedLength the variable in which to store the used length in bytes, or NULL. * @param usedLength the variable in which to store the used length in bytes, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
-44
View File
@@ -40,50 +40,6 @@ using std::setfill;
using std::setprecision; using std::setprecision;
using std::setw; using std::setw;
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
result_t& result, unsigned int* length) {
char* strEnd = NULL;
unsigned long ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL) {
*length = (unsigned int)(strEnd - str);
}
result = RESULT_OK;
return (unsigned int)ret;
}
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
unsigned int* length) {
char* strEnd = NULL;
long ret = strtol(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL) {
*length = (unsigned int)(strEnd - str);
}
result = RESULT_OK;
return static_cast<int>(ret);
}
void printErrorPos(ostream& out, vector<string>::iterator begin, const vector<string>::iterator end, 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) { vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
if (pos > begin) { if (pos > begin) {
+8 -32
View File
@@ -123,7 +123,8 @@ enum PartType {
/** bit flag for @a DataType: value may not be NULL. */ /** bit flag for @a DataType: value may not be NULL. */
#define REQ 0x40 #define REQ 0x40
/** bit flag for @a DataType: binary representation is hex converted to decimal and interpreted as 2 digits (also requires #BCD). */ /** bit flag for @a DataType: binary representation is hex converted to decimal and interpreted as 2 digits
* (also requires #BCD). */
#define HCD 0x80 #define HCD 0x80
/** bit flag for @a DataType: exponential numeric representation. */ /** bit flag for @a DataType: exponential numeric representation. */
@@ -142,32 +143,6 @@ enum PartType {
#define CON 0x1000 #define CON 0x1000
/**
* Parse an unsigned int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
* @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);
/**
* Parse a signed int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
* @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);
/** /**
* Print the error position of the iterator. * Print the error position of the iterator.
* @param out the @a ostream to print to. * @param out the @a ostream to print to.
@@ -253,7 +228,7 @@ class DataType {
/** /**
* Internal method for reading the numeric raw value from a @a SymbolString. * Internal method for reading the numeric raw value from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to read. * @param length the number of symbols to read.
* @param value the variable in which to store the numeric raw value. * @param value the variable in which to store the numeric raw value.
@@ -265,7 +240,7 @@ class DataType {
/** /**
* Internal method for reading the field from a @a SymbolString. * Internal method for reading the field from a @a SymbolString.
* @param input the unescaped @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param isMaster whether the @a SymbolString is the master part. * @param isMaster whether the @a SymbolString is the master part.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to read. * @param length the number of symbols to read.
@@ -282,7 +257,7 @@ class DataType {
* @param input the @a istringstream to parse the formatted value from. * @param input the @a istringstream to parse the formatted value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to write, or @a REMAIN_LEN. * @param length the number of symbols to write, or @a REMAIN_LEN.
* @param output the unescaped @a SymbolString to write the binary value to. * @param output the @a SymbolString to write the binary value to.
* @param isMaster whether the @a SymbolString is the master part. * @param isMaster whether the @a SymbolString is the master part.
* @param usedLength the variable in which to store the used length in bytes, or NULL. * @param usedLength the variable in which to store the used length in bytes, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
@@ -369,7 +344,8 @@ class DateTimeDataType : public DataType {
*/ */
DateTimeDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement, DateTimeDataType(const string id, const unsigned char bitCount, const uint16_t flags, const unsigned int replacement,
const bool hasDate, const bool hasTime, const int16_t resolution) const bool hasDate, const bool hasTime, const int16_t resolution)
: DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime), m_resolution(resolution == 0 ? 1 : resolution) {} : DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime),
m_resolution(resolution == 0 ? 1 : resolution) {}
/** /**
* Destructor. * Destructor.
@@ -521,7 +497,7 @@ class NumberDataType : public DataType {
* @param value the numeric raw value to write. * @param value the numeric raw value to write.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to write, or @a REMAIN_LEN. * @param length the number of symbols to write, or @a REMAIN_LEN.
* @param output the unescaped @a SymbolString to write the binary value to. * @param output the @a SymbolString to write the binary value to.
* @param usedLength the variable in which to store the used length in bytes, * @param usedLength the variable in which to store the used length in bytes,
* or NULL. * or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
+27 -61
View File
@@ -590,43 +590,29 @@ bool Message::hasField(const char* fieldName, bool numeric) {
return m_data->hasField(fieldName, numeric); return m_data->hasField(fieldName, numeric);
} }
result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& masterData, result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& master,
istringstream& input, char separator, istringstream& input, char separator,
const unsigned char dstAddress, unsigned char index) { const unsigned char dstAddress, unsigned char index) {
if (m_isPassive) { if (m_isPassive) {
return RESULT_ERR_INVALID_ARG; // prepare not possible return RESULT_ERR_INVALID_ARG; // prepare not possible
} }
SymbolString master(false); master.clear();
result_t result = master.push_back(srcAddress, false, false); master.push_back(srcAddress);
if (result != RESULT_OK) {
return result;
}
if (dstAddress == SYN) { if (dstAddress == SYN) {
if (m_dstAddress == SYN) { if (m_dstAddress == SYN) {
return RESULT_ERR_INVALID_ADDR; return RESULT_ERR_INVALID_ADDR;
} }
result = master.push_back(m_dstAddress, false, false); master.push_back(m_dstAddress);
} else { } else {
result = master.push_back(dstAddress, false, false); master.push_back(dstAddress);
} }
master.push_back(m_id[0]);
master.push_back(m_id[1]);
result_t result = prepareMasterPart(master, input, separator, index);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
result = master.push_back(m_id[0], false, false); result = storeLastData(pt_masterData, master, index);
if (result != RESULT_OK) {
return result;
}
result = master.push_back(m_id[1], false, false);
if (result != RESULT_OK) {
return result;
}
result = prepareMasterPart(master, input, separator, index);
if (result != RESULT_OK) {
return result;
}
masterData.clear();
masterData.addAll(master);
result = storeLastData(pt_masterData, masterData, index);
if (result < RESULT_OK) { if (result < RESULT_OK) {
return result; return result;
} }
@@ -638,17 +624,11 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
unsigned char pos = master.size(); unsigned char pos = master.size();
result_t result = master.push_back(0, false, false); // length, will be set later master.push_back(0); // length, will be set later
if (result != RESULT_OK) {
return result;
}
for (size_t i = 2; i < m_id.size(); i++) { for (size_t i = 2; i < m_id.size(); i++) {
result = master.push_back(m_id[i], false, false); master.push_back(m_id[i]);
if (result != RESULT_OK) {
return result;
} }
} result_t result = m_data->write(input, pt_masterData, master, getIdLength(), separator);
result = m_data->write(input, pt_masterData, master, getIdLength(), separator);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -656,16 +636,13 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
return result; return result;
} }
result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) { result_t Message::prepareSlave(istringstream& input, SymbolString& slave) {
if (m_isWrite) { if (m_isWrite) {
return RESULT_ERR_INVALID_ARG; // prepare not possible return RESULT_ERR_INVALID_ARG; // prepare not possible
} }
SymbolString slave(false); slave.clear();
result_t result = slave.push_back(0, false, false); // length, will be set later slave.push_back(0); // length, will be set later
if (result != RESULT_OK) { result_t result = m_data->write(input, pt_slaveData, slave, 0);
return result;
}
result = m_data->write(input, pt_slaveData, slave, 0);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -675,8 +652,6 @@ result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) {
m_lastChangeTime = m_lastUpdateTime; m_lastChangeTime = m_lastUpdateTime;
m_lastSlaveData = slave; m_lastSlaveData = slave;
} }
slaveData.clear();
slaveData.addAll(slave);
return result; return result;
} }
@@ -695,7 +670,7 @@ result_t Message::storeLastData(const PartType partType, SymbolString& data, uns
time(&m_lastUpdateTime); time(&m_lastUpdateTime);
} }
if (partType == pt_masterData) { if (partType == pt_masterData) {
switch (data.compareMaster(m_lastMasterData)) { switch (data.compareTo(m_lastMasterData)) {
case 1: // completely different case 1: // completely different
m_lastChangeTime = m_lastUpdateTime; m_lastChangeTime = m_lastUpdateTime;
m_lastMasterData = data; m_lastMasterData = data;
@@ -903,7 +878,7 @@ ChainedMessage::ChainedMessage(const string circuit, const string level, const s
m_lastMasterUpdateTimes = reinterpret_cast<time_t*>(calloc(cnt, sizeof(time_t))); m_lastMasterUpdateTimes = reinterpret_cast<time_t*>(calloc(cnt, sizeof(time_t)));
m_lastSlaveUpdateTimes = reinterpret_cast<time_t*>(calloc(cnt, sizeof(time_t))); m_lastSlaveUpdateTimes = reinterpret_cast<time_t*>(calloc(cnt, sizeof(time_t)));
for (size_t index = 0; index < cnt; index++) { for (size_t index = 0; index < cnt; index++) {
m_lastMasterDatas[index] = new SymbolString(); m_lastMasterDatas[index] = new SymbolString(true);
m_lastSlaveDatas[index] = new SymbolString(); m_lastSlaveDatas[index] = new SymbolString();
} }
} }
@@ -1000,7 +975,7 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
if (index >= cnt) { if (index >= cnt) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
SymbolString allData(false); SymbolString allData(true);
result_t result = m_data->write(input, pt_masterData, allData, 0, separator); result_t result = m_data->write(input, pt_masterData, allData, 0, separator);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
@@ -1017,21 +992,12 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
return RESULT_ERR_INVALID_POS; return RESULT_ERR_INVALID_POS;
} }
vector<unsigned char> id = m_ids[index]; vector<unsigned char> id = m_ids[index];
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN master.push_back((unsigned char)(id.size()-2+addData)); // NN
if (result != RESULT_OK) {
return result;
}
for (size_t i = 2; i < id.size(); i++) { for (size_t i = 2; i < id.size(); i++) {
result = master.push_back(id[i], false, false); master.push_back(id[i]);
if (result != RESULT_OK) {
return result;
}
} }
for (size_t i = 0; i < addData; i++) { for (size_t i = 0; i < addData; i++) {
result = master.push_back(allData[pos+i], false, false); master.push_back(allData[pos+i]);
if (result != RESULT_OK) {
return result;
}
} }
if (index == 0) { if (index == 0) {
for (size_t i = 0; i < cnt; i++) { for (size_t i = 0; i < cnt; i++) {
@@ -1059,7 +1025,7 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
if (partType == pt_masterData) { if (partType == pt_masterData) {
switch (data.compareMaster(*m_lastMasterDatas[index])) { switch (data.compareTo(*m_lastMasterDatas[index])) {
case 1: // completely different case 1: // completely different
*m_lastMasterDatas[index] = data; *m_lastMasterDatas[index] = data;
break; break;
@@ -1098,19 +1064,19 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
} }
} }
// everything was completely retrieved in short time // everything was completely retrieved in short time
SymbolString master(false); SymbolString master(true);
SymbolString slave(false); SymbolString slave;
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
for (index = 0; index < m_ids.size(); index++) { for (index = 0; index < m_ids.size(); index++) {
SymbolString* add = m_lastMasterDatas[index]; SymbolString* add = m_lastMasterDatas[index];
size_t end = 5+(*add)[4]; size_t end = 5+(*add)[4];
for (size_t pos = index == 0 ? 0 : offset; pos < end; pos++) { for (size_t pos = index == 0 ? 0 : offset; pos < end; pos++) {
master.push_back((*add)[pos], false, false); master.push_back((*add)[pos]);
} }
add = m_lastSlaveDatas[index]; add = m_lastSlaveDatas[index];
end = 1+(*add)[0]; end = 1+(*add)[0];
for (size_t pos = index == 0 ? 0 : 1; pos < end; pos++) { for (size_t pos = index == 0 ? 0 : 1; pos < end; pos++) {
slave.push_back((*add)[pos], false, false); slave.push_back((*add)[pos]);
} }
} }
// adjust NN // adjust NN
+5 -5
View File
@@ -421,14 +421,14 @@ class Message {
/** /**
* Prepare the master @a SymbolString for sending a query or command to the bus. * Prepare the master @a SymbolString for sending a query or command to the bus.
* @param srcAddress the source address to set. * @param srcAddress the source address to set.
* @param masterData the master data @a SymbolString for writing symbols to. * @param master the master data @a SymbolString for writing symbols to.
* @param input the @a istringstream to parse the formatted value(s) from. * @param input the @a istringstream to parse the formatted value(s) from.
* @param separator the separator character between multiple fields. * @param separator the separator character between multiple fields.
* @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction. * @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction.
* @param index the index of the part to prepare. * @param index the index of the part to prepare.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData, result_t prepareMaster(const unsigned char srcAddress, SymbolString& master,
istringstream& input, char separator = UI_FIELD_SEPARATOR, istringstream& input, char separator = UI_FIELD_SEPARATOR,
const unsigned char dstAddress = SYN, unsigned char index = 0); const unsigned char dstAddress = SYN, unsigned char index = 0);
@@ -449,10 +449,10 @@ class Message {
/** /**
* Prepare the slave @a SymbolString for sending an answer to the bus. * Prepare the slave @a SymbolString for sending an answer to the bus.
* @param input the @a istringstream to parse the formatted value(s) from. * @param input the @a istringstream to parse the formatted value(s) from.
* @param slaveData the slave data @a SymbolString for writing symbols to. * @param slave the slave data @a SymbolString for writing symbols to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t prepareSlave(istringstream& input, SymbolString& slaveData); virtual result_t prepareSlave(istringstream& input, SymbolString& slave);
/** /**
* Store the last seen master and slave data. * Store the last seen master and slave data.
@@ -631,7 +631,7 @@ class Message {
Condition* m_condition; Condition* m_condition;
/** the last seen master data. */ /** the last seen master data. */
SymbolString m_lastMasterData; SymbolString m_lastMasterData{true};
/** the last seen slave data. */ /** the last seen slave data. */
SymbolString m_lastSlaveData; SymbolString m_lastSlaveData;
+1
View File
@@ -49,6 +49,7 @@ const char* getResultCode(result_t resultCode) {
case RESULT_ERR_NAK: return "ERR: NAK received"; case RESULT_ERR_NAK: return "ERR: NAK received";
case RESULT_ERR_NO_SIGNAL: return "ERR: no signal"; case RESULT_ERR_NO_SIGNAL: return "ERR: no signal";
case RESULT_ERR_SYN: return "ERR: SYN received"; case RESULT_ERR_SYN: return "ERR: SYN received";
case RESULT_ERR_SYMBOL: return "ERR: wrong symbol received";
case RESULT_ERR_NOTAUTHORIZED: return "ERR: not authorized"; case RESULT_ERR_NOTAUTHORIZED: return "ERR: not authorized";
default: default:
+3 -2
View File
@@ -33,7 +33,7 @@ namespace ebusd {
enum result_t { enum result_t {
RESULT_OK = 0, //!< success RESULT_OK = 0, //!< success
RESULT_CONTINUE = 1, //!< more input data is needed (e.g. start of escape sequence received) RESULT_CONTINUE = 1, //!< more input data is needed
RESULT_EMPTY = 2, //!< empty result RESULT_EMPTY = 2, //!< empty result
RESULT_ERR_GENERIC_IO = -1, //!< generic I/O error (usually fatal) RESULT_ERR_GENERIC_IO = -1, //!< generic I/O error (usually fatal)
@@ -62,8 +62,9 @@ enum result_t {
RESULT_ERR_NO_SIGNAL = -22, //!< no signal found on the bus RESULT_ERR_NO_SIGNAL = -22, //!< no signal found on the bus
RESULT_ERR_SYN = -23, //!< SYN received instead of answer RESULT_ERR_SYN = -23, //!< SYN received instead of answer
RESULT_ERR_SYMBOL = -24, //!< wrong symbol received instead of sent symbol
RESULT_ERR_NOTAUTHORIZED = -24 //!< not authorized for this action RESULT_ERR_NOTAUTHORIZED = -25 //!< not authorized for this action
}; };
+94 -115
View File
@@ -54,64 +54,103 @@ static const unsigned char CRC_LOOKUP_TABLE[] = {
}; };
void SymbolString::addAll(const SymbolString& str, bool skipLastSymbol) { unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
bool addCrc = m_unescapeState == 0; result_t& result, unsigned int* length) {
bool isEscaped = str.m_unescapeState == 0;
vector<unsigned char> data = str.m_data;
size_t end = data.size();
if (end > 0 && skipLastSymbol) {
end--;
}
for (size_t i = 0; i < end; i++) {
push_back(data[i], isEscaped, addCrc);
}
if (addCrc) {
push_back(m_crc, false, false); // add CRC
}
}
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; char* strEnd = NULL;
const char* strBegin = str.substr(i, 2).c_str();
unsigned long value = strtoul(strBegin, &strEnd, 16);
if (strEnd == NULL || strEnd != strBegin+2 || value > 0xff) { unsigned long ret = strtoul(str, &strEnd, base);
return RESULT_ERR_INVALID_NUM; // invalid value
if (strEnd == NULL || strEnd == str || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
} }
push_back((unsigned char)value, isEscaped, addCrc);
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
} }
if (addCrc) { if (length != NULL) {
push_back(m_crc, false, false); // add CRC *length = (unsigned int)(strEnd - str);
}
result = RESULT_OK;
return (unsigned int)ret;
}
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
unsigned int* length) {
char* strEnd = NULL;
long ret = strtol(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL) {
*length = (unsigned int)(strEnd - str);
}
result = RESULT_OK;
return static_cast<int>(ret);
}
void SymbolString::updateCrc(unsigned char& crc, const unsigned char value) {
crc = CRC_LOOKUP_TABLE[crc]^value;
}
result_t SymbolString::parseHex(const string& str) {
result_t result;
for (size_t i = 0; i < str.size(); i += 2) {
unsigned char value = (unsigned char)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK) {
return result;
}
m_data.push_back(value);
} }
return RESULT_OK; return RESULT_OK;
} }
const string SymbolString::getDataStr(const bool unescape, const bool skipLastSymbol, result_t SymbolString::parseHexEscaped(const string& str) {
unsigned char skipFirstSymbols) { result_t result;
bool previousEscape = false; bool inEscape = false;
for (size_t i = 0; i < str.size(); i += 2) {
unsigned char value = (unsigned char)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK) {
return result;
}
if (inEscape) {
if (value == 0x00) {
m_data.push_back(ESC);
inEscape = false;
} else if (value == 0x01) {
m_data.push_back(SYN);
inEscape = false;
} else {
return RESULT_ERR_ESC; // invalid escape sequence
}
} else if (value == ESC) {
inEscape = true;
} else if (value == SYN) {
return RESULT_ERR_ESC; // invalid escape sequence
} else {
m_data.push_back(value);
}
}
return inEscape ? RESULT_ERR_ESC : RESULT_OK;
}
const string SymbolString::getDataStr(unsigned char skipFirstSymbols) {
ostringstream sstr; ostringstream sstr;
for (size_t i = 0; i < m_data.size(); i++) { for (size_t i = 0; i < m_data.size(); i++) {
unsigned char value = m_data[i];
if (m_unescapeState == 0 && unescape && previousEscape) {
if (skipFirstSymbols > 0) { if (skipFirstSymbols > 0) {
skipFirstSymbols--; skipFirstSymbols--;
} else if (!skipLastSymbol || i+1 < m_data.size()) {
if (value == 0x00) {
sstr << "a9"; // ESC
} else if (value == 0x01) {
sstr << "aa"; // SYN
} else { } else {
sstr << "XX"; // invalid escape sequence unsigned char value = m_data[i];
}
}
previousEscape = false;
} else if (m_unescapeState == 0 && unescape && value == ESC) {
previousEscape = true; // escape sequence not yet finished
} else if (skipFirstSymbols > 0) {
skipFirstSymbols--;
} else if (!skipLastSymbol || i+1 < m_data.size()) {
sstr << nouppercase << setw(2) << hex sstr << nouppercase << setw(2) << hex
<< setfill('0') << static_cast<unsigned>(value); << setfill('0') << static_cast<unsigned>(value);
} }
@@ -119,82 +158,22 @@ const string SymbolString::getDataStr(const bool unescape, const bool skipLastSy
return sstr.str(); return sstr.str();
} }
result_t SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC) { unsigned char SymbolString::calcCrc() const {
if (m_unescapeState == 0) { // store escaped data unsigned char crc = 0;
if (!isEscaped && value == ESC) { for (size_t i = 0; i < m_data.size(); i++) {
m_data.push_back(ESC); unsigned char value = m_data[i];
m_data.push_back(0x00);
if (updateCRC) {
addCRC(ESC);
addCRC(0x00);
}
} else if (!isEscaped && value == SYN) {
m_data.push_back(ESC);
m_data.push_back(0x01);
if (updateCRC) {
addCRC(ESC);
addCRC(0x01);
}
} else {
m_data.push_back(value);
if (updateCRC) {
addCRC(value);
}
}
return RESULT_OK;
}
if (!isEscaped) {
if (m_unescapeState != 1) {
return RESULT_ERR_ESC; // invalid unescape state
}
m_data.push_back(value);
if (updateCRC) {
if (value == ESC) { if (value == ESC) {
addCRC(ESC); updateCrc(crc, ESC);
addCRC(0x00); updateCrc(crc, 0x00);
} else if (value == SYN) { } else if (value == SYN) {
addCRC(ESC); updateCrc(crc, ESC);
addCRC(0x01); updateCrc(crc, 0x01);
} else { } else {
addCRC(value); updateCrc(crc, value);
} }
} }
return RESULT_OK; return crc;
} }
if (m_unescapeState != 1) {
if (updateCRC) {
addCRC(value);
}
if (value == 0x00) {
m_data.push_back(ESC);
m_unescapeState = 1;
return RESULT_OK;
}
if (value == 0x01) {
m_data.push_back(SYN);
m_unescapeState = 1;
return RESULT_OK;
}
return RESULT_ERR_ESC; // invalid escape sequence
}
if (value == ESC) {
if (updateCRC) {
addCRC(value);
}
m_unescapeState = 2;
return RESULT_CONTINUE;
}
if (updateCRC) {
addCRC(value);
}
m_data.push_back(value);
return RESULT_OK;
}
void SymbolString::addCRC(const unsigned char value) {
m_crc = CRC_LOOKUP_TABLE[m_crc]^value;
}
/** /**
+95 -62
View File
@@ -32,9 +32,9 @@ namespace ebusd {
/** @file lib/ebus/symbol.h /** @file lib/ebus/symbol.h
* Classes, functions, and constants related to symbols on the eBUS. * Classes, functions, and constants related to symbols on the eBUS.
* *
* The @a SymbolString class is used for escaping or unescaping a sequence of * The @a SymbolString class is used for holding a sequence of bytes received
* bytes in preparation for sending to the bus or after reception of bytes from * from or sent to the bus, as well as calculating and verifying the CRC of a
* the bus, as well as calculating and verifying the CRC of a message part. * message part.
* *
* A message on the bus always consists of a command part, i.e. the data sent * A message on the bus always consists of a command part, i.e. the data sent
* from a master to the bus. The command part starts with the sending master * from a master to the bus. The command part starts with the sending master
@@ -70,51 +70,83 @@ using std::vector;
/** escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA. */ /** escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA. */
#define ESC 0xA9 #define ESC 0xA9
/** synchronization symbol. */ /** synchronization symbol. */
#define SYN 0xAA #define SYN 0xAA
/** positive acknowledge symbol. */ /** positive acknowledge symbol. */
#define ACK 0x00 #define ACK 0x00
/** negative acknowledge symbol. */ /** negative acknowledge symbol. */
#define NAK 0xFF #define NAK 0xFF
/** the broadcast destination address. */ /** the broadcast destination address. */
#define BROADCAST 0xFE #define BROADCAST 0xFE
/**
* Parse an unsigned int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
* @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);
/** /**
* A string of escaped or unescaped bus symbols. * Parse a signed int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
* @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);
/**
* A string of unescaped bus symbols.
*/ */
class SymbolString { class SymbolString {
public: public:
/** /**
* Creates a new empty escaped or unescaped instance. * Creates a new empty instance.
* @param escaped whether to create an escaped instance. * @param isMaster whether this instance if for the master part.
*/ */
explicit SymbolString(const bool escaped = true) : m_unescapeState(escaped ? 0 : 1), m_crc(0) {} explicit SymbolString(const bool isMaster = false) { m_isMaster = isMaster; }
/** /**
* Add all symbols from the other @a SymbolString and the calculated CRC if escaped. * Update the CRC by adding a value.
* @param str the @a SymbolString to copy from. * @param crc the current CRC to update.
* @param skipLastSymbol whether to skip the last symbol (probably the CRC). * @param value the escaped value to add to the current CRC.
*/ */
void addAll(const SymbolString& str, const bool skipLastSymbol = false); static void updateCrc(unsigned char& crc, const unsigned char value);
/** /**
* Parse the escaped or unescaped hex @a string, add all symbols, and add the calculated CRC if escaped. * Parse the hex @a string and add all symbols.
* @param str the hex @a string. * @param str the hex @a string.
* @param isEscaped whether the hex string is escaped.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t parseHex(const string& str, const bool isEscaped = false); result_t parseHex(const string& str);
/**
* Parse the escaped hex @a string and add all symbols.
* @param str the hex @a string.
* @return @a RESULT_OK on success, or an error code.
*/
result_t parseHexEscaped(const string& str);
/** /**
* Return the symbols as hex string. * Return the symbols as hex string.
* @param unescape whether to unescape an escaped instance.
* @param skipLastSymbol whether to skip the last symbol (probably the CRC).
* @param skipFirstSymbols the number of first symbols to skip. * @param skipFirstSymbols the number of first symbols to skip.
* @return the symbols as hex string. * @return the symbols as hex string.
*/ */
const string getDataStr(const bool unescape = true, const bool skipLastSymbol = true, const string getDataStr(unsigned char skipFirstSymbols = 0);
unsigned char skipFirstSymbols = 0);
/** /**
* Return a reference to the symbol at the specified index. * Return a reference to the symbol at the specified index.
@@ -131,11 +163,10 @@ class SymbolString {
/** /**
* Return whether this instance is equal to the other instance. * Return whether this instance is equal to the other instance.
* @param other the other instance. * @param other the other instance.
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same * @return true if this instance is equal to the other instance.
* symbols).
*/ */
bool operator == (SymbolString& other) { bool operator == (SymbolString& other) {
return m_unescapeState == other.m_unescapeState && m_data == other.m_data; return m_isMaster == other.m_isMaster && m_data == other.m_data;
} }
/** /**
@@ -144,24 +175,26 @@ class SymbolString {
* @return true if this instance is different from the other instance. * @return true if this instance is different from the other instance.
*/ */
bool operator != (SymbolString& other) { bool operator != (SymbolString& other) {
return m_unescapeState != other.m_unescapeState || m_data != other.m_data; return m_isMaster != other.m_isMaster || m_data != other.m_data;
} }
/** /**
* Compares this instance to the other instance while treating both as master data (i.e. starting with the master * Compare the data in this instance to that of the other instance.
* address and ending with the CRC).
* @param other the other instance. * @param other the other instance.
* @return 0 if this instance is equal to the other instance (i.e. both escaped or both unescaped and same symbols), * @return 0 if the data is equal,
* 1 if this instance is completely different to the other instance, * 1 if the data is completely different,
* 2 if this instance only differs from the other instance in the first byte (the master address). * 2 if both instances are a master part and the data only differs in the first byte (the master address).
*/ */
int compareMaster(SymbolString& other) { int compareTo(SymbolString& other) {
if (m_unescapeState != other.m_unescapeState || m_data.size() != other.m_data.size()) { if (m_data.size() != other.m_data.size()) {
return 1; return 1;
} }
if (m_data == other.m_data) { if (m_data == other.m_data) {
return 0; return 0;
} }
if (!m_isMaster) {
return 1;
}
if (m_data.size() == 1) { if (m_data.size() == 1) {
return 2; return 2;
} }
@@ -172,15 +205,10 @@ class SymbolString {
} }
/** /**
* Appends a the symbol to the end of the symbol string and escapes/unescapes it if necessary. * Append a symbol to the end of the symbol string.
* @param value the symbol to append. * @param value the symbol to append.
* @param isEscaped whether the symbol is escaped.
* @param updateCRC whether to update the calculated CRC in @a m_crc.
* @return RESULT_OK if another symbol was appended,
* RESULT_IN_ESC if this is an unescaped instance and the symbol is escaped and the start of the escape sequence was
* received, RESULT_ERR_ESC if this is an unescaped instance and an invalid escaped sequence was detected.
*/ */
result_t push_back(const unsigned char value, const bool isEscaped = true, const bool updateCRC = true); void push_back(const unsigned char value) { m_data.push_back(value); }
/** /**
* Return the number of symbols in this symbol string. * Return the number of symbols in this symbol string.
@@ -189,21 +217,39 @@ class SymbolString {
unsigned char size() const { return (unsigned char)m_data.size(); } unsigned char size() const { return (unsigned char)m_data.size(); }
/** /**
* Return the calculated CRC. * Return the offset to the first data byte DD.
* @return the offset to the first data byte DD.
*/
unsigned char getDataOffset() const { return m_isMaster ? 5 : 1; }
/**
* Return the number of data bytes DD.
* @return the number of data bytes DD.
*/
unsigned char getDataSize() const { return m_data.size() > (m_isMaster ? 4 : 0) ? m_data[m_isMaster ? 4 : 0] : 0; }
/**
* Return whether the byte sequence is complete with regard to the header and length field.
* @return true if the sequence is complete.
*/
bool isComplete() {
size_t lengthOffset = (m_isMaster ? 4 : 0);
if (m_data.size() < lengthOffset + 1) {
return false;
}
return m_data.size() >= lengthOffset + 1 + m_data[lengthOffset];
}
/**
* Calculate the CRC.
* @return the calculated CRC. * @return the calculated CRC.
*/ */
unsigned char getCRC() const { return m_crc; } unsigned char calcCrc() const;
/** /**
* Clear the symbols. * Clear the symbols.
*/ */
void clear() { m_data.clear(); m_unescapeState = m_unescapeState == 0 ? 0 : 1; m_crc = 0; } void clear() { m_data.clear(); }
/**
* Clear the symbols and adjust the escape mode.
* @param escape true to set to an escaped instance, false to set to an unescaped instance.
*/
void clear(const bool escape) { m_data.clear(); m_unescapeState = escape ? 0 : 1; m_crc = 0; }
private: private:
@@ -212,26 +258,13 @@ class SymbolString {
* @param str the @a SymbolString to copy from. * @param str the @a SymbolString to copy from.
*/ */
SymbolString(const SymbolString& str) SymbolString(const SymbolString& str)
: m_data(str.m_data), m_unescapeState(str.m_unescapeState), m_crc(str.m_crc) {} : m_data(str.m_data), m_isMaster(str.m_isMaster) {}
/** /** the string of unescaped symbols. */
* Update the calculated CRC in @a m_crc by adding a value.
* @param value the (escaped) value to add to the calculated CRC in @a m_crc.
*/
void addCRC(const unsigned char value);
/** the string of bus symbols. */
vector<unsigned char> m_data; vector<unsigned char> m_data;
/** /** whether this instance if for the master part. */
* 0 if the symbols in @a m_data are escaped, bool m_isMaster;
* 1 if the symbols in @a m_data are unescaped and the last symbol passed to @a push_back was a normal symbol,
* 2 if the symbols in @a m_data are unescaped and the last symbol passed to @a push_back was the escape symbol.
*/
int m_unescapeState;
/** the calculated CRC. */
unsigned char m_crc;
}; };
+11 -11
View File
@@ -473,14 +473,14 @@ int main() {
string check[5] = checks[i]; string check[5] = checks[i];
istringstream isstr(check[0]); istringstream isstr(check[0]);
string expectStr = check[1]; string expectStr = check[1];
SymbolString mstr(false); SymbolString mstr(true);
result_t result = mstr.parseHex(check[2]); result_t result = mstr.parseHex(check[2]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
error = true; error = true;
continue; continue;
} }
SymbolString sstr(false); SymbolString sstr;
result = sstr.parseHex(check[3]); result = sstr.parseHex(check[3]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
@@ -563,17 +563,17 @@ int main() {
} }
ostringstream output; ostringstream output;
SymbolString writeMstr(false); SymbolString writeMstr(true);
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10)); result = writeMstr.parseHex(mstr.getDataStr().substr(0, 10));
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " parse \"" << mstr.getDataStr(true, false).substr(0, 10) << "\" error: " << getResultCode(result) cout << " parse \"" << mstr.getDataStr().substr(0, 10) << "\" error: " << getResultCode(result)
<< endl; << endl;
error = true; error = true;
} }
SymbolString writeSstr(false); SymbolString writeSstr;
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2)); result = writeSstr.parseHex(sstr.getDataStr().substr(0, 2));
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) cout << " parse \"" << sstr.getDataStr().substr(0, 2) << "\" error: " << getResultCode(result)
<< endl; << endl;
error = true; error = true;
} }
@@ -621,9 +621,9 @@ int main() {
error = true; error = true;
} else { } else {
bool match = mstr == writeMstr && sstr == writeSstr; bool match = mstr == writeMstr && sstr == writeSstr;
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " " verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr() + " "
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + sstr.getDataStr(), writeMstr.getDataStr() + " "
+ writeSstr.getDataStr(true, false)); + writeSstr.getDataStr());
} }
} }
delete fields; delete fields;
+7 -7
View File
@@ -260,7 +260,7 @@ int main() {
} else if (mstrs[pos] != NULL) { } else if (mstrs[pos] != NULL) {
delete mstrs[pos]; delete mstrs[pos];
} }
mstrs[pos] = new SymbolString(false); mstrs[pos] = new SymbolString(true);
result = mstrs[pos]->parseHex(token); result = mstrs[pos]->parseHex(token);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl;
@@ -277,7 +277,7 @@ int main() {
} else if (sstrs[pos] != NULL) { } else if (sstrs[pos] != NULL) {
delete sstrs[pos]; delete sstrs[pos];
} }
sstrs[pos] = new SymbolString(false); sstrs[pos] = new SymbolString();
result = sstrs[pos]->parseHex(token); result = sstrs[pos]->parseHex(token);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl;
@@ -292,7 +292,7 @@ int main() {
if (mstrs[0] != NULL) { if (mstrs[0] != NULL) {
delete mstrs[0]; delete mstrs[0];
} }
mstrs[0] = new SymbolString(false); mstrs[0] = new SymbolString(true);
result = mstrs[0]->parseHex(check[2]); result = mstrs[0]->parseHex(check[2]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
@@ -301,7 +301,7 @@ int main() {
if (sstrs[0] != NULL) { if (sstrs[0] != NULL) {
delete sstrs[0]; delete sstrs[0];
} }
sstrs[0] = new SymbolString(false); sstrs[0] = new SymbolString();
result = sstrs[0]->parseHex(check[3]); result = sstrs[0]->parseHex(check[3]);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl; cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
@@ -419,7 +419,7 @@ int main() {
} }
if (!message->isPassive() && (withInput || !decode)) { if (!message->isPassive() && (withInput || !decode)) {
istringstream input(inputStr); istringstream input(inputStr);
SymbolString writeMstr(false); SymbolString writeMstr(true);
result = message->prepareMaster(0xff, writeMstr, input); result = message->prepareMaster(0xff, writeMstr, input);
if (failedPrepare) { if (failedPrepare) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
@@ -438,8 +438,8 @@ int main() {
cout << " \"" << inputStr << "\": prepare OK" << endl; cout << " \"" << inputStr << "\": prepare OK" << endl;
bool match = writeMstr == *mstrs[0]; bool match = writeMstr == *mstrs[0];
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false), verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(),
writeMstr.getDataStr(true, false)); writeMstr.getDataStr());
} }
} }
+42 -15
View File
@@ -50,26 +50,32 @@ int main(int argc, char** argv) {
SymbolString sstr(true); SymbolString sstr(true);
if (argc > 1) { if (argc > 1) {
result_t result = sstr.parseHex(argv[1], true); result_t result;
if (argc > 2 && strcmp("escaped", argv[1]) == 0) {
result = sstr.parseHexEscaped(argv[2]);
} else {
result = sstr.parseHex(argv[1]);
}
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "parse escaped error: " << getResultCode(result) << endl; cout << "parse escaped error: " << getResultCode(result) << endl;
} else { } else {
unsigned char gotCrc = sstr.getCRC(); unsigned char gotCrc = sstr.calcCrc();
cout << "calculated CRC: 0x" cout << "calculated CRC: 0x"
<< nouppercase << setw(2) << hex << setfill('0') << nouppercase << setw(2) << hex << setfill('0')
<< static_cast<unsigned>(gotCrc) << endl; << static_cast<unsigned>(gotCrc) << endl;
} }
return 0; return 0;
} }
string gotStr, expectStr; string gotStr, expectStr;
result_t result = sstr.parseHex("10feb5050427a915aa", false); result_t result = sstr.parseHex("10feb5050427a915aa");
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "parse escaped error: " << getResultCode(result) << endl; cout << "parse unescaped error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
gotStr = sstr.getDataStr(false, false), expectStr = "10feb5050427a90015a90177"; gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa";
verify(false, "parse escaped", "10feb5050427a915aa", true, expectStr, gotStr); verify(false, "parse unescaped", "10feb5050427a915aa", true, expectStr, gotStr);
unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77; unsigned char gotCrc = sstr.calcCrc(), expectCrc = 0x77;
ostringstream ostr; ostringstream ostr;
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(expectCrc); ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(expectCrc);
expectStr = ostr.str(); expectStr = ostr.str();
@@ -77,19 +83,40 @@ int main(int argc, char** argv) {
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc); ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc);
gotStr = ostr.str(); gotStr = ostr.str();
verify(false, "CRC", "10feb5050427a915aa", gotCrc == expectCrc, expectStr, gotStr); verify(false, "CRC", "10feb5050427a915aa", gotCrc == expectCrc, expectStr, gotStr);
gotStr = sstr.getDataStr(true, false), expectStr = "10feb5050427a915aa77";
verify(false, "unescape", "10feb5050427a915aa", true, expectStr, gotStr);
} }
sstr = SymbolString(false); sstr.clear();
result = sstr.parseHex("10feb5050427a90015a90177", true); result = sstr.parseHexEscaped("10feb5050427a90015a901");
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "parse unescaped error: " << getResultCode(result) << endl; cout << "parse escaped error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
gotStr = sstr.getDataStr(true, false), expectStr = "10feb5050427a915aa77"; gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa";
verify(false, "parse unescaped", "10feb5050427a90015a90177", true, expectStr, gotStr); verify(false, "parse escaped", "10feb5050427a90015a901", true, expectStr, gotStr);
ostringstream ostr;
ostr << dec << static_cast<unsigned>(4);
expectStr = ostr.str();
ostr.str("");
ostr << dec << static_cast<unsigned>(sstr.getDataSize());
gotStr = ostr.str();
verify(false, "data size", "10feb5050427a90015a901", sstr.getDataSize() == 4, expectStr, gotStr);
}
sstr = SymbolString(); // slave
result = sstr.parseHexEscaped("0427a90015a901");
if (result != RESULT_OK) {
cout << "parse escaped error: " << getResultCode(result) << endl;
error = true;
} else {
gotStr = sstr.getDataStr(), expectStr = "0427a915aa";
verify(false, "parse escaped", "0427a90015a901", true, expectStr, gotStr);
ostringstream ostr;
ostr << dec << static_cast<unsigned>(4);
expectStr = ostr.str();
ostr.str("");
ostr << dec << static_cast<unsigned>(sstr.getDataSize());
gotStr = ostr.str();
verify(false, "data size", "0427a90015a901", sstr.getDataSize() == 4, expectStr, gotStr);
} }
return error ? 1 : 0; return error ? 1 : 0;