Compare commits

...
10 Commits
Author SHA1 Message Date
John d8b2ae1bc8 fix constant field dump
Build / build (push) Failing after 1m52s
Coverage / coverage (push) Failing after 3m13s
2025-02-21 06:37:03 +01:00
John 1965639f07 add getter to grabbed message 2025-01-26 20:37:18 +01:00
John 1a2c810fdc avoid poll on scan messages 2025-01-26 07:53:43 +01:00
John a8f876d48b reduce to cdnversions only 2025-01-21 21:03:54 +01:00
John 4ebecb10e2 add dump with id key 2025-01-12 22:04:42 +01:00
John 34552eab61 fix ignored message id key for NN>3, fix longer message key check (fixes #1436), add log message on exceeded max length 2025-01-12 10:11:04 +01:00
John 0445e4412e fix parsing unexpected mdns txt response 2025-01-09 20:44:34 +01:00
John 2b3aa08673 fix previous commit for i386, optimize comparison 2025-01-07 08:21:26 +01:00
John e795ce604a add value range and step support, fix value list validation 2025-01-06 22:08:49 +01:00
John 88b039e58e simplify value list parsing 2025-01-06 19:48:52 +01:00
12 changed files with 493 additions and 203 deletions
+3 -12
View File
@@ -1,21 +1,12 @@
#!/bin/sh
version=`head -n 1 ../../VERSION`
revision=`git describe --always`
echo "ebusd=${version},${revision}" > versions.txt
echo "ebusd=${version},${revision}" > cdnversions.txt
devver=`curl -s https://adapter.ebusd.eu/v31/firmware/ChangeLog|grep "<h[0-9].*>Version "|head -n 1|sed -e 's#.*<code[^>]*>##' -e 's#<.*##' -e 's# ##'`
devbl=`curl -s https://adapter.ebusd.eu/v31/firmware/ChangeLog|grep "<h[0-9].*>Bootloader version"|head -n 1|sed -e 's#.*<code[^>]*>##' -e 's#<.*##' -e 's# ##'`
echo "device=${devver},${devbl}" >> versions.txt
echo "device=${devver},${devbl}" >> cdnversions.txt
devver=`curl -s https://adapter.ebusd.eu/v5/ChangeLog|grep "<h[0-9].*>Version "|head -n 1|sed -e 's#.*id="\([^"]*\)".*<code[^>]*>\([^<]*\)<.*#\2,\2,\1#'`
echo "device=${devver}" >> versions.txt
cp versions.txt cdnversions.txt
files=`find config/de -type f -or -type l`
../../src/lib/ebus/test/test_filereader $files|sed -e 's#^config/de/##' -e 's#^\([^ ]*\) #\1=#' -e 's# #,#g'|sort >> versions.txt
files=`find config/en -type f -or -type l`
for filever in $(../../src/lib/ebus/test/test_filereader $files|sed -e 's#^config/en/##' -e 's#^\([^ ]*\) #\1=#' -e 's# #,#g'); do
file=${filever%%=*}
ver=${filever#*=}
sed -i -e "s#^$file=\(.*\)\$#$file=\1,$ver#" versions.txt
done
echo "device=${devver}" >> cdnversions.txt
curl -sS https://ebus.github.io/en/versions.json -o veren.json
curl -sS https://ebus.github.io/de/versions.json -o verde.json
node -e 'fs=require("fs");e=JSON.parse(fs.readFileSync("veren.json","utf-8"));d=JSON.parse(fs.readFileSync("verde.json","utf-8"));console.log(Object.entries(d).map(([k,de])=>{en=e[k];return `${k}=${de.hash},${de.size},${de.mtime},${en.hash},${en.size},${en.mtime}`;}).join("\n"))'|sort >> cdnversions.txt
+6
View File
@@ -211,6 +211,12 @@ class GrabbedMessage {
*/
MasterSymbolString& getLastMasterData() { return m_lastMaster; }
/**
* Get the last @a SlaveSymbolString.
* @return the last @a SlaveSymbolString.
*/
SlaveSymbolString& getLastSlaveData() { return m_lastSlave; }
/**
* Dump the last received data and message count to the output.
* @param unknown whether to dump only if this message is unknown.
+4 -1
View File
@@ -408,7 +408,10 @@ int main(int argc, char* argv[], char* envp[]) {
fout.close();
}
}
if (overallResult == RESULT_OK && s_messageMap->getMaxIdLength() > 7) {
logNotice(lf_main, "max message ID length exceeded");
overallResult = RESULT_CONTINUE;
}
cleanup();
return overallResult == RESULT_OK ? EXIT_SUCCESS : EXIT_FAILURE;
}
+4 -2
View File
@@ -165,7 +165,7 @@ static const argDef argDefs[] = {
"Prefer LANG in multilingual configuration files [system default language, DE as fallback]"},
{"checkconfig", O_CHKCFG, nullptr, ARG_NO_ENV, "Check config files, then stop"},
{"dumpconfig", O_DMPCFG, "FORMAT", af_optional|ARG_NO_ENV,
"Check and dump config files in FORMAT (\"json\" or \"csv\"), then stop"},
"Check and dump config files in FORMAT (\"json\", \"csv\", or \"csvall\" for CSV with all attributes), then stop"},
{"dumpconfigto", O_DMPCTO, "FILE", 0, "Dump config files to FILE"},
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]"},
{"inject", 'i', "stop", af_optional|ARG_NO_ENV, "Inject remaining arguments as commands or already seen messages "
@@ -314,10 +314,12 @@ static int parse_opt(int key, char *arg, const argParseOpt *parseOpt, struct opt
case O_CHKCFG: // --checkconfig
opt->checkConfig = true;
break;
case O_DMPCFG: // --dumpconfig[=json|csv]
case O_DMPCFG: // --dumpconfig[=json|csv|csvall]
if (!arg || arg[0] == 0 || strcmp("csv", arg) == 0) {
// no further flags
opt->dumpConfig = OF_DEFINITION;
} else if (strcmp("csvall", arg) == 0) {
opt->dumpConfig = OF_DEFINITION | OF_ALL_ATTRS;
} else if (strcmp("json", arg) == 0) {
opt->dumpConfig = OF_DEFINITION | OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON;
} else {
+3 -2
View File
@@ -135,8 +135,9 @@ result_t TemParamDataType::writeSymbols(const size_t offset, const size_t length
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
}
}
if (value < getMinValue() || value > getMaxValue()) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
result_t ret = checkValueRange(value);
if (ret != RESULT_OK) {
return ret;
}
return writeRawValue(value, offset, length, output, usedLength);
}
+70 -17
View File
@@ -273,6 +273,7 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
string divisorStr = pluck("divisor", &row);
string valuesStr = pluck("values", &row);
string rangeStr = pluck("range", &row);
if (divisorStr.empty() && valuesStr.empty()) {
divisorStr = pluck("divisor/values", &row); // [divisor|values]
if (divisorStr.find('=') != string::npos) {
@@ -309,27 +310,22 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
while (getline(stream, token, VALUE_SEPARATOR)) {
FileReader::trim(&token);
const char* str = token.c_str();
char* strEnd = nullptr;
unsigned long id;
if (strncasecmp(str, "0x", 2) == 0) {
str += 2;
id = strtoul(str, &strEnd, 16); // hexadecimal
} else {
id = strtoul(str, &strEnd, 10); // decimal
}
if (strEnd == nullptr || strEnd == str || id > MAX_VALUE) {
size_t len = 0;
unsigned int id = parseInt(str, 0, 0, MAX_VALUE, &result, &len, true);
if (result != RESULT_OK) {
*errorDescription = "value "+token+" in field "+formatInt(fieldIndex);
result = RESULT_ERR_INVALID_LIST;
break;
}
str += len;
// remove blanks around '=' sign
while (*strEnd == ' ') strEnd++;
if (*strEnd != '=') {
while (*str == ' ') str++;
if (*str != '=') {
*errorDescription = "value "+token+" in field "+formatInt(fieldIndex);
result = RESULT_ERR_INVALID_LIST;
break;
}
token = string(strEnd + 1);
token = string(str + 1);
FileReader::trim(&token);
values[(unsigned int)id] = token;
}
@@ -370,6 +366,57 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
}
transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper);
const DataType* dataType = DataTypeList::getInstance()->get(typeName, length == REMAIN_LEN ? 0 : length);
if (dataType && dataType->isNumeric() && !rangeStr.empty()) {
const NumberDataType* numType = reinterpret_cast<const NumberDataType*>(dataType);
if (divisor != 1 && divisor != 0) {
result = numType->derive(divisor, numType->getBitCount(), &numType);
divisor = 1;
}
// either from-to or from-to:step
size_t sepPos = rangeStr.find('-', 1);
string part = rangeStr.substr(0, sepPos);
FileReader::trim(&part);
unsigned int from;
if (result == RESULT_OK) {
result = numType->parseInput(part, &from);
}
unsigned int to = from;
unsigned int inc = 0;
if (result == RESULT_OK) {
part = rangeStr.substr(sepPos+1);
FileReader::trim(&part);
sepPos = part.find(':');
if (sepPos != string::npos) {
string incStr = part.substr(sepPos + 1);
FileReader::trim(&incStr);
part = part.substr(0, sepPos);
FileReader::trim(&part);
result = numType->parseInput(incStr, &inc);
}
if (result == RESULT_OK) {
result = numType->parseInput(part, &to);
}
}
float ffrom = 0, fto = 0;
if (result == RESULT_OK) {
result = numType->getFloatFromRawValue(from, &ffrom);
}
if (result == RESULT_OK) {
result = numType->getFloatFromRawValue(to, &fto);
}
if (result == RESULT_OK && ffrom > fto) {
result = RESULT_ERR_INVALID_LIST;
}
if (result == RESULT_OK) {
result = numType->derive(from, to, inc, &numType);
};
if (result != RESULT_OK) {
*errorDescription = "\""+rangeStr+"\" in field "+formatInt(fieldIndex);
result = RESULT_ERR_OUT_OF_RANGE;
break;
}
dataType = numType;
}
if (!dataType) {
result = RESULT_ERR_NOTFOUND;
*errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex);
@@ -517,8 +564,11 @@ result_t SingleDataField::create(const string& name, const map<string, string>&
*returnField = new SingleDataField(name, attributes, numType, partType, byteCount);
return RESULT_OK;
}
if (values->begin()->first < numType->getMinValue() || values->rbegin()->first > numType->getMaxValue()) {
return RESULT_ERR_OUT_OF_RANGE;
for (auto& it : *values) {
result_t ret = numType->checkValueRange(it.first);
if (ret != RESULT_OK) {
return ret;
}
}
*returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, *values);
return RESULT_OK;
@@ -780,8 +830,11 @@ result_t ValueListDataField::derive(const string& name, PartType partType, int d
}
const NumberDataType* num = reinterpret_cast<const NumberDataType*>(m_dataType);
if (!values.empty()) {
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
for (auto& it : values) {
result_t ret = num->checkValueRange(it.first);
if (ret != RESULT_OK) {
return RESULT_ERR_INVALID_ARG;
}
}
fields->push_back(new ValueListDataField(useName, *attributes,
num, partType, m_length, values));
@@ -912,7 +965,7 @@ void ConstantDataField::dump(bool prependFieldSeparator, OutputFormat outputForm
dumpPrefix(prependFieldSeparator, outputFormat, output);
// no divisor appended since it is not allowed for ConstantDataField
if (outputFormat & OF_JSON) {
appendJson(false, "value", m_value, true, output);
appendJson(true, "value", m_value, true, output);
*output << ", \"verify\": " << (m_verify ? "true" : "false");
} else {
*output << (m_verify?"==":"=") << m_value;
+185 -75
View File
@@ -700,9 +700,17 @@ bool NumberDataType::dump(OutputFormat outputFormat, size_t length, AppendDiviso
ret = true;
}
}
if (ret && (outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
if (ret) {
*output << ", \"precision\": " << static_cast<unsigned>(getPrecision());
}
*output << ", \"min\": ";
getMinMax(false, OF_JSON, output);
*output << ", \"max\": ";
getMinMax(true, OF_JSON, output);
*output << ", \"step\": ";
getStep(OF_JSON, output);
}
return ret;
}
@@ -747,6 +755,11 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
} else {
return RESULT_ERR_INVALID_ARG;
}
ostringstream str;
str << m_id << ',' << static_cast<unsigned>(bitCount) << ',' << static_cast<signed>(divisor);
string key = str.str();
*derived = static_cast<const NumberDataType*>(DataTypeList::getInstance()->get(key));
if (*derived == nullptr) {
if (m_bitCount < 8) {
*derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_firstBit, divisor, m_baseType ? m_baseType : this);
@@ -754,16 +767,107 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
*derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
}
DataTypeList::getInstance()->addCleanup(*derived);
DataTypeList::getInstance()->add(*derived, key);
}
return RESULT_OK;
}
result_t NumberDataType::derive(unsigned int min, unsigned int max, unsigned int inc, const NumberDataType** derived)
const {
if (m_bitCount < 8) {
return RESULT_ERR_INVALID_ARG;
}
if (min == m_minValue && max == m_maxValue && (inc == 0 || inc == m_incValue)) {
*derived = this;
return RESULT_OK;
}
if (checkValueRange(min) != RESULT_OK || checkValueRange(max) != RESULT_OK) {
return RESULT_ERR_OUT_OF_RANGE;
}
ostringstream str;
str << m_id << ',' << static_cast<unsigned>(m_bitCount) << ',' << static_cast<signed>(m_divisor)
<< ',' << static_cast<unsigned>(min)<< ',' << static_cast<unsigned>(max)<< ',' << static_cast<unsigned>(inc);
string key = str.str();
*derived = static_cast<const NumberDataType*>(DataTypeList::getInstance()->get(key));
if (*derived == nullptr) {
*derived = new NumberDataType(m_id, m_bitCount, m_flags, m_replacement,
min, max, inc, m_divisor, m_baseType ? m_baseType : this);
DataTypeList::getInstance()->add(*derived, key);
}
return RESULT_OK;
}
result_t NumberDataType::getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const {
return readFromRawValue(getMax ? m_maxValue : m_minValue, outputFormat, output);
return readFromRawValue(getMax ? m_maxValue : m_minValue, outputFormat, output, true);
}
result_t NumberDataType::getStep(const OutputFormat outputFormat, ostream* output) const {
return readFromRawValue(hasFlag(EXP) ? floatToUint(1.0f) : 1, outputFormat, output);
return readFromRawValue(m_incValue ? m_incValue : hasFlag(EXP) ? floatToUint(1.0f) : 1, outputFormat, output, true);
}
result_t NumberDataType::checkValueRange(unsigned int value, bool* pnegative) const {
bool negative;
if (hasFlag(SIG)) { // signed value
unsigned int negBit = 1 << (m_bitCount - 1);
negative = (value & negBit) != 0;
if (hasFlag(EXP)) {
float fval = uintToFloat(value, negative);
if (!isfinite(fval)) {
return RESULT_EMPTY;
}
float cval = uintToFloat(m_minValue, (m_minValue & negBit) != 0);
if (!isfinite(cval)) {
return RESULT_EMPTY;
}
if (fval < cval) {
return RESULT_ERR_OUT_OF_RANGE;
}
cval = uintToFloat(m_maxValue, (m_maxValue & negBit) != 0);
if (!isfinite(cval)) {
return RESULT_EMPTY;
}
if (fval > cval) {
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
if (m_minValue & negBit) {
// negative min
if (negative && value < m_minValue) {
// e.g. SCH val=0xfc=-4 min=0xff=-1
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
// positive min
if (negative || value < m_minValue) {
// e.g. SCH val=0xfc=-4 min=0x01=+1
// e.g. SCH val=0x00=0 min=0x01=+1
return RESULT_ERR_OUT_OF_RANGE;
}
}
if (m_maxValue & negBit) {
// negative max
if (!negative || value > m_maxValue) {
// e.g. SCH val=0x00=0 max=0xff=-1
// e.g. SCH val=0xff=-1 max=0xfe=-2
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
// positive max
if (!negative && value > m_maxValue) {
// e.g. SCH val=0x04=+4 max=0x01=+1
return RESULT_ERR_OUT_OF_RANGE;
}
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE;
} else {
negative = false;
}
if (pnegative) {
*pnegative = negative;
}
return RESULT_OK;
}
result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
@@ -830,22 +934,10 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
return RESULT_EMPTY;
}
bool negative;
if (hasFlag(SIG)) { // signed value
negative = (value & (1 << (m_bitCount - 1))) != 0;
if (!hasFlag(EXP)) {
if (negative) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} else {
negative = false;
bool negative = false;
result_t ret = checkValueRange(value, &negative);
if (ret != RESULT_OK) {
return ret;
}
int signedValue;
if (m_bitCount == 32) {
@@ -865,7 +957,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
val /= static_cast<float>(m_divisor);
}
}
*output = static_cast<float>(val);
*output = val;
return RESULT_OK;
}
if (!negative) {
@@ -895,7 +987,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
}
result_t NumberDataType::readFromRawValue(unsigned int value,
OutputFormat outputFormat, ostream* output) const {
OutputFormat outputFormat, ostream* output, bool skipRangeCheck) const {
size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8);
// initialize output
*output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6);
@@ -909,22 +1001,10 @@ result_t NumberDataType::readFromRawValue(unsigned int value,
return RESULT_OK;
}
bool negative;
if (hasFlag(SIG)) { // signed value
negative = (value & (1 << (m_bitCount - 1))) != 0;
if (!hasFlag(EXP)) {
if (negative) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} else {
negative = false;
bool negative = false;
result_t ret = checkValueRange(value, &negative);
if (!skipRangeCheck && ret != RESULT_OK) {
return ret;
}
int signedValue;
if (m_bitCount == 32) {
@@ -1055,7 +1135,7 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
} else {
if (m_divisor == 1) {
if (hasFlag(SIG)) {
long signedValue = static_cast<long>(val); // TODO static_c?
long signedValue = static_cast<long>(val);
if (signedValue < 0 && m_bitCount != 32) {
value = (unsigned int)(signedValue + (1 << m_bitCount));
} else {
@@ -1091,37 +1171,28 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
value = (unsigned int)dvalue;
}
}
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
result_t ret = checkValueRange(value);
if (ret != RESULT_OK) {
return ret;
}
*output = value;
return RESULT_OK;
}
result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
SymbolString* output, size_t* usedLength) const {
result_t NumberDataType::parseInput(const string inputStr, unsigned int* parsedValue) const {
unsigned int value;
const string inputStr = input->str();
if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) {
value = m_replacement; // replacement value
} else if (inputStr.empty()) {
return RESULT_ERR_EOF; // input too short
} else if (hasFlag(EXP)) { // IEEE 754 binary32
} else {
if (hasFlag(EXP)) { // IEEE 754 binary32
const char* str = inputStr.c_str();
char* strEnd = nullptr;
double dvalue = strtod(str, &strEnd);
if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (m_divisor < 0) {
@@ -1138,21 +1209,29 @@ result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstrea
char* strEnd = nullptr;
if (m_divisor == 1) {
if (hasFlag(SIG)) {
long signedValue = strtol(str, &strEnd, 10);
long signedValue = strtol(str, &strEnd, 0);
if (errno == ERANGE
|| (m_bitCount != 32 && (signedValue < 0L ? (signedValue < -(1L << (m_bitCount - 1))) : (signedValue >= (1L << (m_bitCount - 1)))))
) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
if (signedValue < 0 && m_bitCount != 32) {
value = (unsigned int)(signedValue + (1 << m_bitCount));
value = (unsigned int)(signedValue + (1L << m_bitCount));
} else {
value = (unsigned int)signedValue;
}
} else {
value = (unsigned int)strtoul(str, &strEnd, 10);
value = (unsigned int)strtoul(str, &strEnd, 0);
if (errno == ERANGE || (m_bitCount != 32 && value >= (1U << m_bitCount))) {
return RESULT_ERR_OUT_OF_RANGE;
}
}
if (strEnd == nullptr || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
return RESULT_ERR_INVALID_NUM; // invalid value
}
} else {
double dvalue = strtod(str, &strEnd);
if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value
}
if (m_divisor < 0) {
@@ -1161,36 +1240,40 @@ result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstrea
dvalue = round(dvalue * m_divisor);
}
if (hasFlag(SIG)) {
if (dvalue < -exp2((8 * static_cast<double>(length)) - 1)
|| dvalue >= exp2((8 * static_cast<double>(length)) - 1)) {
double max = exp2(m_bitCount - 1);
if (dvalue < 0.0 ? (dvalue < -max) : (dvalue >= max)) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
if (dvalue < 0 && m_bitCount != 32) {
if (dvalue < 0.0 && m_bitCount != 32) {
value = static_cast<int>(dvalue + (1 << m_bitCount));
} else {
value = static_cast<int>(dvalue);
}
} else {
if (dvalue < 0.0 || dvalue >= exp2(8 * static_cast<double>(length))) {
if (dvalue < 0.0 || dvalue >= exp2(m_bitCount)) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
value = (unsigned int)dvalue;
}
}
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
result_t ret = checkValueRange(value);
if (ret != RESULT_OK) {
return ret;
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
*parsedValue = value;
return RESULT_OK;
}
result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
SymbolString* output, size_t* usedLength) const {
unsigned int value;
const string inputStr = input->str();
result_t ret = parseInput(inputStr, &value);
if (ret != RESULT_OK) {
return ret;
}
return writeRawValue(value, offset, length, output, usedLength);
}
@@ -1207,6 +1290,7 @@ DataTypeList::DataTypeList() {
// unsigned decimal in BCD, 0000 - 9999 (fixed length)
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1));
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
add(new NumberDataType("U1L", 8, REQ, 0, 0, 0xff, 1)); // unsigned 1-byte, 0 - 255 (no replacement)
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
// >= 1 byte character string filled up with 0x00 (null terminated string)
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0));
@@ -1264,6 +1348,7 @@ DataTypeList::DataTypeList() {
add(new NumberDataType("HCD:2", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
add(new NumberDataType("HCD:3", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
add(new NumberDataType("S1L", 8, SIG|REQ, 0, 0x80, 0x7f, 1)); // signed integer, -128 - +127 (no replacement)
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
// unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2));
@@ -1283,26 +1368,50 @@ DataTypeList::DataTypeList() {
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1));
// unsigned integer, 0 - 65534, big endian
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1));
// unsigned integer, 0 - 65535, little endian (no replacement)
add(new NumberDataType("U2L", 16, REQ, 0, 0, 0xffff, 1));
// unsigned integer, 0 - 65535, big endian (no replacement)
add(new NumberDataType("U2B", 16, REQ|REV, 0, 0, 0xffff, 1));
// signed integer, -32767 - +32767, little endian
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
// signed integer, -32767 - +32767, big endian
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1));
// signed integer, -32768 - +32767, little endian (no replacement)
add(new NumberDataType("S2L", 16, SIG|REQ, 0, 0x8000, 0x7fff, 1));
// signed integer, -32768 - +32767, big endian (no replacement)
add(new NumberDataType("S2B", 16, SIG|REQ|REV, 0, 0x8000, 0x7fff, 1));
// unsigned 3 bytes int, 0 - 16777214, little endian
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
// unsigned 3 bytes int, 0 - 16777214, big endian
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1));
// unsigned 3 bytes int, 0 - 16777215, little endian (no replacement)
add(new NumberDataType("U3L", 24, REQ, 0, 0, 0xffffff, 1));
// unsigned 3 bytes int, 0 - 16777215, big endian (no replacement)
add(new NumberDataType("U3B", 24, REQ|REV, 0, 0, 0xffffff, 1));
// signed 3 bytes int, -8388607 - +8388607, little endian
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0x7fffff, 1));
// signed 3 bytes int, -8388607 - +8388607, big endian
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0x7fffff, 1));
// signed 3 bytes int, -8388608 - +8388607, little endian (no replacement)
add(new NumberDataType("S3L", 24, SIG|REQ, 0, 0x800000, 0x7fffff, 1));
// signed 3 bytes int, -8388608 - +8388607, big endian (no replacement)
add(new NumberDataType("S3B", 24, SIG|REQ|REV, 0, 0x800000, 0x7fffff, 1));
// unsigned integer, 0 - 4294967294, little endian
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
// unsigned integer, 0 - 4294967294, big endian
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
// signed integer, -2147483647 - +2147483647, little endian
// unsigned integer, 0 - 4294967295, little endian (no replacement)
add(new NumberDataType("U4L", 32, REQ, 0, 0, 0xffffffff, 1));
// unsigned integer, 0 - 4294967295, big endian (no replacement)
add(new NumberDataType("U4B", 32, REQ|REV, 0, 0, 0xffffffff, 1));
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0x7fffffff, 1));
// signed integer, -2147483647 - +2147483647, big endian
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0x7fffffff, 1));
// signed integer, -2147483648 - +2147483647, little endian (no replacement)
add(new NumberDataType("S4L", 32, SIG|REQ, 0, 0x80000000, 0x7fffffff, 1));
// signed integer, -2147483648 - +2147483647, big endian (no replacement)
add(new NumberDataType("S4B", 32, SIG|REQ|REV, 0, 0x80000000, 0x7fffffff, 1));
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
@@ -1350,11 +1459,12 @@ void DataTypeList::clear() {
m_typesById.clear();
}
result_t DataTypeList::add(const DataType* dataType) {
if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
result_t DataTypeList::add(const DataType* dataType, const string derivedKey) {
string key = derivedKey.empty() ? dataType->getId() : derivedKey;
if (m_typesById.find(key) != m_typesById.end()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
}
m_typesById[dataType->getId()] = dataType;
m_typesById[key] = dataType;
m_cleanupTypes.push_back(dataType);
return RESULT_OK;
}
+55 -4
View File
@@ -481,7 +481,25 @@ class NumberDataType : public DataType {
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
unsigned int minValue, unsigned int maxValue, int divisor,
const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue),
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_incValue(0),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {}
/**
* Constructs a new instance for multiple of 8 bits with increment value.
* @param id the type identifier.
* @param bitCount the number of bits (maximum length if #ADJ flag is set).
* @param flags the combination of flags (like #BCD).
* @param replacement the replacement value (no replacement if equal to minValue).
* @param minValue the minimum raw value.
* @param maxValue the maximum raw value.
* @param incValue the smallest step value for increment/decrement, or 0 for auto.
* @param divisor the divisor (negative for reciprocal).
* @param baseType the base @a NumberDataType for derived instances, or nullptr.
*/
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
unsigned int minValue, unsigned int maxValue, unsigned int incValue, int divisor,
const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_incValue(incValue),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {}
/**
@@ -496,7 +514,7 @@ class NumberDataType : public DataType {
*/
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
int16_t firstBit, int divisor, const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1),
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_incValue(0),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {}
/**
@@ -527,6 +545,18 @@ class NumberDataType : public DataType {
*/
virtual result_t derive(int divisor, size_t bitCount, const NumberDataType** derived) const;
/**
* Derive a new @a NumberDataType from this.
* @param min the minimum raw value.
* @param max the minimum raw value.
* @param inc the smallest step value for increment/decrement, or 0 to keep the current increment (or calculate
* automatically).
* @param derived the derived @a NumberDataType, or this if derivation is
* not necessary.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t derive(unsigned int min, unsigned int max, unsigned int inc, const NumberDataType** derived) const;
/**
* @return the minimum raw value.
*/
@@ -546,6 +576,14 @@ class NumberDataType : public DataType {
*/
result_t getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const;
/**
* Check the value against the minimum and maximum value.
* @param value the raw value.
* @param negative optional variable in which to store the negative flag.
* @return @a RESULT_OK on success, or an error code.
*/
result_t checkValueRange(unsigned int value, bool* negative = nullptr) const;
/**
* Get the smallest step value for increment/decrement.
* @param outputFormat the @a OutputFormat options to use.
@@ -598,10 +636,19 @@ class NumberDataType : public DataType {
* @param value the numeric raw value.
* @param outputFormat the @a OutputFormat options to use.
* @param output the ostream to append the formatted value to.
* @param skipRangeCheck whether to skip the value range check.
* @return @a RESULT_OK on success, or an error code.
*/
result_t readFromRawValue(unsigned int value,
OutputFormat outputFormat, ostream* output) const;
OutputFormat outputFormat, ostream* output, bool skipRangeCheck = false) const;
/**
* Internal method for parsing an input string to the coorresponding raw value.
* @param inputStr the input string to parse the formatted value from.
* @param parsedValue the variable in which to store the parsed raw value.
* @return @a RESULT_OK on success, or an error code.
*/
result_t parseInput(const string inputStr, unsigned int* parsedValue) const;
/**
* Internal method for writing the numeric raw value to a @a SymbolString.
@@ -628,6 +675,9 @@ class NumberDataType : public DataType {
/** the maximum raw value. */
const unsigned int m_maxValue;
/** the smallest step value for increment/decrement, or 0 for auto. */
const unsigned int m_incValue;
/** the divisor (negative for reciprocal). */
const int m_divisor;
@@ -680,10 +730,11 @@ class DataTypeList {
/**
* Adds a @a DataType instance to this map.
* @param dataType the @a DataType instance to add.
* @param derivedKey optional speicla key for derived instances.
* @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success.
*/
result_t add(const DataType* dataType);
result_t add(const DataType* dataType, const string derivedKey = "");
/**
* Adds a @a DataType instance for later cleanup.
+13 -7
View File
@@ -111,7 +111,7 @@ Message::Message(const string& filename, const string& circuit, const string& le
m_pollPriority(pollPriority),
m_usedByCondition(false), m_isScanMessage(false), m_condition(condition), m_availableSinceTime(0),
m_dataHandlerState(0), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollOrder(0), m_lastPollTime(0) {
if (circuit == "scan") {
if (strcasecmp(circuit.c_str(), "scan") == 0) {
setScanMessage();
m_pollPriority = 0;
}
@@ -180,7 +180,7 @@ uint64_t Message::createKey(const vector<symbol_t>& id, bool isWrite, bool isPas
int exp = 5;
for (const auto it : id) {
key ^= (uint64_t)it << (8 * exp--);
if (exp == 0) {
if (exp < 0) {
exp = 3;
}
}
@@ -206,7 +206,7 @@ uint64_t Message::createKey(const MasterSymbolString& master, size_t maxIdLength
int exp = 3;
for (size_t i = 0; i < idLength; i++) {
key ^= (uint64_t)master.dataAt(i) << (8 * exp--);
if (exp == 0) {
if (exp < 0) {
exp = 3;
}
}
@@ -941,6 +941,9 @@ void Message::dumpField(const string& fieldName, bool withConditions, OutputForm
for (auto it = m_id.begin()+2; it < m_id.end(); it++) {
*output << hex << setw(2) << setfill('0') << static_cast<unsigned>(*it);
}
if (outputFormat & OF_ALL_ATTRS) {
*output << "=" << hex << setw(0) << setfill('0') << static_cast<uint64_t>(m_key);
}
return;
}
if (fieldName == "fields") {
@@ -2712,13 +2715,12 @@ Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination,
if (anyDestination && master.size() >= 5 && master[4] == 0 && master[2] == 0x07 && master[3] == 0x04) {
return m_scanMessage;
}
uint64_t baseKey = Message::createKey(master,
anyDestination || master[1] != BROADCAST ? m_maxIdLength : m_maxBroadcastIdLength, anyDestination);
size_t maxIdLength = anyDestination || master[1] != BROADCAST ? m_maxIdLength : m_maxBroadcastIdLength;
uint64_t baseKey = Message::createKey(master, maxIdLength, anyDestination);
if (baseKey == INVALID_KEY) {
return nullptr;
}
bool isWriteDest = isMaster(master[1]) || master[1] == BROADCAST;
size_t maxIdLength = Message::getKeyLength(baseKey);
for (size_t idLength = maxIdLength; true; idLength--) {
uint64_t key = baseKey;
if (idLength == maxIdLength) {
@@ -2728,7 +2730,7 @@ Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination,
int exp = 3;
for (size_t i = 0; i < idLength; i++) {
key ^= (uint64_t)master.dataAt(i) << (8 * exp--);
if (exp == 0) {
if (exp < 0) {
exp = 3;
}
}
@@ -2907,6 +2909,10 @@ void MessageMap::dump(bool withConditions, OutputFormat outputFormat, ostream* o
*output << (m_addAll ? "[" : "{");
} else {
Message::dumpHeader(nullptr, output);
if (m_addAll) {
*output << endl << "# max ID length: " << static_cast<unsigned>(m_maxIdLength)
<< " (broadcast only: " << static_cast<unsigned>(m_maxBroadcastIdLength) << ")";
}
}
if (!(outputFormat & OF_SHORT)) {
*output << endl;
+4 -7
View File
@@ -158,13 +158,6 @@ class Message : public AttributedItem {
*/
static uint64_t createKey(symbol_t pb, symbol_t sb, bool broadcast);
/**
* Get the length field from the key.
* @param key the key.
* @return the length field from the key.
*/
static size_t getKeyLength(uint64_t key) { return (size_t)(key >> (8 * 7 + 5)); }
/**
* Parse an ID part from the input @a string.
* @param input the input @a string, hex digits optionally separated by space.
@@ -1651,6 +1644,10 @@ class MessageMap : public MappedFileReader {
*/
void dump(bool withConditions, OutputFormat outputFormat, ostream* output) const;
/**
* @return the maximum ID length used by any of the known @a Message instances.
*/
size_t getMaxIdLength() const { return m_maxIdLength; }
private:
/** empty vector for @a getLoadedFiles(). */
+64 -4
View File
@@ -53,15 +53,18 @@ void verify(bool expectFailMatch, string type, string input,
class TestReader : public MappedFileReader {
public:
TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest)
TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest, bool withRange)
: MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest),
m_fields(nullptr) {}
m_withRange(withRange), m_fields(nullptr) {}
result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override {
if (row->empty()) {
row->push_back("*name");
row->push_back("part");
row->push_back("type");
row->push_back("divisor/values");
if (m_withRange) {
row->push_back("range");
}
row->push_back("unit");
row->push_back("comment");
return RESULT_OK;
@@ -86,6 +89,7 @@ class TestReader : public MappedFileReader {
const DataFieldTemplates* m_templates;
const bool m_isSet;
const bool m_isMasterDest;
const bool m_withRange;
public:
const DataField* m_fields;
};
@@ -101,7 +105,7 @@ int main() {
// entry: definition, decoded value, master data, slave data, flags
// definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
unsigned int baseLine = __LINE__+1;
string checks[][5] = {
string checks[][6] = {
{"x,,ign:10", "", "10fe07000a00000000000000000000", "00", ""},
{"x,,ign:*", "", "10fe07000a00000000000000000000", "00", "W"},
{"x,,ign,2", "", "", "", "c"},
@@ -344,6 +348,13 @@ int main() {
{"x,,uch,==48", "", "10feffff01ab", "00", "rW"},
{"x,,uch,=48", "", "10feffff0130", "00", ""},
{"x,,uch,==48", "", "10feffff0130", "00", ""},
{"x,,uch,,1-3", "2", "10feffff0102", "00", "-"},
{"x,,uch,,1-3", "4", "10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,uch,,1-3", "2", "10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,uch,,0x1-0x3", "4","10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,uch,,0x1-0x3", "2","10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,uch", "\n \"x\": {\"value\": 2}", "10feffff0102", "00", "-jV", "\n { \"name\": \"x\", \"slave\": false, \"type\": \"UCH\", \"isbits\": false, \"isadjustable\": false, \"isignored\": false, \"isreverse\": false, \"length\": 1, \"result\": \"number\", \"min\": 0, \"max\": 254, \"step\": 1, \"unit\": \"\", \"comment\": \"\"}"},
{"x,,uch,,1-3:2", "\n \"x\": {\"value\": 2}", "10feffff0102", "00", "-jV", "\n { \"name\": \"x\", \"slave\": false, \"type\": \"UCH\", \"isbits\": false, \"isadjustable\": false, \"isignored\": false, \"isreverse\": false, \"length\": 1, \"result\": \"number\", \"min\": 1, \"max\": 3, \"step\": 2, \"unit\": \"\", \"comment\": \"\"}"},
{"x,,sch", "-90", "10feffff01a6", "00", ""},
{"x,,sch", "0", "10feffff0100", "00", ""},
{"x,,sch", "-1", "10feffff01ff", "00", ""},
@@ -352,6 +363,15 @@ int main() {
{"x,,sch", "127", "10feffff017f", "00", ""},
{"x,,sch,10", "-9.0", "10feffff01a6", "00", ""},
{"x,,sch,-10", "-900", "10feffff01a6", "00", ""},
{"x,,sch,,1-3", "2", "10feffff0102", "00", "-"},
{"x,,sch,,1-500", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-130-1", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-127-127", "-", "10feffff0180", "00", "-"},
{"x,,sch,,-127-128", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-128-127", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,1-3", "4", "10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,sch,,1-3", "2", "10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,sch,,-3--1", "-4", "10feffff01fe", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,d1b", "-90", "10feffff01a6", "00", ""},
{"x,,d1b", "0", "10feffff0100", "00", ""},
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
@@ -429,6 +449,12 @@ int main() {
{"x,,flt", "-", "10feffff020080", "00", ""},
{"x,,flt", "-32.767", "10feffff020180", "00", ""},
{"x,,flt", "32.767", "10feffff02ff7f", "00", ""},
{"x,,flt,,1-3", "2.000", "10feffff02d007", "00", "-"},
{"x,,flt,,1-3", "4.000", "10feffff02d007", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,flt,,1-3", "2.000", "10feffff02a00f", "00", "-rW:ERR: argument value out of valid range"},
{"x,,flt,,-3--1", "-4", "10feffff0230f8", "00", "-Rw:ERR: argument value out of valid range"}, // -4:60f0, -2:30f8
{"x,,flt,,-3.1--1.0", "-4", "10feffff0230f8", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,flt,,-3.1--1.0", "-2", "10feffff0260f0", "00", "-rW:ERR: argument value out of valid range"},
{"x,,flr", "-0.090", "10feffff02ffa6", "00", ""},
{"x,,flr", "0.000", "10feffff020000", "00", ""},
{"x,,flr", "-0.001", "10feffff02ffff", "00", ""},
@@ -445,6 +471,11 @@ int main() {
{"x,,exp", "0.25", "10feffff040000803e", "00", ""},
{"x,,exp", "0.95", "10feffff043333733f", "00", ""},
{"x,,exp", "0.65", "10feffff046666263f", "00", ""},
{"x,,exp", "0.065", "10feffff04b81e853d", "00", ""},
{"x,,exp,,0-0.65", "0.65", "10feffff046666263f", "00", "-"},
{"x,,exp,,0-0.5", "0.65", "10feffff046666263f", "00", "-rw:ERR: argument value out of valid range"},
{"x,,exp,10,0-0.065", "0.0650000", "10feffff046666263f", "00", "-"},
{"x,,exp,10,0-0.05", "0.0650000", "10feffff046666263f", "00", "-rw:ERR: argument value out of valid range"},
{"x,,exr", "-0.09", "10feffff04bdb851ec", "00", ""},
{"x,,exr", "0.0", "10feffff0400000000", "00", ""},
{"x,,exr", "-0.001", "10feffff04ba83126f", "00", ""},
@@ -577,6 +608,12 @@ int main() {
continue;
}
string flags = check[4];
size_t colon = flags.find(':');
string errStr;
if (colon != string::npos) {
errStr = flags.substr(colon+1);
flags = flags.substr(0, colon);
}
bool isSet = flags.find('s') != string::npos;
bool testFields = flags.find('F') != string::npos;
bool failedCreate = flags.find('c') != string::npos;
@@ -584,6 +621,7 @@ int main() {
bool failedReadMatch = flags.find('R') != string::npos;
bool failedWrite = flags.find('w') != string::npos;
bool failedWriteMatch = flags.find('W') != string::npos;
string withDump = check[5]; // optional
const char* findName = flags.find('I') == string::npos ? nullptr : "x";
ssize_t findIndex = -1;
if (flags.find('i') != string::npos) {
@@ -599,6 +637,9 @@ int main() {
if (flags.find("vvv") != string::npos) {
verbosity |= OF_COMMENTS;
}
if (flags.find("V") != string::npos) {
verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS|OF_ALL_ATTRS;
}
if (flags.find('j') != string::npos) {
verbosity |= OF_JSON;
}
@@ -620,7 +661,8 @@ int main() {
}
continue;
}
TestReader reader{templates, isSet, mstr[1] == BROADCAST || isMaster(mstr[1])};
bool withRange = flags.find('-') != string::npos;
TestReader reader{templates, isSet, mstr[1] == BROADCAST || isMaster(mstr[1]), withRange};
lineNo = 0;
dummystr.clear();
dummystr.str("#");
@@ -638,6 +680,9 @@ int main() {
if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
error = true;
} else if (!errStr.empty() && errorDescription != errStr) {
cout << "\"" << check[0] << "\": failed create error: unexpected result \"" << errorDescription << "\" instead of \"" << errStr << "\"" << endl;
error = true;
} else {
cout << "\"" << check[0] << "\": failed create OK" << endl;
}
@@ -680,6 +725,10 @@ int main() {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl;
error = true;
} else if (!errStr.empty() && getResultCode(result) != errStr) {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpected result \"";
cout << getResultCode(result) << "\" instead of \"" << errStr << "\"" << endl;
} else {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< OK" << endl;
@@ -744,6 +793,10 @@ int main() {
cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< error: unexpectedly succeeded" << endl;
error = true;
} else if (!errStr.empty() && getResultCode(result) != errStr) {
cout << " failed write " << fields->getName(-1) << " >"
<< "< error: unexpected result \"";
cout << getResultCode(result) << "\" instead of \"" << errStr << "\"" << endl;
} else {
cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< OK" << endl;
@@ -760,6 +813,13 @@ int main() {
writeMstr.getStr() + " " + writeSstr.getStr());
}
}
if (!withDump.empty()) {
output.clear();
output.str("");
fields->dump(false, verbosity, &output);
bool match = output.str() == withDump;
verify(false, "dump", withDump, match, withDump, output.str());
}
delete fields;
fields = nullptr;
}
+16 -6
View File
@@ -579,23 +579,33 @@ int resolveMdnsOneShot(const char* url, mdns_oneshot_t *result, mdns_oneshot_t *
printf(" %s=%s\n", (atype == DNS_TYPE_TXT) ? "txt" : "ptr", name);
#endif
if (atype == DNS_TYPE_TXT && name[0]) {
// parse id=xxxxxxxxxxxx[.proto=xxx]
char* sep = strchr(name, '=');
char* sep2;
if (sep && strncmp(name, "id", sep-name) == 0) {
sep2 = strchr(name, '.');
if (sep && sep-name == 2 && strncmp(name, "id", 2) == 0) {
sep2 = strchr(sep+1, '.');
if (!sep2) {
sep2 = name + pos;
}
if (sep2-sep-1 == sizeof(mdns_oneshot_t::id)-1) {
memcpy(id, sep+1, sizeof(mdns_oneshot_t::id)-1);
} else {
sep = nullptr;
}
sep = sep ? strchr(sep2+1, '=') : nullptr;
sep = sep && sep2 < name + pos ? strchr(sep2+1, '=') : nullptr;
} else {
sep2 = name - 1;
}
if (sep && strncmp(sep2+1, "proto", sep-sep2-1) == 0 && (
pos == (size_t)(sep-name)+1+sizeof(mdns_oneshot_t::proto)-1
|| strchr(sep+1, '.') == sep+1+sizeof(mdns_oneshot_t::proto)-1)) {
if (sep && sep-sep2-1 == 5 && strncmp(sep2+1, "proto", 5) == 0) {
sep2 = strchr(sep+1, '.');
if (!sep2) {
sep2 = name + pos;
}
if (sep2-sep-1 == sizeof(mdns_oneshot_t::proto)-1) {
memcpy(proto, sep+1, sizeof(mdns_oneshot_t::proto)-1);
}
}
}
} else if (atype == DNS_TYPE_SRV && rdLen >= sizeof(dns_rr_srv_t)) {
dns_rr_srv_t *srv = reinterpret_cast<dns_rr_srv_t*>(record+len);
size_t pos = 0;