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:
+219
-138
@@ -46,13 +46,17 @@ const char* getStateCode(BusState state) {
|
||||
case bs_skip: return "skip";
|
||||
case bs_ready: return "ready";
|
||||
case bs_sendCmd: return "send command";
|
||||
case bs_recvCmdCrc: return "receive command CRC";
|
||||
case bs_recvCmdAck: return "receive command ACK";
|
||||
case bs_recvRes: return "receive response";
|
||||
case bs_recvResCrc: return "receive response CRC";
|
||||
case bs_sendResAck: return "send response ACK";
|
||||
case bs_recvCmd: return "receive command";
|
||||
case bs_recvResAck: return "receive response ACK";
|
||||
case bs_sendCmdCrc: return "send command CRC";
|
||||
case bs_sendCmdAck: return "send command ACK";
|
||||
case bs_sendRes: return "send response";
|
||||
case bs_sendResCrc: return "send response CRC";
|
||||
case bs_sendSyn: return "send SYN";
|
||||
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());
|
||||
}
|
||||
m_result = result;
|
||||
m_slave.addAll(slave, true);
|
||||
m_slave = slave;
|
||||
return false;
|
||||
}
|
||||
|
||||
void GrabbedMessage::setLastData(SymbolString& master, SymbolString& slave) {
|
||||
m_lastMaster.clear(false);
|
||||
m_lastMaster.addAll(master);
|
||||
m_lastSlave.clear(false);
|
||||
m_lastSlave.addAll(slave);
|
||||
m_lastMaster.clear();
|
||||
m_lastMaster = master;
|
||||
m_lastSlave.clear();
|
||||
m_lastSlave = slave;
|
||||
m_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the input @a SymbolString with the specified @a DataType and length.
|
||||
* @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 baseOffset the base offset in the @a SymbolString.
|
||||
* @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,
|
||||
unsigned char offsets, ostringstream& output, bool firstOnly = false) {
|
||||
bool first = true;
|
||||
string in = input->getDataStr(true, true, baseOffset);
|
||||
string in = input->getDataStr(baseOffset);
|
||||
for (unsigned char offset = 0; offset <= offsets; offset++) {
|
||||
ostringstream out;
|
||||
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;
|
||||
result_t ret = RESULT_EMPTY;
|
||||
SymbolString master(true);
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
for (unsigned char index = 0; index < message->getCount(); index++) {
|
||||
istringstream input(inputStr);
|
||||
ret = message->prepareMaster(masterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index);
|
||||
@@ -463,11 +467,13 @@ result_t BusHandler::handleSymbol() {
|
||||
break;
|
||||
|
||||
case bs_recvCmd:
|
||||
case bs_recvCmdCrc:
|
||||
case bs_recvCmdAck:
|
||||
timeout = m_slaveRecvTimeout;
|
||||
break;
|
||||
|
||||
case bs_recvRes:
|
||||
case bs_recvResCrc:
|
||||
if (m_response.size() > 0 || m_slaveRecvTimeout > SYN_TIMEOUT) {
|
||||
timeout = m_slaveRecvTimeout;
|
||||
} else {
|
||||
@@ -481,28 +487,42 @@ result_t BusHandler::handleSymbol() {
|
||||
|
||||
case bs_sendCmd:
|
||||
if (m_currentRequest != NULL) {
|
||||
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // escaped command
|
||||
sendSymbol = m_currentRequest->m_master[m_nextSendPos]; // unescaped command
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case bs_sendCmdCrc:
|
||||
if (m_currentRequest != NULL) {
|
||||
sendSymbol = m_crc;
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case bs_sendResAck:
|
||||
if (m_currentRequest != NULL) {
|
||||
sendSymbol = m_responseCrcValid ? ACK : NAK;
|
||||
sendSymbol = m_crcValid ? ACK : NAK;
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case bs_sendCmdAck:
|
||||
if (m_answer) {
|
||||
sendSymbol = m_commandCrcValid ? ACK : NAK;
|
||||
sendSymbol = m_crcValid ? ACK : NAK;
|
||||
sending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case bs_sendRes:
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@@ -516,6 +536,14 @@ result_t BusHandler::handleSymbol() {
|
||||
// send symbol if necessary
|
||||
result_t result;
|
||||
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);
|
||||
if (result == RESULT_OK) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
case bs_noSignal:
|
||||
@@ -617,59 +677,55 @@ result_t BusHandler::handleSymbol() {
|
||||
}
|
||||
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) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
m_command.push_back(recvSymbol);
|
||||
m_repeat = false;
|
||||
return setState(bs_recvCmd, RESULT_OK);
|
||||
|
||||
case bs_recvCmd:
|
||||
headerLen = 4;
|
||||
// header symbols are never escaped
|
||||
crcPos = m_command.size() > headerLen ? headerLen + 1 + m_command[headerLen] : 0xff;
|
||||
result = m_command.push_back(recvSymbol, true, m_command.size() < crcPos);
|
||||
if (result < RESULT_OK) {
|
||||
return setState(bs_skip, result);
|
||||
}
|
||||
if (result == RESULT_OK && crcPos != 0xff && m_command.size() == crcPos + 1) { // CRC received
|
||||
unsigned char dstAddress = m_command[1];
|
||||
// header symbols are never escaped
|
||||
m_commandCrcValid = m_command[headerLen + 1 + m_command[headerLen]] == m_command.getCRC();
|
||||
if (m_commandCrcValid) {
|
||||
if (dstAddress == BROADCAST) {
|
||||
receiveCompleted();
|
||||
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);
|
||||
}
|
||||
if (m_answer && (dstAddress == m_ownMasterAddress || dstAddress == m_ownSlaveAddress)) {
|
||||
return setState(bs_sendCmdAck, RESULT_ERR_CRC);
|
||||
}
|
||||
if (m_repeat) {
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_recvCmdAck, RESULT_ERR_CRC);
|
||||
m_command.push_back(recvSymbol);
|
||||
if (m_command.isComplete()) { // all data received
|
||||
return setState(bs_recvCmdCrc, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_recvCmdCrc:
|
||||
m_crcValid = recvSymbol == m_crc;
|
||||
if (m_command[1] == BROADCAST) {
|
||||
if (m_crcValid) {
|
||||
receiveCompleted();
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (m_crcValid) {
|
||||
addSeenAddress(m_command[0]);
|
||||
return setState(bs_recvCmdAck, RESULT_OK);
|
||||
}
|
||||
if (m_repeat) {
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_recvCmdAck, RESULT_ERR_CRC);
|
||||
|
||||
case bs_recvCmdAck:
|
||||
if (recvSymbol == ACK) {
|
||||
if (!m_commandCrcValid) {
|
||||
if (!m_crcValid) {
|
||||
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])) {
|
||||
receiveCompleted();
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
@@ -680,6 +736,7 @@ result_t BusHandler::handleSymbol() {
|
||||
if (recvSymbol == NAK) {
|
||||
if (!m_repeat) {
|
||||
m_repeat = true;
|
||||
m_crc = 0;
|
||||
m_nextSendPos = 0;
|
||||
m_command.clear();
|
||||
if (m_currentRequest != NULL) {
|
||||
@@ -692,36 +749,34 @@ result_t BusHandler::handleSymbol() {
|
||||
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) {
|
||||
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) {
|
||||
return setState(bs_sendResAck, RESULT_OK);
|
||||
}
|
||||
return setState(bs_recvResAck, RESULT_OK);
|
||||
}
|
||||
if (m_repeat) {
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendSyn, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendResAck, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_recvResAck, RESULT_ERR_CRC);
|
||||
m_response.push_back(recvSymbol);
|
||||
if (m_response.isComplete()) { // all data received
|
||||
return setState(bs_recvResCrc, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_recvResCrc:
|
||||
m_crcValid = recvSymbol == m_crc;
|
||||
if (m_crcValid) {
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendResAck, RESULT_OK);
|
||||
}
|
||||
return setState(bs_recvResAck, RESULT_OK);
|
||||
}
|
||||
if (m_repeat) {
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendSyn, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_CRC);
|
||||
}
|
||||
if (m_currentRequest != NULL) {
|
||||
return setState(bs_sendResAck, RESULT_ERR_CRC);
|
||||
}
|
||||
return setState(bs_recvResAck, RESULT_ERR_CRC);
|
||||
|
||||
case bs_recvResAck:
|
||||
if (recvSymbol == ACK) {
|
||||
if (!m_responseCrcValid) {
|
||||
if (!m_crcValid) {
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
}
|
||||
receiveCompleted();
|
||||
@@ -738,54 +793,66 @@ result_t BusHandler::handleSymbol() {
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
|
||||
case bs_sendCmd:
|
||||
if (m_currentRequest != NULL && sending && recvSymbol == sendSymbol) {
|
||||
// successfully sent
|
||||
m_nextSendPos++;
|
||||
if (m_nextSendPos >= m_currentRequest->m_master.size()) {
|
||||
// master data completely sent
|
||||
if (m_currentRequest->m_master[1] == BROADCAST) {
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
}
|
||||
m_commandCrcValid = true;
|
||||
return setState(bs_recvCmdAck, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
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);
|
||||
}
|
||||
m_nextSendPos++;
|
||||
if (m_nextSendPos >= m_currentRequest->m_master.size()) {
|
||||
return setState(bs_sendCmdCrc, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_sendResAck:
|
||||
if (m_currentRequest != NULL && sending && recvSymbol == sendSymbol) {
|
||||
// successfully sent
|
||||
if (!m_responseCrcValid) {
|
||||
if (!m_repeat) {
|
||||
m_repeat = true;
|
||||
m_response.clear();
|
||||
return setState(bs_recvRes, RESULT_ERR_NAK, true);
|
||||
}
|
||||
return setState(bs_sendSyn, RESULT_ERR_ACK);
|
||||
}
|
||||
case bs_sendCmdCrc:
|
||||
if (m_currentRequest->m_master[1] == BROADCAST) {
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
m_crcValid = true;
|
||||
return setState(bs_recvCmdAck, RESULT_OK);
|
||||
|
||||
case bs_sendResAck:
|
||||
if (!sending || m_currentRequest == NULL) {
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
}
|
||||
if (recvSymbol != sendSymbol) {
|
||||
return setState(bs_skip, RESULT_ERR_SYMBOL);
|
||||
}
|
||||
if (!m_crcValid) {
|
||||
if (!m_repeat) {
|
||||
m_repeat = true;
|
||||
m_response.clear();
|
||||
return setState(bs_recvRes, RESULT_ERR_NAK, true);
|
||||
}
|
||||
return setState(bs_sendSyn, RESULT_ERR_ACK);
|
||||
}
|
||||
return setState(bs_sendSyn, RESULT_OK);
|
||||
|
||||
case bs_sendCmdAck:
|
||||
if (sending && m_answer && recvSymbol == sendSymbol) {
|
||||
// successfully sent
|
||||
if (!m_commandCrcValid) {
|
||||
if (!m_repeat) {
|
||||
m_repeat = true;
|
||||
m_command.clear();
|
||||
return setState(bs_recvCmd, RESULT_ERR_NAK, true);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
}
|
||||
if (isMaster(m_command[1])) {
|
||||
receiveCompleted(); // decode command and store value
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
if (!sending || !m_answer) {
|
||||
return setState(bs_skip, RESULT_ERR_INVALID_ARG);
|
||||
}
|
||||
if (recvSymbol != sendSymbol) {
|
||||
return setState(bs_skip, RESULT_ERR_SYMBOL);
|
||||
}
|
||||
if (!m_crcValid) {
|
||||
if (!m_repeat) {
|
||||
m_repeat = true;
|
||||
m_crc = 0;
|
||||
m_command.clear();
|
||||
return setState(bs_recvCmd, RESULT_ERR_NAK, true);
|
||||
}
|
||||
return setState(bs_skip, RESULT_ERR_ACK);
|
||||
}
|
||||
if (isMaster(m_command[1])) {
|
||||
receiveCompleted(); // decode command and store value
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
}
|
||||
|
||||
m_nextSendPos = 0;
|
||||
m_repeat = false;
|
||||
m_nextSendPos = 0;
|
||||
m_repeat = false;
|
||||
{
|
||||
Message* message;
|
||||
istringstream input; // TODO create input from database of internal variables
|
||||
message = m_messages->find(m_command);
|
||||
@@ -803,33 +870,45 @@ result_t BusHandler::handleSymbol() {
|
||||
input.str(SCAN_ANSWER);
|
||||
}
|
||||
// build response and store in m_response for sending back to requesting master
|
||||
m_response.clear(true); // escape while sending response
|
||||
m_response.clear();
|
||||
result = message->prepareSlave(input, m_response);
|
||||
if (result != RESULT_OK) {
|
||||
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:
|
||||
if (sending && m_answer && recvSymbol == sendSymbol) {
|
||||
// successfully sent
|
||||
m_nextSendPos++;
|
||||
if (m_nextSendPos >= m_response.size()) {
|
||||
// slave data completely sent
|
||||
return setState(bs_recvResAck, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
if (!sending || !m_answer) {
|
||||
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);
|
||||
}
|
||||
m_nextSendPos++;
|
||||
if (m_nextSendPos >= m_response.size()) {
|
||||
// slave data completely sent
|
||||
return setState(bs_sendResCrc, RESULT_OK);
|
||||
}
|
||||
return RESULT_OK;
|
||||
|
||||
case bs_sendResCrc:
|
||||
if (!sending || m_currentRequest == NULL) {
|
||||
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:
|
||||
if (sending && recvSymbol == sendSymbol) {
|
||||
// successfully sent
|
||||
return setState(bs_skip, RESULT_OK);
|
||||
if (!sending) {
|
||||
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;
|
||||
}
|
||||
@@ -863,7 +942,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
}
|
||||
|
||||
if (state == bs_noSignal) { // notify all requests
|
||||
m_response.clear(false); // notify with empty response
|
||||
m_response.clear(); // notify with empty response
|
||||
while ((m_currentRequest = m_nextRequests.pop()) != NULL) {
|
||||
bool restart = m_currentRequest->notify(RESULT_ERR_NO_SIGNAL, m_response);
|
||||
if (restart) { // should not occur with no signal
|
||||
@@ -877,6 +956,7 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
}
|
||||
}
|
||||
|
||||
m_escape = 0;
|
||||
if (state == m_state) {
|
||||
return result;
|
||||
}
|
||||
@@ -895,12 +975,13 @@ result_t BusHandler::setState(BusState state, result_t result, bool firstRepetit
|
||||
|
||||
if (state == bs_ready || state == bs_skip) {
|
||||
m_command.clear();
|
||||
m_commandCrcValid = false;
|
||||
m_response.clear(false); // unescape while receiving response
|
||||
m_responseCrcValid = false;
|
||||
m_crc = 0;
|
||||
m_crcValid = false;
|
||||
m_response.clear();
|
||||
m_nextSendPos = 0;
|
||||
} else if (state == bs_recvRes || state == bs_sendRes) {
|
||||
m_crc = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1182,7 +1263,7 @@ result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
istringstream input;
|
||||
SymbolString master;
|
||||
SymbolString master(true);
|
||||
result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress);
|
||||
if (result == RESULT_OK) {
|
||||
result = sendAndWait(master, slave);
|
||||
|
||||
+27
-21
@@ -66,13 +66,17 @@ enum BusState {
|
||||
bs_skip, //!< skip all symbols until next @a SYN
|
||||
bs_ready, //!< ready for next master (after @a SYN symbol, send/receive QQ)
|
||||
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_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_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_sendCmdAck, //!< send command ACK/NACK [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]
|
||||
};
|
||||
|
||||
@@ -102,7 +106,7 @@ class BusRequest {
|
||||
public:
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
BusRequest(SymbolString& master, const bool deleteOnFinish)
|
||||
@@ -124,7 +128,7 @@ class BusRequest {
|
||||
|
||||
|
||||
protected:
|
||||
/** the escaped master data @a SymbolString to send. */
|
||||
/** the master data @a SymbolString to send. */
|
||||
SymbolString& m_master;
|
||||
|
||||
/** the number of times a send is repeated due to lost arbitration. */
|
||||
@@ -166,8 +170,8 @@ class PollRequest : public BusRequest {
|
||||
|
||||
|
||||
private:
|
||||
/** the escaped master data @a SymbolString. */
|
||||
SymbolString m_master;
|
||||
/** the master data @a SymbolString. */
|
||||
SymbolString m_master{true};
|
||||
|
||||
/** the associated @a Message. */
|
||||
Message* m_message;
|
||||
@@ -218,8 +222,8 @@ class ScanRequest : public BusRequest {
|
||||
/** the @a MessageMap instance. */
|
||||
MessageMap* m_messageMap;
|
||||
|
||||
/** the escaped master data @a SymbolString. */
|
||||
SymbolString m_master;
|
||||
/** the master data @a SymbolString. */
|
||||
SymbolString m_master{true};
|
||||
|
||||
/** the currently queried @a Message. */
|
||||
Message* m_message;
|
||||
@@ -253,7 +257,7 @@ class ActiveBusRequest : public BusRequest {
|
||||
public:
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
ActiveBusRequest(SymbolString& master, SymbolString& slave)
|
||||
@@ -292,8 +296,8 @@ class GrabbedMessage {
|
||||
* @param other the @a GrabbedMessage to copy from.
|
||||
*/
|
||||
GrabbedMessage(const GrabbedMessage& other) : m_count(other.m_count) {
|
||||
m_lastMaster.addAll(other.m_lastMaster);
|
||||
m_lastSlave.addAll(other.m_lastSlave);
|
||||
m_lastMaster = other.m_lastMaster;
|
||||
m_lastSlave = other.m_lastSlave;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,8 +368,7 @@ class BusHandler : public WaitThread {
|
||||
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_state(bs_noSignal), m_escape(0), m_crc(0), m_crcValid(false), m_repeat(false),
|
||||
m_grabMessages(true) {
|
||||
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.
|
||||
* @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.
|
||||
* @return the result code.
|
||||
*/
|
||||
@@ -632,21 +635,24 @@ class BusHandler : public WaitThread {
|
||||
/** the current @a BusState. */
|
||||
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. */
|
||||
bool m_repeat;
|
||||
|
||||
/** the unescaped received command. */
|
||||
SymbolString m_command;
|
||||
/** the received command. */
|
||||
SymbolString m_command{true};
|
||||
|
||||
/** whether the command CRC is valid. */
|
||||
bool m_commandCrcValid;
|
||||
|
||||
/** the unescaped received response or escaped response to send. */
|
||||
/** the received response or response to send. */
|
||||
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). */
|
||||
unsigned char m_seenAddresses[256];
|
||||
|
||||
|
||||
+32
-37
@@ -233,7 +233,7 @@ void MainLoop::run() {
|
||||
result = m_busHandler->startScan(true, "*");
|
||||
} else {
|
||||
logNotice(lf_main, "starting initial scan for %2.2x", m_initialScan);
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
result = m_busHandler->scanAndWait(m_initialScan, slave);
|
||||
Message* message = m_messages->getScanMessage(m_initialScan);
|
||||
if (result == RESULT_OK && message != NULL) {
|
||||
@@ -257,7 +257,7 @@ void MainLoop::run() {
|
||||
taskDelay = 5;
|
||||
lastScanAddress = 0;
|
||||
} else {
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
if (scanned) {
|
||||
Message* message = m_messages->getScanMessage(lastScanAddress);
|
||||
slave = message->getLastSlaveData();
|
||||
@@ -486,13 +486,14 @@ result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, SymbolStr
|
||||
}
|
||||
result_t 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;
|
||||
}
|
||||
ret = master.push_back(srcAddress == SYN ? m_address : srcAddress, false);
|
||||
if (ret == RESULT_OK) {
|
||||
ret = master.parseHex(msg.str());
|
||||
}
|
||||
master.push_back(srcAddress == SYN ? m_address : srcAddress);
|
||||
ret = master.parseHex(msg.str());
|
||||
if (ret == RESULT_OK && !isValidAddress(master[1])) {
|
||||
ret = RESULT_ERR_INVALID_ADDR;
|
||||
}
|
||||
@@ -613,18 +614,18 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
|
||||
time(&now);
|
||||
|
||||
if (hex && argPos > 0) {
|
||||
SymbolString cacheMaster(false);
|
||||
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress);
|
||||
SymbolString master(true);
|
||||
result_t ret = parseHexMaster(args, argPos, master, srcAddress);
|
||||
if (ret != RESULT_OK) {
|
||||
return getResultCode(ret);
|
||||
}
|
||||
if (cacheMaster[1] == BROADCAST || isMaster(cacheMaster[1])) {
|
||||
if (master[1] == BROADCAST || isMaster(master[1])) {
|
||||
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
|
||||
Message* message = m_messages->find(cacheMaster, false, true, false, false);
|
||||
Message* message = m_messages->find(master, false, true, false, false);
|
||||
|
||||
if (message == NULL) {
|
||||
return getResultCode(RESULT_ERR_NOTFOUND);
|
||||
@@ -643,17 +644,15 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
|
||||
|| (message->isPassive() && message->getLastUpdateTime() != 0))) {
|
||||
SymbolString& slave = message->getLastSlaveData();
|
||||
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
|
||||
SymbolString master(true);
|
||||
master.addAll(cacheMaster);
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
ret = m_busHandler->sendAndWait(master, slave);
|
||||
|
||||
if (ret == RESULT_OK) {
|
||||
ret = message->storeLastData(cacheMaster, slave);
|
||||
ret = message->storeLastData(master, slave);
|
||||
ostringstream result;
|
||||
if (ret == RESULT_OK) {
|
||||
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(),
|
||||
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(),
|
||||
getResultCode(ret));
|
||||
@@ -822,15 +821,15 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
|
||||
}
|
||||
|
||||
if (hex && argPos > 0) {
|
||||
SymbolString cacheMaster(false);
|
||||
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress);
|
||||
SymbolString master(true);
|
||||
result_t ret = parseHexMaster(args, argPos, master, srcAddress);
|
||||
if (ret != RESULT_OK) {
|
||||
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
|
||||
Message* message = m_messages->find(cacheMaster, false, false, true, false);
|
||||
Message* message = m_messages->find(master, false, false, true, false);
|
||||
|
||||
if (message == NULL) {
|
||||
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
|
||||
}
|
||||
// send message
|
||||
SymbolString master(true);
|
||||
master.addAll(cacheMaster);
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
ret = m_busHandler->sendAndWait(master, slave);
|
||||
|
||||
if (ret == RESULT_OK) {
|
||||
// also update read messages
|
||||
ret = message->storeLastData(cacheMaster, slave);
|
||||
ret = message->storeLastData(master, slave);
|
||||
ostringstream result;
|
||||
if (ret == RESULT_OK) {
|
||||
ret = message->decodeLastData(result);
|
||||
@@ -870,7 +867,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
|
||||
if (isMaster(master[1])) {
|
||||
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(),
|
||||
getResultCode(ret));
|
||||
@@ -959,17 +956,15 @@ string MainLoop::executeHex(vector<string> &args) {
|
||||
}
|
||||
|
||||
if (argPos > 0) {
|
||||
SymbolString cacheMaster(false);
|
||||
result_t ret = parseHexMaster(args, argPos, cacheMaster, srcAddress);
|
||||
SymbolString master(true);
|
||||
result_t ret = parseHexMaster(args, argPos, master, srcAddress);
|
||||
if (ret != RESULT_OK) {
|
||||
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
|
||||
SymbolString master(true);
|
||||
master.addAll(cacheMaster);
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
ret = m_busHandler->sendAndWait(master, slave);
|
||||
|
||||
if (ret == RESULT_OK) {
|
||||
@@ -979,7 +974,7 @@ string MainLoop::executeHex(vector<string> &args) {
|
||||
if (isMaster(master[1])) {
|
||||
return getResultCode(RESULT_OK);
|
||||
}
|
||||
return slave.getDataStr(true, false);
|
||||
return slave.getDataStr();
|
||||
}
|
||||
logError(lf_main, "hex: %s", getResultCode(ret));
|
||||
return getResultCode(ret);
|
||||
@@ -1171,13 +1166,13 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
|
||||
result << "no data stored";
|
||||
} else if (hexFormat) {
|
||||
result << message->getLastMasterData().getDataStr()
|
||||
<< " / " << message->getLastSlaveData().getDataStr(true, false);
|
||||
<< " / " << message->getLastSlaveData().getDataStr();
|
||||
} else {
|
||||
result_t ret = message->decodeLastData(result, verbosity);
|
||||
if (ret != RESULT_OK) {
|
||||
result << " (" << getResultCode(ret)
|
||||
<< " for " << message->getLastMasterData().getDataStr()
|
||||
<< " / " << message->getLastSlaveData().getDataStr(true, false) << ")";
|
||||
<< " / " << message->getLastSlaveData().getDataStr() << ")";
|
||||
}
|
||||
}
|
||||
if (verbosity == (OF_NAMES|OF_UNITS|OF_COMMENTS)) {
|
||||
@@ -1310,7 +1305,7 @@ string MainLoop::executeScan(vector<string> &args, string levels) {
|
||||
if (result != RESULT_OK) {
|
||||
return getResultCode(result);
|
||||
}
|
||||
SymbolString slave(false);
|
||||
SymbolString slave;
|
||||
result = m_busHandler->scanAndWait(dstAddress, slave);
|
||||
if (result != RESULT_OK) {
|
||||
return getResultCode(result);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 92 KiB |
@@ -77,14 +77,14 @@ int main() {
|
||||
string check[5] = checks[i];
|
||||
istringstream isstr(check[0]);
|
||||
string expectStr = check[1];
|
||||
SymbolString mstr(false);
|
||||
SymbolString mstr(true);
|
||||
result_t result = mstr.parseHex(check[2]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
SymbolString sstr(false);
|
||||
SymbolString sstr;
|
||||
result = sstr.parseHex(check[3]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -130,17 +130,17 @@ int main() {
|
||||
cout << "\": create OK" << endl;
|
||||
|
||||
ostringstream output;
|
||||
SymbolString writeMstr(false);
|
||||
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
|
||||
SymbolString writeMstr(true);
|
||||
result = writeMstr.parseHex(mstr.getDataStr().substr(0, 10));
|
||||
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;
|
||||
error = true;
|
||||
}
|
||||
SymbolString writeSstr(false);
|
||||
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
|
||||
SymbolString writeSstr;
|
||||
result = writeSstr.parseHex(sstr.getDataStr().substr(0, 2));
|
||||
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;
|
||||
error = true;
|
||||
}
|
||||
@@ -186,8 +186,8 @@ int main() {
|
||||
error = true;
|
||||
} else {
|
||||
bool match = mstr == writeMstr && sstr == writeSstr;
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
|
||||
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " " + writeSstr.getDataStr(true, false));
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr() + " "
|
||||
+ sstr.getDataStr(), writeMstr.getDataStr() + " " + writeSstr.getDataStr());
|
||||
}
|
||||
delete fields;
|
||||
fields = NULL;
|
||||
|
||||
+4
-4
@@ -163,7 +163,7 @@ class DataField {
|
||||
/**
|
||||
* Reads the numeric value from the @a SymbolString.
|
||||
* @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 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.
|
||||
@@ -180,7 +180,7 @@ class DataField {
|
||||
/**
|
||||
* Reads the value from the @a SymbolString.
|
||||
* @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 output the @a ostringstream to append the formatted value to.
|
||||
* @param outputFormat the @a OutputFormat options to use.
|
||||
@@ -332,7 +332,7 @@ class SingleDataField : public DataField {
|
||||
protected:
|
||||
/**
|
||||
* 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 offset the offset in the @a SymbolString.
|
||||
* @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.
|
||||
* @param input the @a istringstream to parse the formatted value from.
|
||||
* @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 usedLength the variable in which to store the used length in bytes, or NULL.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
|
||||
@@ -40,50 +40,6 @@ using std::setfill;
|
||||
using std::setprecision;
|
||||
using std::setw;
|
||||
|
||||
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue,
|
||||
result_t& result, unsigned int* length) {
|
||||
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,
|
||||
vector<string>::iterator pos, string filename, size_t lineNo, result_t result) {
|
||||
if (pos > begin) {
|
||||
|
||||
+8
-32
@@ -123,7 +123,8 @@ enum PartType {
|
||||
/** bit flag for @a DataType: value may not be NULL. */
|
||||
#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
|
||||
|
||||
/** bit flag for @a DataType: exponential numeric representation. */
|
||||
@@ -142,32 +143,6 @@ enum PartType {
|
||||
#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.
|
||||
* @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.
|
||||
* @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 length the number of symbols to read.
|
||||
* @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.
|
||||
* @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 offset the offset in the @a SymbolString.
|
||||
* @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 offset the offset in the @a SymbolString.
|
||||
* @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 usedLength the variable in which to store the used length in bytes, or NULL.
|
||||
* @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,
|
||||
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.
|
||||
@@ -521,7 +497,7 @@ class NumberDataType : public DataType {
|
||||
* @param value the numeric raw value to write.
|
||||
* @param offset the offset in the @a SymbolString.
|
||||
* @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,
|
||||
* or NULL.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
|
||||
+27
-61
@@ -590,43 +590,29 @@ bool Message::hasField(const char* fieldName, bool 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,
|
||||
const unsigned char dstAddress, unsigned char index) {
|
||||
if (m_isPassive) {
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
}
|
||||
SymbolString master(false);
|
||||
result_t result = master.push_back(srcAddress, false, false);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.clear();
|
||||
master.push_back(srcAddress);
|
||||
if (dstAddress == SYN) {
|
||||
if (m_dstAddress == SYN) {
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
}
|
||||
result = master.push_back(m_dstAddress, false, false);
|
||||
master.push_back(m_dstAddress);
|
||||
} 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) {
|
||||
return result;
|
||||
}
|
||||
result = master.push_back(m_id[0], false, false);
|
||||
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);
|
||||
result = storeLastData(pt_masterData, master, index);
|
||||
if (result < RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -638,17 +624,11 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
unsigned char pos = master.size();
|
||||
result_t result = master.push_back(0, false, false); // length, will be set later
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.push_back(0); // length, will be set later
|
||||
for (size_t i = 2; i < m_id.size(); i++) {
|
||||
result = master.push_back(m_id[i], false, false);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.push_back(m_id[i]);
|
||||
}
|
||||
result = m_data->write(input, pt_masterData, master, getIdLength(), separator);
|
||||
result_t result = m_data->write(input, pt_masterData, master, getIdLength(), separator);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -656,16 +636,13 @@ result_t Message::prepareMasterPart(SymbolString& master, istringstream& input,
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) {
|
||||
result_t Message::prepareSlave(istringstream& input, SymbolString& slave) {
|
||||
if (m_isWrite) {
|
||||
return RESULT_ERR_INVALID_ARG; // prepare not possible
|
||||
}
|
||||
SymbolString slave(false);
|
||||
result_t result = slave.push_back(0, false, false); // length, will be set later
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
result = m_data->write(input, pt_slaveData, slave, 0);
|
||||
slave.clear();
|
||||
slave.push_back(0); // length, will be set later
|
||||
result_t result = m_data->write(input, pt_slaveData, slave, 0);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
@@ -675,8 +652,6 @@ result_t Message::prepareSlave(istringstream& input, SymbolString& slaveData) {
|
||||
m_lastChangeTime = m_lastUpdateTime;
|
||||
m_lastSlaveData = slave;
|
||||
}
|
||||
slaveData.clear();
|
||||
slaveData.addAll(slave);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -695,7 +670,7 @@ result_t Message::storeLastData(const PartType partType, SymbolString& data, uns
|
||||
time(&m_lastUpdateTime);
|
||||
}
|
||||
if (partType == pt_masterData) {
|
||||
switch (data.compareMaster(m_lastMasterData)) {
|
||||
switch (data.compareTo(m_lastMasterData)) {
|
||||
case 1: // completely different
|
||||
m_lastChangeTime = m_lastUpdateTime;
|
||||
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_lastSlaveUpdateTimes = reinterpret_cast<time_t*>(calloc(cnt, sizeof(time_t)));
|
||||
for (size_t index = 0; index < cnt; index++) {
|
||||
m_lastMasterDatas[index] = new SymbolString();
|
||||
m_lastMasterDatas[index] = new SymbolString(true);
|
||||
m_lastSlaveDatas[index] = new SymbolString();
|
||||
}
|
||||
}
|
||||
@@ -1000,7 +975,7 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
|
||||
if (index >= cnt) {
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
SymbolString allData(false);
|
||||
SymbolString allData(true);
|
||||
result_t result = m_data->write(input, pt_masterData, allData, 0, separator);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
@@ -1017,21 +992,12 @@ result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream&
|
||||
return RESULT_ERR_INVALID_POS;
|
||||
}
|
||||
vector<unsigned char> id = m_ids[index];
|
||||
result = master.push_back((unsigned char)(id.size()-2+addData), false, false); // NN
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.push_back((unsigned char)(id.size()-2+addData)); // NN
|
||||
for (size_t i = 2; i < id.size(); i++) {
|
||||
result = master.push_back(id[i], false, false);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.push_back(id[i]);
|
||||
}
|
||||
for (size_t i = 0; i < addData; i++) {
|
||||
result = master.push_back(allData[pos+i], false, false);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
master.push_back(allData[pos+i]);
|
||||
}
|
||||
if (index == 0) {
|
||||
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;
|
||||
}
|
||||
if (partType == pt_masterData) {
|
||||
switch (data.compareMaster(*m_lastMasterDatas[index])) {
|
||||
switch (data.compareTo(*m_lastMasterDatas[index])) {
|
||||
case 1: // completely different
|
||||
*m_lastMasterDatas[index] = data;
|
||||
break;
|
||||
@@ -1098,19 +1064,19 @@ result_t ChainedMessage::storeLastData(const PartType partType, SymbolString& da
|
||||
}
|
||||
}
|
||||
// everything was completely retrieved in short time
|
||||
SymbolString master(false);
|
||||
SymbolString slave(false);
|
||||
SymbolString master(true);
|
||||
SymbolString slave;
|
||||
size_t offset = 5+(m_ids[0].size()-2); // skip QQ, ZZ, PB, SB, NN
|
||||
for (index = 0; index < m_ids.size(); index++) {
|
||||
SymbolString* add = m_lastMasterDatas[index];
|
||||
size_t end = 5+(*add)[4];
|
||||
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];
|
||||
end = 1+(*add)[0];
|
||||
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
|
||||
|
||||
@@ -421,14 +421,14 @@ class Message {
|
||||
/**
|
||||
* Prepare the master @a SymbolString for sending a query or command to the bus.
|
||||
* @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 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 index the index of the part to prepare.
|
||||
* @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,
|
||||
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.
|
||||
* @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.
|
||||
*/
|
||||
virtual result_t prepareSlave(istringstream& input, SymbolString& slaveData);
|
||||
virtual result_t prepareSlave(istringstream& input, SymbolString& slave);
|
||||
|
||||
/**
|
||||
* Store the last seen master and slave data.
|
||||
@@ -631,7 +631,7 @@ class Message {
|
||||
Condition* m_condition;
|
||||
|
||||
/** the last seen master data. */
|
||||
SymbolString m_lastMasterData;
|
||||
SymbolString m_lastMasterData{true};
|
||||
|
||||
/** the last seen slave data. */
|
||||
SymbolString m_lastSlaveData;
|
||||
|
||||
@@ -49,6 +49,7 @@ const char* getResultCode(result_t resultCode) {
|
||||
case RESULT_ERR_NAK: return "ERR: NAK received";
|
||||
case RESULT_ERR_NO_SIGNAL: return "ERR: no signal";
|
||||
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";
|
||||
|
||||
default:
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ebusd {
|
||||
enum result_t {
|
||||
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_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_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
|
||||
};
|
||||
|
||||
|
||||
|
||||
+95
-116
@@ -54,64 +54,103 @@ static const unsigned char CRC_LOOKUP_TABLE[] = {
|
||||
};
|
||||
|
||||
|
||||
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) {
|
||||
end--;
|
||||
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;
|
||||
}
|
||||
for (size_t i = 0; i < end; i++) {
|
||||
push_back(data[i], isEscaped, addCrc);
|
||||
|
||||
if (minValue > ret || ret > maxValue) {
|
||||
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
|
||||
return 0;
|
||||
}
|
||||
if (addCrc) {
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
if (length != NULL) {
|
||||
*length = (unsigned int)(strEnd - str);
|
||||
}
|
||||
result = RESULT_OK;
|
||||
return (unsigned int)ret;
|
||||
}
|
||||
|
||||
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;
|
||||
const char* strBegin = str.substr(i, 2).c_str();
|
||||
unsigned long value = strtoul(strBegin, &strEnd, 16);
|
||||
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result,
|
||||
unsigned int* length) {
|
||||
char* strEnd = NULL;
|
||||
|
||||
if (strEnd == NULL || strEnd != strBegin+2 || value > 0xff) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
push_back((unsigned char)value, isEscaped, addCrc);
|
||||
long ret = strtol(str, &strEnd, base);
|
||||
|
||||
if (strEnd == NULL || *strEnd != 0) {
|
||||
result = RESULT_ERR_INVALID_NUM; // invalid value
|
||||
return 0;
|
||||
}
|
||||
if (addCrc) {
|
||||
push_back(m_crc, false, false); // add CRC
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const string SymbolString::getDataStr(const bool unescape, const bool skipLastSymbol,
|
||||
unsigned char skipFirstSymbols) {
|
||||
bool previousEscape = false;
|
||||
result_t SymbolString::parseHexEscaped(const string& str) {
|
||||
result_t result;
|
||||
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;
|
||||
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) {
|
||||
skipFirstSymbols--;
|
||||
} else if (!skipLastSymbol || i+1 < m_data.size()) {
|
||||
if (value == 0x00) {
|
||||
sstr << "a9"; // ESC
|
||||
} else if (value == 0x01) {
|
||||
sstr << "aa"; // SYN
|
||||
} else {
|
||||
sstr << "XX"; // invalid escape sequence
|
||||
}
|
||||
}
|
||||
previousEscape = false;
|
||||
} else if (m_unescapeState == 0 && unescape && value == ESC) {
|
||||
previousEscape = true; // escape sequence not yet finished
|
||||
} else if (skipFirstSymbols > 0) {
|
||||
if (skipFirstSymbols > 0) {
|
||||
skipFirstSymbols--;
|
||||
} else if (!skipLastSymbol || i+1 < m_data.size()) {
|
||||
} else {
|
||||
unsigned char value = m_data[i];
|
||||
sstr << nouppercase << setw(2) << hex
|
||||
<< setfill('0') << static_cast<unsigned>(value);
|
||||
}
|
||||
@@ -119,83 +158,23 @@ 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) {
|
||||
if (m_unescapeState == 0) { // store escaped data
|
||||
if (!isEscaped && value == ESC) {
|
||||
m_data.push_back(ESC);
|
||||
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);
|
||||
}
|
||||
unsigned char SymbolString::calcCrc() const {
|
||||
unsigned char crc = 0;
|
||||
for (size_t i = 0; i < m_data.size(); i++) {
|
||||
unsigned char value = m_data[i];
|
||||
if (value == ESC) {
|
||||
updateCrc(crc, ESC);
|
||||
updateCrc(crc, 0x00);
|
||||
} else if (value == SYN) {
|
||||
updateCrc(crc, ESC);
|
||||
updateCrc(crc, 0x01);
|
||||
} else {
|
||||
m_data.push_back(value);
|
||||
if (updateCRC) {
|
||||
addCRC(value);
|
||||
}
|
||||
updateCrc(crc, 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) {
|
||||
addCRC(ESC);
|
||||
addCRC(0x00);
|
||||
} else if (value == SYN) {
|
||||
addCRC(ESC);
|
||||
addCRC(0x01);
|
||||
} else {
|
||||
addCRC(value);
|
||||
}
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
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;
|
||||
return crc;
|
||||
}
|
||||
|
||||
void SymbolString::addCRC(const unsigned char value) {
|
||||
m_crc = CRC_LOOKUP_TABLE[m_crc]^value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the index of the upper or lower 4 bits of a master address.
|
||||
|
||||
+95
-62
@@ -32,9 +32,9 @@ namespace ebusd {
|
||||
/** @file lib/ebus/symbol.h
|
||||
* Classes, functions, and constants related to symbols on the eBUS.
|
||||
*
|
||||
* The @a SymbolString class is used for escaping or unescaping a sequence of
|
||||
* bytes in preparation for sending to the bus or after reception of bytes from
|
||||
* the bus, as well as calculating and verifying the CRC of a message part.
|
||||
* The @a SymbolString class is used for holding a sequence of bytes received
|
||||
* from or sent to the bus, as well as calculating and verifying the CRC of a
|
||||
* message part.
|
||||
*
|
||||
* 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
|
||||
@@ -70,51 +70,83 @@ using std::vector;
|
||||
|
||||
/** escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA. */
|
||||
#define ESC 0xA9
|
||||
|
||||
/** synchronization symbol. */
|
||||
#define SYN 0xAA
|
||||
|
||||
/** positive acknowledge symbol. */
|
||||
#define ACK 0x00
|
||||
|
||||
/** negative acknowledge symbol. */
|
||||
#define NAK 0xFF
|
||||
|
||||
/** the broadcast destination address. */
|
||||
#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 {
|
||||
public:
|
||||
/**
|
||||
* Creates a new empty escaped or unescaped instance.
|
||||
* @param escaped whether to create an escaped instance.
|
||||
* Creates a new empty 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.
|
||||
* @param str the @a SymbolString to copy from.
|
||||
* @param skipLastSymbol whether to skip the last symbol (probably the CRC).
|
||||
* Update the CRC by adding a value.
|
||||
* @param crc the current CRC to update.
|
||||
* @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 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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.
|
||||
* @return the symbols as hex string.
|
||||
*/
|
||||
const string getDataStr(const bool unescape = true, const bool skipLastSymbol = true,
|
||||
unsigned char skipFirstSymbols = 0);
|
||||
const string getDataStr(unsigned char skipFirstSymbols = 0);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param other the other instance.
|
||||
* @return true if this instance is equal to the other instance (i.e. both escaped or both unescaped and same
|
||||
* symbols).
|
||||
* @return true if this instance is equal to the other instance.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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
|
||||
* address and ending with the CRC).
|
||||
* Compare the data in this instance to that of 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),
|
||||
* 1 if this instance is completely different to the other instance,
|
||||
* 2 if this instance only differs from the other instance in the first byte (the master address).
|
||||
* @return 0 if the data is equal,
|
||||
* 1 if the data is completely different,
|
||||
* 2 if both instances are a master part and the data only differs in the first byte (the master address).
|
||||
*/
|
||||
int compareMaster(SymbolString& other) {
|
||||
if (m_unescapeState != other.m_unescapeState || m_data.size() != other.m_data.size()) {
|
||||
int compareTo(SymbolString& other) {
|
||||
if (m_data.size() != other.m_data.size()) {
|
||||
return 1;
|
||||
}
|
||||
if (m_data == other.m_data) {
|
||||
return 0;
|
||||
}
|
||||
if (!m_isMaster) {
|
||||
return 1;
|
||||
}
|
||||
if (m_data.size() == 1) {
|
||||
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 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.
|
||||
@@ -189,21 +217,39 @@ class SymbolString {
|
||||
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.
|
||||
*/
|
||||
unsigned char getCRC() const { return m_crc; }
|
||||
unsigned char calcCrc() const;
|
||||
|
||||
/**
|
||||
* Clear the symbols.
|
||||
*/
|
||||
void clear() { m_data.clear(); m_unescapeState = m_unescapeState == 0 ? 0 : 1; m_crc = 0; }
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
void clear() { m_data.clear(); }
|
||||
|
||||
|
||||
private:
|
||||
@@ -212,26 +258,13 @@ class SymbolString {
|
||||
* @param str the @a SymbolString to copy from.
|
||||
*/
|
||||
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) {}
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
/** the string of unescaped symbols. */
|
||||
vector<unsigned char> m_data;
|
||||
|
||||
/**
|
||||
* 0 if the symbols in @a m_data are escaped,
|
||||
* 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;
|
||||
/** whether this instance if for the master part. */
|
||||
bool m_isMaster;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -473,14 +473,14 @@ int main() {
|
||||
string check[5] = checks[i];
|
||||
istringstream isstr(check[0]);
|
||||
string expectStr = check[1];
|
||||
SymbolString mstr(false);
|
||||
SymbolString mstr(true);
|
||||
result_t result = mstr.parseHex(check[2]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
continue;
|
||||
}
|
||||
SymbolString sstr(false);
|
||||
SymbolString sstr;
|
||||
result = sstr.parseHex(check[3]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -563,17 +563,17 @@ int main() {
|
||||
}
|
||||
|
||||
ostringstream output;
|
||||
SymbolString writeMstr(false);
|
||||
result = writeMstr.parseHex(mstr.getDataStr(true, false).substr(0, 10));
|
||||
SymbolString writeMstr(true);
|
||||
result = writeMstr.parseHex(mstr.getDataStr().substr(0, 10));
|
||||
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;
|
||||
error = true;
|
||||
}
|
||||
SymbolString writeSstr(false);
|
||||
result = writeSstr.parseHex(sstr.getDataStr(true, false).substr(0, 2));
|
||||
SymbolString writeSstr;
|
||||
result = writeSstr.parseHex(sstr.getDataStr().substr(0, 2));
|
||||
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;
|
||||
error = true;
|
||||
}
|
||||
@@ -621,9 +621,9 @@ int main() {
|
||||
error = true;
|
||||
} else {
|
||||
bool match = mstr == writeMstr && sstr == writeSstr;
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr(true, false) + " "
|
||||
+ sstr.getDataStr(true, false), writeMstr.getDataStr(true, false) + " "
|
||||
+ writeSstr.getDataStr(true, false));
|
||||
verify(failedWriteMatch, "write", expectStr, match, mstr.getDataStr() + " "
|
||||
+ sstr.getDataStr(), writeMstr.getDataStr() + " "
|
||||
+ writeSstr.getDataStr());
|
||||
}
|
||||
}
|
||||
delete fields;
|
||||
|
||||
@@ -260,7 +260,7 @@ int main() {
|
||||
} else if (mstrs[pos] != NULL) {
|
||||
delete mstrs[pos];
|
||||
}
|
||||
mstrs[pos] = new SymbolString(false);
|
||||
mstrs[pos] = new SymbolString(true);
|
||||
result = mstrs[pos]->parseHex(token);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -277,7 +277,7 @@ int main() {
|
||||
} else if (sstrs[pos] != NULL) {
|
||||
delete sstrs[pos];
|
||||
}
|
||||
sstrs[pos] = new SymbolString(false);
|
||||
sstrs[pos] = new SymbolString();
|
||||
result = sstrs[pos]->parseHex(token);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << token << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -292,7 +292,7 @@ int main() {
|
||||
if (mstrs[0] != NULL) {
|
||||
delete mstrs[0];
|
||||
}
|
||||
mstrs[0] = new SymbolString(false);
|
||||
mstrs[0] = new SymbolString(true);
|
||||
result = mstrs[0]->parseHex(check[2]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[2] << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -301,7 +301,7 @@ int main() {
|
||||
if (sstrs[0] != NULL) {
|
||||
delete sstrs[0];
|
||||
}
|
||||
sstrs[0] = new SymbolString(false);
|
||||
sstrs[0] = new SymbolString();
|
||||
result = sstrs[0]->parseHex(check[3]);
|
||||
if (result != RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": parse \"" << check[3] << "\" error: " << getResultCode(result) << endl;
|
||||
@@ -419,7 +419,7 @@ int main() {
|
||||
}
|
||||
if (!message->isPassive() && (withInput || !decode)) {
|
||||
istringstream input(inputStr);
|
||||
SymbolString writeMstr(false);
|
||||
SymbolString writeMstr(true);
|
||||
result = message->prepareMaster(0xff, writeMstr, input);
|
||||
if (failedPrepare) {
|
||||
if (result == RESULT_OK) {
|
||||
@@ -438,8 +438,8 @@ int main() {
|
||||
cout << " \"" << inputStr << "\": prepare OK" << endl;
|
||||
|
||||
bool match = writeMstr == *mstrs[0];
|
||||
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(true, false),
|
||||
writeMstr.getDataStr(true, false));
|
||||
verify(failedPrepareMatch, "prepare", inputStr, match, mstrs[0]->getDataStr(),
|
||||
writeMstr.getDataStr());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,26 +50,32 @@ int main(int argc, char** argv) {
|
||||
SymbolString sstr(true);
|
||||
|
||||
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) {
|
||||
cout << "parse escaped error: " << getResultCode(result) << endl;
|
||||
} else {
|
||||
unsigned char gotCrc = sstr.getCRC();
|
||||
unsigned char gotCrc = sstr.calcCrc();
|
||||
cout << "calculated CRC: 0x"
|
||||
<< nouppercase << setw(2) << hex << setfill('0')
|
||||
<< static_cast<unsigned>(gotCrc) << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string gotStr, expectStr;
|
||||
result_t result = sstr.parseHex("10feb5050427a915aa", false);
|
||||
result_t result = sstr.parseHex("10feb5050427a915aa");
|
||||
if (result != RESULT_OK) {
|
||||
cout << "parse escaped error: " << getResultCode(result) << endl;
|
||||
cout << "parse unescaped error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
} else {
|
||||
gotStr = sstr.getDataStr(false, false), expectStr = "10feb5050427a90015a90177";
|
||||
verify(false, "parse escaped", "10feb5050427a915aa", true, expectStr, gotStr);
|
||||
unsigned char gotCrc = sstr.getCRC(), expectCrc = 0x77;
|
||||
gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa";
|
||||
verify(false, "parse unescaped", "10feb5050427a915aa", true, expectStr, gotStr);
|
||||
unsigned char gotCrc = sstr.calcCrc(), expectCrc = 0x77;
|
||||
ostringstream ostr;
|
||||
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(expectCrc);
|
||||
expectStr = ostr.str();
|
||||
@@ -77,19 +83,40 @@ int main(int argc, char** argv) {
|
||||
ostr << nouppercase << setw(2) << hex << setfill('0') << static_cast<unsigned>(gotCrc);
|
||||
gotStr = ostr.str();
|
||||
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);
|
||||
result = sstr.parseHex("10feb5050427a90015a90177", true);
|
||||
sstr.clear();
|
||||
result = sstr.parseHexEscaped("10feb5050427a90015a901");
|
||||
if (result != RESULT_OK) {
|
||||
cout << "parse unescaped error: " << getResultCode(result) << endl;
|
||||
cout << "parse escaped error: " << getResultCode(result) << endl;
|
||||
error = true;
|
||||
} else {
|
||||
gotStr = sstr.getDataStr(true, false), expectStr = "10feb5050427a915aa77";
|
||||
verify(false, "parse unescaped", "10feb5050427a90015a90177", true, expectStr, gotStr);
|
||||
gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa";
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user