store bit count separately, added ignored type (IGN), moved field length definition from part to type and allow adjusting length for bit types, added PartType masterDataID, simplfied

This commit is contained in:
john30
2014-11-22 19:17:30 +01:00
parent 1f33218692
commit 24e46f5b44
3 changed files with 237 additions and 186 deletions
+182 -150
View File
@@ -29,11 +29,12 @@
/** the known data field types. */
static const dataType_t dataTypes[] = {
{"IGN",16*8,bt_str, IGN|ADJ, 0, 1, 16, 0, 0}, // >= 1 byte ignored data
{"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space
{"HEX",16*8,bt_hexstr, ADJ, 0, 2, 47, 0, 0}, // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
{"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday)
{"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday)
{"BDA", 24, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99)
{"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) // TODO remove duplicate of BDA
{"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) // TODO remove duplicate of BDA
{"HDA", 24, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA
{"BTI", 24, bt_tim, BCD|REV, 0, 8, 8, 0, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
{"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
@@ -52,41 +53,14 @@ static const dataType_t dataTypes[] = {
{"D2C", 16, bt_num, SIG, 0x8000, 0x8001, 0x7fff, 16, 2}, // signed number (fraction 1/16), -2047.9 - +2047.9
{"ULG", 32, bt_num, LST, 0xffffffff, 0, 0xfffffffe, 1, 0}, // unsigned integer, 0 - 4294967294
{"SLG", 32, bt_num, SIG, 0x80000000, 0x80000001, 0xffffffff, 1, 0}, // signed integer, -2147483647 - +2147483647
{"BI0", 1, bt_num, LST, 0, 0, 0x1, 1, 0}, // single bit 0
{"BI1", 1, bt_num, LST, 0, 0, 0x1, 1, 1}, // single bit 1
{"BI2", 1, bt_num, LST, 0, 0, 0x1, 1, 2}, // single bit 2
{"BI3", 1, bt_num, LST, 0, 0, 0x1, 1, 3}, // single bit 3
{"BI4", 1, bt_num, LST, 0, 0, 0x1, 1, 4}, // single bit 4
{"BI5", 1, bt_num, LST, 0, 0, 0x1, 1, 5}, // single bit 5
{"BI6", 1, bt_num, LST, 0, 0, 0x1, 1, 6}, // single bit 6
{"BI7", 1, bt_num, LST, 0, 0, 0x1, 1, 7}, // single bit 7
{"B01", 2, bt_num, LST, 0, 0, 0x3, 1, 0}, // two bits 0-1
{"B12", 2, bt_num, LST, 0, 0, 0x3, 1, 1}, // two bits 1-2
{"B23", 2, bt_num, LST, 0, 0, 0x3, 1, 2}, // two bits 2-3
{"B34", 2, bt_num, LST, 0, 0, 0x3, 1, 3}, // two bits 3-4
{"B45", 2, bt_num, LST, 0, 0, 0x3, 1, 4}, // two bits 4-5
{"B56", 2, bt_num, LST, 0, 0, 0x3, 1, 5}, // two bits 5-6
{"B67", 2, bt_num, LST, 0, 0, 0x3, 1, 6}, // two bits 6-7
{"B02", 3, bt_num, LST, 0, 0, 0x7, 1, 0}, // three bits 0-2
{"B13", 3, bt_num, LST, 0, 0, 0x7, 1, 1}, // three bits 1-3
{"B24", 3, bt_num, LST, 0, 0, 0x7, 1, 2}, // three bits 2-4
{"B35", 3, bt_num, LST, 0, 0, 0x7, 1, 3}, // three bits 3-5
{"B46", 3, bt_num, LST, 0, 0, 0x7, 1, 4}, // three bits 4-6
{"B57", 3, bt_num, LST, 0, 0, 0x7, 1, 5}, // three bits 5-7
{"B03", 4, bt_num, LST, 0, 0, 0xf, 1, 0}, // four bits 0-3
{"B14", 4, bt_num, LST, 0, 0, 0xf, 1, 1}, // four bits 1-4
{"B25", 4, bt_num, LST, 0, 0, 0xf, 1, 2}, // four bits 2-5
{"B36", 4, bt_num, LST, 0, 0, 0xf, 1, 3}, // four bits 3-6
{"B47", 4, bt_num, LST, 0, 0, 0xf, 1, 4}, // four bits 4-7
{"B04", 5, bt_num, LST, 0, 0, 0x1f, 1, 0}, // five bits 0-4
{"B15", 5, bt_num, LST, 0, 0, 0x1f, 1, 1}, // five bits 1-5
{"B26", 5, bt_num, LST, 0, 0, 0x1f, 1, 2}, // five bits 2-6
{"B37", 5, bt_num, LST, 0, 0, 0x1f, 1, 3}, // five bits 3-7
{"B05", 6, bt_num, LST, 0, 0, 0x3f, 1, 0}, // six bits 0-5
{"B16", 6, bt_num, LST, 0, 0, 0x3f, 1, 1}, // six bits 1-6
{"B27", 6, bt_num, LST, 0, 0, 0x3f, 1, 2}, // six bits 2-7
{"B06", 7, bt_num, LST, 0, 0, 0x7f, 1, 0}, // seven bits 0-6
{"B17", 7, bt_num, LST, 0, 0, 0x7f, 1, 1}, // seven bits 1-7
{"BI0", 7, bt_num, ADJ|LST, 0, 0, 0xef, 1, 0}, // bit 0 (up to 7 bits until bit 6)
{"BI1", 7, bt_num, ADJ|LST, 0, 0, 0x7f, 1, 1}, // bit 1 (up to 7 bits until bit 7)
{"BI2", 6, bt_num, ADJ|LST, 0, 0, 0x3f, 1, 2}, // bit 2 (up to 6 bits until bit 7)
{"BI3", 5, bt_num, ADJ|LST, 0, 0, 0x1f, 1, 3}, // bit 3 (up to 5 bits until bit 7)
{"BI4", 4, bt_num, ADJ|LST, 0, 0, 0x0f, 1, 4}, // bit 4 (up to 4 bits until bit 7)
{"BI5", 3, bt_num, ADJ|LST, 0, 0, 0x07, 1, 5}, // bit 5 (up to 3 bits until bit 7)
{"BI6", 2, bt_num, ADJ|LST, 0, 0, 0x03, 1, 6}, // bit 6 (up to 2 bits until bit 7)
{"BI7", 1, bt_num, ADJ|LST, 0, 0, 0x01, 1, 7}, // bit 7
};
@@ -132,18 +106,17 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
std::string unit, comment;
PartType partType;
unsigned int divisor = 0;
unsigned char length;
const bool isTemplate = dstAddress == SYN;
std::string token;
if (it == end)
break;
// name;[m|s][len];type[;[divisor|values][;[unit][;[comment]]]]
// name;part;type[:len][;[divisor|values][;[unit][;[comment]]]]
const std::string name = *it++;
if (it == end)
break;
const char* posStr = (*it++).c_str();
const char* partStr = (*it++).c_str();
if (it == end)
break;
@@ -151,18 +124,17 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
firstName = name;
firstComment = comment;
}
if (dstAddress == BROADCAST || isMaster(dstAddress)
|| (isTemplate == false && isSetMessage == true && (posStr[0] == 0 || posStr[0] <= '9'))
|| posStr[0] == 'm') { // master data
partType = pt_masterData;
if (posStr[0] == 'm')
posStr++;
if (isTemplate == false && strcasecmp(partStr, "I") == 0) {
partType = pt_masterDataID;
}
else if ((isTemplate == false && isSetMessage == false && (posStr[0] == 0 || posStr[0] <= '9'))
|| posStr[0] == 's') { // slave data
else if (dstAddress == BROADCAST || isMaster(dstAddress)
|| (isTemplate == false && isSetMessage == true && partStr[0] == 0)
|| strcasecmp(partStr, "M") == 0) { // master data
partType = pt_masterData;
}
else if ((isTemplate == false && isSetMessage == false && partStr[0] == 0)
|| strcasecmp(partStr, "S") == 0) { // slave data
partType = pt_slaveData;
if (posStr[0] == 's')
posStr++;
}
else if (isTemplate) {
partType = pt_any;
@@ -172,17 +144,10 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
break;
}
if (posStr[0] == 0) {
length = 0;
}
else {
length = parseInt(posStr, 10, 1, MAX_POS, result);
if (result != RESULT_OK)
break;
}
const char* typeStr = (*it++).c_str();
if (typeStr[0] == 0) {
std::string typeStr = *it++;
if (typeStr.empty() == true) {
if (name.empty() == false || partStr[0] != 0)
result = RESULT_ERR_INVALID_ARG;
break;
}
@@ -190,7 +155,7 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
if (it != end) {
std::string divisorStr = *it++;
if (divisorStr.empty() == false) {
if (divisorStr.find_first_not_of("0123456789") == std::string::npos) {
if (divisorStr.find('=') == std::string::npos) {
divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result);
if (result != RESULT_OK)
break;
@@ -231,47 +196,73 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
comment.clear();
}
// check for reference(s) to templates
if (templates.empty() == false) {
std::istringstream stream(typeStr);
bool found = false;
while (std::getline(stream, token, VALUE_SEPARATOR) != 0) {
std::map< std::string, DataField*>::const_iterator ref = templates.find(token);
if (ref == templates.end()) {
if (found == false)
break; // fallback to direct definition
result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition
break;
size_t pos = typeStr.find(':');
unsigned char length;
if (pos == std::string::npos) {
length = 0;
// check for reference(s) to templates
if (templates.empty() == false) {
std::istringstream stream(typeStr);
bool found = false;
std::string lengthStr;
while (std::getline(stream, token, VALUE_SEPARATOR) != 0) {
std::map<std::string, DataField*>::const_iterator ref = templates.find(token);
if (ref == templates.end()) {
if (found == false)
break; // fallback to direct definition
result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition
break;
}
found = true;
result = ref->second->derive(name, comment, unit, partType, divisor, values, fields);
if (result != RESULT_OK)
break;
}
if (length > 1) {
result = RESULT_ERR_INVALID_ARG; // different length not possible for derivation
break;
}
found = true;
result = ref->second->derive(name, comment, unit, partType, divisor, values, fields);
if (result != RESULT_OK)
break;
if (found == true || result != RESULT_OK)
break; // TODO check for found == true
}
if (found == true || result != RESULT_OK)
break;
}
else {
length = parseInt(typeStr.substr(pos+1).c_str(), 10, 1, MAX_POS, result);
if (result != RESULT_OK)
break;
typeStr = typeStr.substr(0, pos);
}
SingleDataField* add = NULL;
const char* typeName = typeStr.c_str();
for (size_t i = 0; result == RESULT_OK && add == NULL && i < sizeof(dataTypes) / sizeof(dataTypes[0]); i++) {
dataType_t dataType = dataTypes[i];
if (strcasecmp(typeStr, dataType.name) == 0) {
unsigned char numBytes = (dataType.numBits + 7) / 8;
unsigned char useLength = length;
if ((dataType.flags & ADJ) != 0) {
if (useLength == 0)
useLength = 1; // minimum length defaults to 1
else if (useLength > numBytes) {
if (strcasecmp(typeName, dataType.name) == 0) {
unsigned char bitCount = dataType.maxBits;
unsigned char useLength = (bitCount + 7) / 8;
if ((dataType.flags & ADJ) != 0) { // adjustable length
if ((bitCount % 8) != 0) {
if (length == 0) {
useLength = 1; // default length: 1 byte
bitCount = 1; // default count: 1 bit
}
else if (length > bitCount) {
result = RESULT_ERR_INVALID_ARG; // invalid length
break;
}
else {
bitCount = length;
useLength = (length + 7) / 8;
}
}
else if (length == 0) {
useLength = 1; // default length: 1 byte
}
else if (length <= useLength) {
useLength = length;
}
else {
result = RESULT_ERR_INVALID_ARG; // invalid length
break;
}
}
else if (useLength == 0)
useLength = numBytes;
else if (useLength != numBytes)
else if (length > 0 && length != useLength)
continue; // check for another one with same name but different length
switch (dataType.type)
@@ -294,7 +285,7 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
else
divisor *= dataType.divisor;
add = new NumberDataField(name, comment, unit, dataType, partType, useLength, divisor);
add = new NumberDataField(name, comment, unit, dataType, partType, useLength, bitCount, divisor);
break;
}
if (values.begin()->first < dataType.minValueOrLength
@@ -303,7 +294,7 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
break;
}
add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, values);
add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, bitCount, values);
break;
}
}
@@ -330,22 +321,17 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
}
bool SingleDataField::hasFullByteOffset()
{
return m_length > 1 || (m_dataType.numBits % 8) == 0
|| m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) >= 8;
}
result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset,
SymbolString& slaveData, unsigned char slaveOffset,
std::ostringstream& output,
bool verbose, char separator)
{
SymbolString& input = m_partType == pt_masterData ? masterData : slaveData;
SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData;
unsigned char offset;
switch (m_partType)
{
case pt_masterData:
case pt_masterDataID:
offset = 5 + masterOffset; // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
@@ -355,7 +341,14 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff
return RESULT_ERR_INVALID_ARG; // invalid part type
}
if (verbose)
if (isIgnored() == true) {
if (offset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
}
return RESULT_OK;
}
if (verbose == true)
output << m_name << "=";
result_t result = readSymbols(input, offset, output);
@@ -375,11 +368,12 @@ result_t SingleDataField::write(std::istringstream& input,
SymbolString& slaveData, unsigned char slaveOffset,
char separator)
{
SymbolString& output = m_partType == pt_masterData ? masterData : slaveData;
SymbolString& output = m_partType != pt_slaveData ? masterData : slaveData;
unsigned char offset;
switch (m_partType)
{
case pt_masterData:
case pt_masterDataID:
offset = 5 + masterOffset; // skip QQ ZZ PB SB NN
break;
case pt_slaveData:
@@ -423,6 +417,7 @@ result_t StringDataField::readSymbols(SymbolString& input,
if (baseOffset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
}
if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first)
start = m_length - 1;
incr = -1;
@@ -494,6 +489,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
incr = -1;
}
if (isIgnored() == true) {
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
output[baseOffset + offset] = m_dataType.replacement; // fill up with replacement
}
return RESULT_OK;
}
result_t result;
size_t i = 0;
for (size_t offset = start; i < count; offset += incr, i++) {
@@ -581,6 +582,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
}
bool NumericDataField::hasFullByteOffset(bool after)
{
return m_length > 1 || (m_bitCount % 8) == 0
|| (after == true && m_bitOffset + (m_bitCount % 8) >= 8);
}
result_t NumericDataField::readRawValue(SymbolString& input,
unsigned char baseOffset, unsigned int& value)
{
@@ -619,9 +626,10 @@ result_t NumericDataField::readRawValue(SymbolString& input,
if ((m_dataType.flags & BCD) == 0) {
value >>= m_bitOffset;
if ((m_dataType.numBits % 8) != 0)
value &= (1 << m_dataType.numBits) - 1;
if ((m_bitCount % 8) != 0)
value &= (1 << m_bitCount) - 1;
}
return RESULT_OK;
}
@@ -638,8 +646,9 @@ result_t NumericDataField::writeRawValue(unsigned int value,
}
if ((m_dataType.flags & BCD) == 0) {
if ((m_dataType.numBits % 8) != 0)
value &= (1 << m_dataType.numBits) - 1;
if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0)
return RESULT_ERR_INVALID_ARG;
value <<= m_bitOffset;
}
for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) {
@@ -656,7 +665,7 @@ result_t NumericDataField::writeRawValue(unsigned int value,
ch = (value / exp) & 0xff;
exp = exp << 8;
}
if (offset == start && (m_dataType.numBits % 8) != 0 && baseOffset + offset < output.size())
if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size())
output[baseOffset + offset] |= ch;
else
output[baseOffset + offset] = ch;
@@ -687,10 +696,10 @@ result_t NumberDataField::derive(std::string name, std::string comment,
if (divisor != 1)
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values));
fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values));
}
else
fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, divisor));
fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, divisor));
return RESULT_OK;
}
@@ -710,27 +719,27 @@ result_t NumberDataField::readSymbols(SymbolString& input,
return RESULT_OK;
}
bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_dataType.numBits - 1))) != 0;
if (m_dataType.numBits == 32) {
bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_bitCount - 1))) != 0;
if (m_bitCount == 32) {
if (negative == false) {
if (m_divisor <= 1)
output << static_cast<unsigned>(value);
else
output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0)
output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0)
<< std::fixed << static_cast<float>(value / (float) m_divisor);
return RESULT_OK;
}
signedValue = (int) value; // negative signed value
}
else if (negative) // negative signed value
signedValue = (int) value - (1 << m_dataType.numBits);
signedValue = (int) value - (1 << m_bitCount);
else
signedValue = (int) value;
if (m_divisor <= 1)
output << static_cast<int>(signedValue);
else
output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0)
output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0)
<< std::fixed << static_cast<float>(signedValue / (float) m_divisor);
return RESULT_OK;
@@ -742,18 +751,17 @@ result_t NumberDataField::writeSymbols(std::istringstream& input,
unsigned int value;
const char* str = input.str().c_str();
if (strcasecmp(str, NULL_VALUE) == 0)
// replacement value
value = m_dataType.replacement;
if (isIgnored() == true || strcasecmp(str, NULL_VALUE) == 0)
value = m_dataType.replacement; // replacement value
else if (str == NULL || *str == 0)
return RESULT_ERR_INVALID_ARG; // input too short
return RESULT_ERR_INVALID_ARG; // input too short//TODO LENGTH_SEPARATOR
else {
char* strEnd = NULL;
if (m_divisor <= 1) {
if ((m_dataType.flags & SIG) != 0) {
int signedValue = strtol(str, &strEnd, 10);
if (signedValue < 0 && m_dataType.numBits != 32)
value = (unsigned int) (signedValue + (1 << m_dataType.numBits));
if (signedValue < 0 && m_bitCount != 32)
value = (unsigned int) (signedValue + (1 << m_bitCount));
else
value = (unsigned int) signedValue;
}
@@ -771,8 +779,8 @@ result_t NumberDataField::writeSymbols(std::istringstream& input,
if ((m_dataType.flags & SIG) != 0) {
if (dvalue < -(1LL << (8 * m_length)) || dvalue >= (1LL << (8 * m_length)))
return RESULT_ERR_INVALID_ARG; // value out of range
if (dvalue < 0 && m_dataType.numBits != 32)
value = (unsigned int) (dvalue + (1 << m_dataType.numBits));
if (dvalue < 0 && m_bitCount != 32)
value = (unsigned int) (dvalue + (1 << m_bitCount));
else
value = (unsigned int) dvalue;
}
@@ -784,7 +792,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input,
}
if ((m_dataType.flags & SIG) != 0) { // signed value
if ((value & (1 << (m_dataType.numBits - 1))) != 0) { // negative signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_dataType.minValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
}
@@ -823,7 +831,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment,
else
values = m_values;
fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values));
fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values));
return RESULT_OK;
}
@@ -854,14 +862,17 @@ result_t ValueListDataField::readSymbols(SymbolString& input,
result_t ValueListDataField::writeSymbols(std::istringstream& input,
unsigned char baseOffset, SymbolString& output)
{
if (isIgnored() == true)
return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value
const char* str = input.str().c_str();
for (std::map<unsigned int, std::string>::iterator it = m_values.begin(); it != m_values.end(); it++)
if (it->second.compare(str) == 0)
return writeRawValue(it->first, baseOffset, output);
if (strcasecmp(str, NULL_VALUE) == 0) // replacement value
return writeRawValue(m_dataType.replacement, baseOffset, output);
if (strcasecmp(str, NULL_VALUE) == 0)
return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value
return RESULT_ERR_INVALID_ARG; // value assignment not found
}
@@ -878,15 +889,17 @@ unsigned char DataFieldSet::getLength(PartType partType)
{
unsigned char length = 0;
bool previousFullByteOffset[] = { true, true, true };
bool previousFullByteOffset[] = { true, true, true, true };
for (std::vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it;
if (field->getPartType() == partType) {
length += field->getLength(partType);
if (previousFullByteOffset[partType] == false) {
if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false)
length--;
}
previousFullByteOffset[partType] = field->hasFullByteOffset();
length += field->getLength(partType);
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
}
}
@@ -918,29 +931,38 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset
output << m_name << "={ ";
bool first = true;
unsigned char offsets[] = { 0, masterOffset, slaveOffset };
bool previousFullByteOffset[] = { true, true, true };
unsigned char offsets[4];
memset(offsets, 0, sizeof(offsets));
offsets[pt_masterData] = masterOffset;
offsets[pt_slaveData] = slaveOffset;
bool previousFullByteOffset[] = { true, true, true, true };
for (std::vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
if (first)
first = false;
else
output << separator;
SingleDataField* field = *it;
bool ignored = field->isIgnored();
PartType partType = field->getPartType();
if (previousFullByteOffset[partType] == false) {
offsets[partType]--;
if (ignored == false) {
if (first)
first = false;
else
output << separator;
}
if (partType == pt_masterDataID)
partType = pt_masterData;
if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false)
offsets[partType]--;
result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator);
if (result != RESULT_OK)
return result;
offsets[partType] += field->getLength(partType);
previousFullByteOffset[partType] = field->hasFullByteOffset();
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
}
if (verbose) {
if (verbose == true) {
if (m_comment.length() > 0)
output << " [" << m_comment << "]";
output << "}";
@@ -956,18 +978,28 @@ result_t DataFieldSet::write(std::istringstream& input,
{
std::string token;
unsigned char offsets[] = { 0, masterOffset, slaveOffset };
bool previousFullByteOffset[] = { true, true, true };
unsigned char offsets[4];
memset(offsets, 0, sizeof(offsets));
offsets[pt_masterData] = masterOffset;
offsets[pt_slaveData] = slaveOffset;
bool previousFullByteOffset[] = { true, true, true, true };
for (std::vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
SingleDataField* field = *it;
bool ignored = field->isIgnored();
PartType partType = field->getPartType();
if (previousFullByteOffset[partType] == false) {
if (partType == pt_masterDataID)
partType = pt_masterData;
if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false)
offsets[partType]--;
}
result_t result;
if (m_fields.size() > 1) {
if (std::getline(input, token, separator) == 0)
if (ignored == true)
token.clear();
else if (std::getline(input, token, separator) == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
std::istringstream single(token);
result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator);
}
@@ -978,7 +1010,7 @@ result_t DataFieldSet::write(std::istringstream& input,
return result;
offsets[partType] += field->getLength(partType);
previousFullByteOffset[partType] = field->hasFullByteOffset();
previousFullByteOffset[partType] = field->hasFullByteOffset(true);
}
return RESULT_OK;
+30 -13
View File
@@ -28,9 +28,10 @@
/** the message part in which a data field is stored. */
enum PartType {
pt_any, // stored in any data (master or slave)
pt_masterData, // stored in master data
pt_slaveData, // stored in slave data
pt_any, // stored in any data (master or slave)
pt_masterData, // stored in master data
pt_masterDataID, // stored in master data and also used as message ID part
pt_slaveData, // stored in slave data
};
/** the available base data types. */
@@ -49,11 +50,12 @@ const unsigned int REV = 0x04; // reverted binary representation (most significa
const unsigned int SIG = 0x08; // signed value
const unsigned int LST = 0x10; // value list is possible (without applied divisor)
const unsigned int DAY = 0x20; // forced value list defaulting to week days
const unsigned int IGN = 0x40; // ignore value during read and write
/** the structure for defining field types with their properties. */
typedef struct {
const char* name; // field identifier
const unsigned int numBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD)
const unsigned int maxBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD)
const BaseType type; // base data type
const unsigned int flags; // flags (e.g. @a BCD)
const unsigned int replacement; // replacement value (fill-up value for @a bt_str / @a bt_hexstr, no replacement if equal to @a minValueOrLength for @a bt_num)
@@ -208,6 +210,11 @@ public:
* @return the value unit.
*/
std::string getUnit() const { return m_unit; }
/**
* @brief Get whether this field is ignored.
* @return whether this field is ignored.
*/
bool isIgnored() const { return (m_dataType.flags & IGN) != 0; }
/**
* @brief Get the message part in which the field is stored.
* @return the message part in which the field is stored.
@@ -218,10 +225,11 @@ public:
// re-use same position as previous field as not all bits of fully consumed yet
/**
* @brief Get whether this field uses a full byte offset.
* @param after @p true to check after consuming the bits, false to check before.
* @return true if this field uses a full byte offset, false if this field
* only consumes a part of a byte and a subsequent field may re-use the same offset.
*/
bool hasFullByteOffset();
virtual bool hasFullByteOffset(bool after) { return true; }
/**
* @brief Reads the value from the master or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
@@ -337,17 +345,20 @@ public:
* @param dataType the data type definition.
* @param partType the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param bitCount the number of bits in the binary value.
* @param bitOffset the offset to the first bit in the binary value.
*/
NumericDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char length, const unsigned char bitOffset)
const unsigned char length, const unsigned char bitCount, const unsigned char bitOffset)
: SingleDataField(name, comment, unit, dataType, partType, length),
m_bitOffset(bitOffset) {}
m_bitCount(bitCount), m_bitOffset(bitOffset) {}
/**
* @brief Destructor.
*/
virtual ~NumericDataField() {}
// @copydoc
virtual bool hasFullByteOffset(bool after);
protected:
@@ -368,9 +379,13 @@ protected:
*/
result_t writeRawValue(unsigned int value, const unsigned char offset, SymbolString& output);
/** the number of bits in the binary value. */
const unsigned char m_bitCount;
/** the offset to the first bit in the binary value. */
const unsigned char m_bitOffset;
};
@@ -393,9 +408,10 @@ public:
*/
NumberDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char length, const unsigned int divisor)
: NumericDataField(name, comment, unit, dataType, partType, length,
(dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0),
const unsigned char length, const unsigned char bitCount,
const unsigned int divisor)
: NumericDataField(name, comment, unit, dataType, partType, length, bitCount,
(dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0),
m_divisor(divisor) {}
/**
* @brief Destructor.
@@ -439,9 +455,10 @@ public:
*/
ValueListDataField(const std::string name, const std::string comment,
const std::string unit, const dataType_t dataType, const PartType partType,
const unsigned char length, const std::map<unsigned int, std::string> values)
: NumericDataField(name, comment, unit, dataType, partType, length,
(dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0),
const unsigned char length, const unsigned char bitCount,
const std::map<unsigned int, std::string> values)
: NumericDataField(name, comment, unit, dataType, partType, length, bitCount,
(dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0),
m_values(values) {}
/**
* @brief Destructor.
+25 -23
View File
@@ -43,21 +43,23 @@ int main()
{
std::string checks[][5] = {
//name;[len];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags
{"x;10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x;10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""},
{"x;10;str", " ", "10fe07000a20202020202020202020", "00", ""},
{"x;11;str", "", "10fe07000a20202020202020202020", "00", "rW"},
{"x;;ign:10", "", "10fe07000a00000000000000000000", "00", ""},
{"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x;;str:10", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""},
{"x;;str:10", " ", "10fe07000a20202020202020202020", "00", ""},
{"x;;str:11", "", "10fe07000a20202020202020202020", "00", "rW"},
{"x;;hex", "20", "10fe07000120", "00", ""},
{"x;10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x;11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"},
{"x;;hex:10", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""},
{"x;;hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"},
{"x;;bda", "26.10.2014","10fe07000426100014", "00", ""},
{"x;;bda", "01.01.2000","10fe07000401010000", "00", ""},
{"x;;bda", "31.12.2099","10fe07000431120099", "00", ""},
{"x;;bda", "", "10fe07000432100014", "00", "rw"},
{"x;3;bda","26.10.2014","10fe070003261014", "00", ""},
{"x;3;bda","01.01.2000","10fe070003010100", "00", ""},
{"x;3;bda","31.12.2099","10fe070003311299", "00", ""},
{"x;3;bda","", "10fe070003321299", "00", "rw"},
{"x;;bda:3","26.10.2014","10fe070003261014", "00", ""},
{"x;;bda:3","01.01.2000","10fe070003010100", "00", ""},
{"x;;bda:3","31.12.2099","10fe070003311299", "00", ""},
{"x;;bda:3","", "10fe070003321299", "00", "rw"},
{"x;;bti", "21:04:58", "10fe070003580421", "00", ""},
{"x;;bti", "00:00:00", "10fe070003000000", "00", ""},
{"x;;bti", "23:59:59", "10fe070003595923", "00", ""},
@@ -84,8 +86,8 @@ int main()
{"x;;bcd", "99", "10feffff0199", "00", ""},
{"x;;bcd", "-", "10feffff01ff", "00", ""},
{"x;;bcd", "", "10feffff019a", "00", "rw"},
{"x;16;str", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""},
{"x;17;uch", "", "10feffff00", "00", "c"},
{"x;;str:16", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""},
{"x;;uch:17", "", "10feffff00", "00", "c"},
{"x;s;uch", "0", "1025ffff0310111213", "0300010203", "W"},
{"x;s;uch", "0", "1025ffff00", "0100", ""},
{"x;s;uch;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""},
@@ -148,14 +150,15 @@ int main()
{"x;;bi3", "-", "10feffff0100", "00", ""},
{"x;;bi3;0=off,1=on","on", "10feffff0108", "00", ""},
{"x;;bi3;0=off,1=on","off","10feffff0100", "00", ""},
{"x;;b34", "1", "10feffff0108", "00", ""},
{"x;;b34", "-", "10feffff0100", "00", ""},
{"x;;b34", "3", "10feffff0118", "00", ""},
{"x;;b34;1=on","on", "10feffff0108", "00", ""},
{"x;;b34;1=on","-", "10feffff0100", "00", ""},
{"x;;b34;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""},
{"x;;b34;0=off,1=on","on", "10feffff0108", "00", ""},
{"x;;b34;0=off,1=on","off","10feffff0100", "00", ""},
{"x;;bi3:2", "1", "10feffff0108", "00", ""},
{"x;;bi3:2", "1", "10feffff01ef", "00", "W"},
{"x;;bi3:2", "-", "10feffff0100", "00", ""},
{"x;;bi3:2", "3", "10feffff0118", "00", ""},
{"x;;bi3:2;1=on","on", "10feffff0108", "00", ""},
{"x;;bi3:2;1=on","-", "10feffff0100", "00", ""},
{"x;;bi3:2;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""},
{"x;;bi3:2;0=off,1=on","on", "10feffff0108", "00", ""},
{"x;;bi3:2;0=off,1=on","off","10feffff0100", "00", ""},
{"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""},
{"x;s;uch","3","1050ffff00", "0103", ""},
{"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"},
@@ -164,8 +167,8 @@ int main()
{"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
{"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination
{"x;;bi3;;;;y;;bi5", "-;-", "10feffff0100", "00", ""}, // bit combination
{"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination, auto pos incr
{"x;;bi3;;;;y;;bi5;;;;t;;uch", "-;-;9","10feffff020009", "00", "RW"}, // bit combination
{"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination
{"x;;bi6:2;;;;y;;bi0:2;;;;t;;uch", "2;1;9","10feffff03800109", "00", ""}, // bit combination
{"temp;;d2b;;°C;Aussentemperatur","","", "", "t"}, // template with relative pos
{"x;;temp","18.004","10fe0700020112", "00", ""}, // reference to template
{"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos
@@ -202,7 +205,6 @@ int main()
}
std::vector<std::string>::iterator it = entries.begin();
result_t result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate ? SYN : mstr[1]);
if (failedCreate == true) {
if (result == RESULT_OK)
std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl;