merge in latest libebus commit 9520d5a3283472c2a53b8396b0796723f660bed7:
simplified SymbolString interface and let it handle unescaping itself
This commit is contained in:
@@ -31,6 +31,7 @@ static const int RESULT_DATA = 2; // some data received
|
||||
static const int RESULT_SYN = 3; // regular SYN after message received
|
||||
static const int RESULT_BUS_LOCKED = 4; // bus is locked for access
|
||||
static const int RESULT_BUS_PRIOR_RETRY = 5; // retry to access bus
|
||||
static const int RESULT_IN_ESC = 6; // start of escape sequence received
|
||||
|
||||
static const int RESULT_ERR_SEND = -1; // send error
|
||||
static const int RESULT_ERR_EXTRA_DATA = -2; // received bytes > sent bytes
|
||||
|
||||
+72
-53
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "symbol.h"
|
||||
#include "result.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
@@ -27,7 +28,7 @@ namespace libebus
|
||||
/**
|
||||
* @brief CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1.
|
||||
*/
|
||||
static const unsigned char CRC_LOOKUP_TABLE[]
|
||||
static const unsigned char CRC_LOOKUP_TABLE[] =
|
||||
{
|
||||
0x00, 0x9b, 0xad, 0x36, 0xc1, 0x5a, 0x6c, 0xf7, 0x19, 0x82, 0xb4, 0x2f, 0xd8, 0x43, 0x75, 0xee,
|
||||
0x32, 0xa9, 0x9f, 0x04, 0xf3, 0x68, 0x5e, 0xc5, 0x2b, 0xb0, 0x86, 0x1d, 0xea, 0x71, 0x47, 0xdc,
|
||||
@@ -49,41 +50,35 @@ static const unsigned char CRC_LOOKUP_TABLE[]
|
||||
|
||||
|
||||
SymbolString::SymbolString(const std::string str)
|
||||
: m_crc(0)
|
||||
: m_unescapeState(0), m_crc(0)
|
||||
{
|
||||
// parse + escape
|
||||
for (size_t i = 0; i+1 < str.size(); i += 2) {
|
||||
unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16);
|
||||
push_back_escape((unsigned char)value);
|
||||
unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); // TODO check
|
||||
push_back((unsigned char)value, false, true);
|
||||
}
|
||||
// add CRC + escape
|
||||
push_back_escape(m_crc, false);
|
||||
push_back(m_crc, false, false);
|
||||
}
|
||||
|
||||
SymbolString::SymbolString(const std::string str, bool escaped)
|
||||
: m_crc(0)
|
||||
SymbolString::SymbolString(const std::string str, bool isEscaped)
|
||||
: m_unescapeState(1), m_crc(0)
|
||||
{
|
||||
bool previousEscape = false;
|
||||
|
||||
// parse + optionally unescape
|
||||
for (size_t i = 0; i+1 < str.size(); i += 2) {
|
||||
unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16);
|
||||
if (escaped == true) {
|
||||
push_back_unescape((unsigned char)value, previousEscape, false);
|
||||
}
|
||||
else
|
||||
m_data.push_back((unsigned char)value);
|
||||
unsigned long value = strtoul(str.substr(i, 2).c_str(), NULL, 16); // TODO check
|
||||
push_back((unsigned char)value, isEscaped, false);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string SymbolString::getDataStr(bool unescape)
|
||||
const std::string SymbolString::getDataStr(const bool unescape)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
bool previousEscape = false;
|
||||
|
||||
for (size_t i = 0; i < size(); i++) {
|
||||
unsigned char value = at(i);
|
||||
if (unescape == true && previousEscape == true) {
|
||||
for (size_t i = 0; i < m_data.size(); i++) {
|
||||
unsigned char value = m_data[i];
|
||||
if (m_unescapeState == 0 && unescape == true && previousEscape == true) {
|
||||
if (value == 0x00) {
|
||||
sstr << "a9"; // ESC
|
||||
}
|
||||
@@ -95,7 +90,7 @@ const std::string SymbolString::getDataStr(bool unescape)
|
||||
}
|
||||
previousEscape = false;
|
||||
}
|
||||
else if (unescape == true && value == ESC) {
|
||||
else if (m_unescapeState == 0 && unescape == true && value == ESC) {
|
||||
previousEscape = true; // escape sequence not yet finished
|
||||
}
|
||||
else {
|
||||
@@ -107,56 +102,80 @@ const std::string SymbolString::getDataStr(bool unescape)
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
void SymbolString::push_back_escape(const unsigned char value, bool updateCRC)
|
||||
int SymbolString::push_back(const unsigned char value, const bool isEscaped, const bool updateCRC)
|
||||
{
|
||||
if (value == ESC) {
|
||||
m_data.push_back(ESC);
|
||||
m_data.push_back(0x00);
|
||||
if (updateCRC) {
|
||||
addCRC(ESC);
|
||||
addCRC(0x00);
|
||||
if (m_unescapeState == 0) { // store escaped data
|
||||
if (isEscaped == false && value == ESC) {
|
||||
m_data.push_back(ESC);
|
||||
m_data.push_back(0x00);
|
||||
if (updateCRC) {
|
||||
addCRC(ESC);
|
||||
addCRC(0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value == SYN) {
|
||||
m_data.push_back(ESC);
|
||||
m_data.push_back(0x01);
|
||||
if (updateCRC) {
|
||||
addCRC(ESC);
|
||||
addCRC(0x01);
|
||||
else if (isEscaped == false && 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;
|
||||
}
|
||||
else {
|
||||
else if (isEscaped == false) {
|
||||
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;
|
||||
}
|
||||
else if (m_unescapeState != 1) {
|
||||
if (updateCRC) {
|
||||
addCRC(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char SymbolString::push_back_unescape(const unsigned char value, bool& previousEscape, bool updateCRC)
|
||||
{
|
||||
if (updateCRC) {
|
||||
addCRC(value);
|
||||
}
|
||||
if (previousEscape == true) {
|
||||
if (value == 0x00) {
|
||||
m_data.push_back(ESC);
|
||||
previousEscape = false;
|
||||
return ESC;
|
||||
m_unescapeState = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (value == 0x01) {
|
||||
m_data.push_back(SYN);
|
||||
previousEscape = false;
|
||||
return SYN;
|
||||
m_unescapeState = 1;
|
||||
return RESULT_OK;
|
||||
}
|
||||
return 0; // invalid escape sequence
|
||||
return RESULT_ERR_ESC; // invalid escape sequence
|
||||
}
|
||||
if (value == ESC) {
|
||||
previousEscape = true;
|
||||
return 1; // escape sequence not yet finished
|
||||
else if (value == ESC) {
|
||||
if (updateCRC) {
|
||||
addCRC(value);
|
||||
}
|
||||
m_unescapeState = 2;
|
||||
return RESULT_IN_ESC;
|
||||
}
|
||||
if (updateCRC) {
|
||||
addCRC(value);
|
||||
}
|
||||
m_data.push_back(value);
|
||||
return value;
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
void SymbolString::addCRC(const unsigned char value) {
|
||||
|
||||
+31
-35
@@ -37,71 +37,61 @@ static const unsigned char BROADCAST = 0xFE; // the broadcast destination addres
|
||||
|
||||
|
||||
/**
|
||||
* @brief A string of bus symbols.
|
||||
* @brief A string of escaped or unescaped bus symbols.
|
||||
*/
|
||||
class SymbolString
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a new empty SymbolString.
|
||||
* @brief Creates a new unescaped empty instance.
|
||||
* @param escaped whether to create an escaped instance.
|
||||
*/
|
||||
SymbolString() : m_crc(0) {}
|
||||
SymbolString() : m_unescapeState(1), m_crc(0) {}
|
||||
/**
|
||||
* @brief Creates a new escaped SymbolString from an unescaped hex string and adds the calculated CRC.
|
||||
* @brief Creates a new escaped instance from an unescaped hex string and adds the calculated CRC.
|
||||
* @param str the unescaped hex string.
|
||||
*/
|
||||
SymbolString(const std::string str);
|
||||
/**
|
||||
* @brief Creates a new unescaped SymbolString from a hex string.
|
||||
* @param escaped whether the hex string is escaped and shall be unescaped.
|
||||
* @brief Creates a new unescaped instance from a hex string.
|
||||
* @param isEscaped whether the hex string is escaped and shall be unescaped.
|
||||
* @param str the hex string.
|
||||
*/
|
||||
SymbolString(const std::string str, bool escaped);
|
||||
SymbolString(const std::string str, const bool isEscaped);
|
||||
/**
|
||||
* @brief Returns the symbols as hex string.
|
||||
* @param escaped whether to unescape the symbols.
|
||||
* @param unescape whether to unescape an escaped instance.
|
||||
* @return the symbols as hex string.
|
||||
*/
|
||||
const std::string getDataStr(bool unescape=false);
|
||||
const std::string getDataStr(const bool unescape=true);
|
||||
/**
|
||||
* @brief Returns the symbol at the specified index.
|
||||
* @brief Returns a reference to the symbol at the specified index.
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the symbol at the specified index.
|
||||
* @throw std::out_of_range if @a index is invalid.
|
||||
* @return the reference to the symbol at the specified index.
|
||||
*/
|
||||
unsigned char at(const size_t index) { return m_data.at(index); }
|
||||
unsigned char& operator[](const size_t index) { if (index >= m_data.size()) m_data.resize(index+1); return m_data[index]; }
|
||||
/**
|
||||
* @brief Returns the symbol at the specified index.
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the symbol at the specified index.
|
||||
*/
|
||||
unsigned char operator[](const size_t index) { return m_data[index]; }
|
||||
const unsigned char& operator[](const size_t index) const { return m_data[index]; }
|
||||
/**
|
||||
* @brief Returns the symbol at the specified index.
|
||||
* @param index the index of the symbol to return.
|
||||
* @return the symbol at the specified index.
|
||||
* @brief Returns 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).
|
||||
*/
|
||||
unsigned char operator[](const size_t index) const { return m_data[index]; }
|
||||
bool operator==(SymbolString other) { return (m_unescapeState==0)==(m_unescapeState==0) && m_data==other.m_data; }
|
||||
/**
|
||||
* @brief Inserts a the symbol at the specified index.
|
||||
* @param index the index at which to insert the symbol.
|
||||
* @param value the symbol to insert.
|
||||
*/
|
||||
void insert(const size_t index, const unsigned char value) { m_data.insert(m_data.begin()+index, value); }
|
||||
/**
|
||||
* @brief Appends a the symbol to the end of the symbol string and escapes it if necessary.
|
||||
* @brief Appends a the symbol to the end of the symbol string and escapes/unescapes it if necessary.
|
||||
* @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.
|
||||
*/
|
||||
void push_back_escape(const unsigned char value, bool updateCRC=true);
|
||||
/**
|
||||
* @brief Appends a the symbol to the end of the symbol string and unescapes it.
|
||||
* @param value the symbol to append.
|
||||
* @param previousEscape whether the previous value was the escape symbol (set to false for the initial call).
|
||||
* @param updateCrc whether to update the calculated CRC in @a m_crc.
|
||||
* @return if previousEscape is false on return: the unescaped symbol. otherwise: zero if the escape sequence was invalid, one if the escape sequence is not yet finished.
|
||||
*/
|
||||
unsigned char push_back_unescape(const unsigned char value, bool& previousEscape, bool updateCRC=true);
|
||||
int push_back(const unsigned char value, const bool isEscaped, const bool updateCRC=true);
|
||||
/**
|
||||
* @brief Returns the number of symbols in this symbol string.
|
||||
* @return the number of available symbols.
|
||||
@@ -115,7 +105,7 @@ public:
|
||||
/**
|
||||
* @brief Clears the symbols.
|
||||
*/
|
||||
void clear() { m_crc=0; m_data.clear(); }
|
||||
void clear() { m_data.clear(); m_unescapeState = m_unescapeState==0 ? 0 : 1; m_crc = 0; }
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -128,6 +118,12 @@ private:
|
||||
* @brief the string of bus symbols.
|
||||
*/
|
||||
std::vector<unsigned char> m_data;
|
||||
/**
|
||||
* @brief 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;
|
||||
/**
|
||||
* @brief the calculated CRC.
|
||||
*/
|
||||
|
||||
@@ -25,15 +25,9 @@ using namespace libebus;
|
||||
|
||||
int main ()
|
||||
{
|
||||
SymbolString sstr("10feb5050427a915aa");
|
||||
SymbolString sstr = SymbolString("10feb5050427a915aa");
|
||||
|
||||
std::stringstream out;
|
||||
for (size_t i = 0; i<sstr.size(); i++) {
|
||||
out << std::nouppercase << std::setw(2) << std::hex
|
||||
<< std::setfill('0') << static_cast<unsigned>(sstr[i]);
|
||||
}
|
||||
|
||||
std::string gotStr = out.str(), expectStr = "10feb5050427a90015a90177";
|
||||
std::string gotStr = sstr.getDataStr(false), expectStr = "10feb5050427a90015a90177";
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "ctor escaped successful." << std::endl;
|
||||
@@ -54,7 +48,7 @@ int main ()
|
||||
<< std::setfill('0') << static_cast<unsigned>(expectCrc)
|
||||
<< std::endl;
|
||||
|
||||
gotStr = sstr.getDataStr(true), expectStr = "10feb5050427a915aa77";
|
||||
gotStr = sstr.getDataStr(), expectStr = "10feb5050427a915aa77";
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "unescape successful." << std::endl;
|
||||
@@ -63,7 +57,9 @@ int main ()
|
||||
<< ", expected " << expectStr << std::endl;
|
||||
|
||||
sstr = SymbolString("10feb5050427a90015a90177", true);
|
||||
gotStr = sstr.getDataStr(false);
|
||||
|
||||
gotStr = sstr.getDataStr();
|
||||
|
||||
if (strcasecmp(gotStr.c_str(), expectStr.c_str()) == 0)
|
||||
std::cout << "ctor unescaped successful." << std::endl;
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user