added helper method extractDefaultsFromFilename() and support extracting default circuit name from file name
This commit is contained in:
+27
-44
@@ -612,7 +612,6 @@ static bool readTemplates(const string path, const string extension, bool availa
|
|||||||
* Read the configuration files from the specified path.
|
* Read the configuration files from the specified path.
|
||||||
* @param path the path from which to read the files.
|
* @param path the path from which to read the files.
|
||||||
* @param extension the filename extension of the files to read.
|
* @param extension the filename extension of the files to read.
|
||||||
* @param templates the available @a DataFieldTemplates.
|
|
||||||
* @param messages the @a MessageMap to load the messages into.
|
* @param messages the @a MessageMap to load the messages into.
|
||||||
* @param recursive whether to load all files recursively.
|
* @param recursive whether to load all files recursively.
|
||||||
* @param verbose whether to verbosely log problems.
|
* @param verbose whether to verbosely log problems.
|
||||||
@@ -673,7 +672,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
|
|||||||
if (result != RESULT_OK)
|
if (result != RESULT_OK)
|
||||||
logError(lf_main, "error executing instructions: %s, %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
|
logError(lf_main, "error executing instructions: %s, %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
|
||||||
else if (log.tellp() > 0)
|
else if (log.tellp() > 0)
|
||||||
logNotice(lf_main, log.str().c_str());
|
logInfo(lf_main, log.str().c_str());
|
||||||
|
|
||||||
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
||||||
|
|
||||||
@@ -698,7 +697,8 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataFieldSet* identFields = DataFieldSet::getIdentFields();
|
DataFieldSet* identFields = DataFieldSet::getIdentFields();
|
||||||
string path, prefix, ident, sw, hw; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
|
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
|
||||||
|
unsigned int sw, hw;
|
||||||
ostringstream out;
|
ostringstream out;
|
||||||
unsigned char offset = 0;
|
unsigned char offset = 0;
|
||||||
size_t field = 0;
|
size_t field = 0;
|
||||||
@@ -721,13 +721,11 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
ident = out.str();
|
ident = out.str();
|
||||||
out.str("");
|
out.str("");
|
||||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||||
result = (*identFields)[field]->read(partType, data, offset, out, 0); // software version number
|
result = (*identFields)[field]->read(partType, data, offset, sw, 0); // software version number
|
||||||
}
|
}
|
||||||
if (result==RESULT_OK) {
|
if (result==RESULT_OK) {
|
||||||
sw = out.str();
|
|
||||||
out.str("");
|
|
||||||
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
|
||||||
result = (*identFields)[field]->read(partType, data, offset, out, 0); // hardware version number
|
result = (*identFields)[field]->read(partType, data, offset, hw, 0); // hardware version number
|
||||||
}
|
}
|
||||||
if (result!=RESULT_OK) {
|
if (result!=RESULT_OK) {
|
||||||
logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result));
|
logError(lf_main, "unable to load scan config %2.2x: decode %s", address, getResultCode(result));
|
||||||
@@ -735,7 +733,6 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
}
|
}
|
||||||
vector<string> files;
|
vector<string> files;
|
||||||
bool hasTemplates = false;
|
bool hasTemplates = false;
|
||||||
hw = out.str();
|
|
||||||
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
|
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
|
||||||
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
|
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
|
||||||
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
|
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
|
||||||
@@ -747,8 +744,6 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(), prefix.c_str());
|
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(), prefix.c_str());
|
||||||
return RESULT_ERR_NOTFOUND;
|
return RESULT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
// complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.index][.*][.SWxxxx][.HWxxxx][.*].csv
|
|
||||||
for (string::iterator it = ident.begin(); it!=ident.end(); it++) {
|
for (string::iterator it = ident.begin(); it!=ident.end(); it++) {
|
||||||
if (::isspace(*it)) {
|
if (::isspace(*it)) {
|
||||||
ident.erase(it--);
|
ident.erase(it--);
|
||||||
@@ -756,37 +751,26 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
*it = (char)::tolower(*it);
|
*it = (char)::tolower(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t prefixLen = path.length()+1+prefix.length()-1;
|
// complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.circuit][.suffix][.*][.SWxxxx][.HWxxxx][.*].csv
|
||||||
size_t bestMatch = 0;
|
size_t bestMatch = 0;
|
||||||
string best;
|
string best;
|
||||||
for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) {
|
for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) {
|
||||||
string name = *it;
|
string name = *it;
|
||||||
name = name.substr(prefixLen, name.length()-prefixLen+1-strlen(".csv")); // .*.
|
unsigned char checkDest;
|
||||||
|
string checkIdent, useCircuit, useSuffix;
|
||||||
|
unsigned int checkSw, checkHw;
|
||||||
|
if (!FileReader::extractDefaultsFromFilename(name.substr(path.length()+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (address!=checkDest || (checkSw!=UINT_MAX && sw!=checkSw) || (checkHw!=UINT_MAX && hw!=checkHw)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
size_t match = 1;
|
size_t match = 1;
|
||||||
if (name.length()>2) { // more than just "."
|
if (!checkIdent.empty()) {
|
||||||
size_t pos = name.rfind(".SW"); // check for ".SWxxxx."
|
|
||||||
if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
|
|
||||||
if (name.substr(pos+3, 4)==sw)
|
|
||||||
match += 6;
|
|
||||||
else {
|
|
||||||
continue; // SW mismatch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos = name.rfind(".HW"); // check for ".HWxxxx."
|
|
||||||
if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
|
|
||||||
if (name.substr(pos+3, 4)==hw)
|
|
||||||
match += 6;
|
|
||||||
else {
|
|
||||||
continue; // HW mismatch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos = name.find(".", 1); // check for ".C[C[C[C[C]]]]."
|
|
||||||
if (ident.length()>0 && pos!=string::npos && pos>1 && pos<=6) { // up to 5 chars between two "."s, immediately after "ZZ."
|
|
||||||
string check = name.substr(1, pos-1);
|
|
||||||
string remain = ident;
|
string remain = ident;
|
||||||
bool matches = false;
|
bool matches = false;
|
||||||
while (remain.length()>0 && remain.length()>=check.length()) {
|
while (remain.length()>0 && remain.length()>=checkIdent.length()) {
|
||||||
if (check==remain) {
|
if (checkIdent==remain) {
|
||||||
matches = true;
|
matches = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -794,21 +778,20 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
break;
|
break;
|
||||||
remain.erase(remain.length()-1); // remove trailing digit
|
remain.erase(remain.length()-1); // remove trailing digit
|
||||||
}
|
}
|
||||||
if (matches)
|
if (!matches) {
|
||||||
match += remain.length();
|
|
||||||
else {
|
|
||||||
continue; // IDENT mismatch
|
continue; // IDENT mismatch
|
||||||
}
|
}
|
||||||
}
|
match += remain.length();
|
||||||
}
|
}
|
||||||
if (match>=bestMatch) {
|
if (match>=bestMatch) {
|
||||||
bestMatch = match;
|
bestMatch = match;
|
||||||
best = *it;
|
best = name;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best.length()==0) {
|
if (best.empty()) {
|
||||||
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%s, HW%s", address, path.c_str(), prefix.c_str(), ident.c_str(), sw.c_str(), hw.c_str());
|
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d", address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw);
|
||||||
return RESULT_ERR_NOTFOUND;
|
return RESULT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,10 +818,10 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
}
|
}
|
||||||
result = messages->readFromFile(best, opt.checkConfig);
|
result = messages->readFromFile(best, opt.checkConfig);
|
||||||
if (result!=RESULT_OK) {
|
if (result!=RESULT_OK) {
|
||||||
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%s, HW%s: %s", best.c_str(), ident.c_str(), sw.c_str(), hw.c_str(), getResultCode(result));
|
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), ident.c_str(), sw, hw, getResultCode(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%s, HW%s", best.c_str(), ident.c_str(), sw.c_str(), hw.c_str());
|
logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d", best.c_str(), ident.c_str(), sw, hw);
|
||||||
|
|
||||||
result = messages->resolveConditions(false);
|
result = messages->resolveConditions(false);
|
||||||
if (result != RESULT_OK)
|
if (result != RESULT_OK)
|
||||||
@@ -849,7 +832,7 @@ result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolS
|
|||||||
if (result != RESULT_OK)
|
if (result != RESULT_OK)
|
||||||
logError(lf_main, "error executing instructions: %s, %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
|
logError(lf_main, "error executing instructions: %s, %s, %s", getResultCode(result), messages->getLastError().c_str(), log.str().c_str());
|
||||||
else if (log.tellp() > 0)
|
else if (log.tellp() > 0)
|
||||||
logNotice(lf_main, log.str().c_str());
|
logInfo(lf_main, log.str().c_str());
|
||||||
|
|
||||||
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
|
||||||
relativeFile = best.substr(strlen(opt.configPath)+1);
|
relativeFile = best.substr(strlen(opt.configPath)+1);
|
||||||
|
|||||||
+82
-18
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "result.h"
|
#include "result.h"
|
||||||
|
#include <climits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -93,25 +94,19 @@ public:
|
|||||||
return RESULT_ERR_NOTFOUND;
|
return RESULT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
size_t lastSep = filename.find_last_of('/');
|
size_t lastSep = filename.find_last_of('/');
|
||||||
size_t firstDot = filename.find_first_of('.', lastSep+1);
|
if (lastSep!=string::npos) { // potential destination address, matches "^ZZ."
|
||||||
if (lastSep!=string::npos && firstDot==lastSep+1+2) { // potential destination address, matches "^ZZ."
|
// extract defaultDest, defaultCircuit, defaultSuffix from filename:
|
||||||
result_t result;
|
// ZZ.IDENT[.CIRCUIT][.SUFFIX].*csv
|
||||||
string str = filename.substr(lastSep+1, 2);
|
unsigned char checkDest;
|
||||||
unsigned char zz = (unsigned char)parseInt(str.c_str(), 16, 0, 0xff, result, NULL);
|
string checkIdent, useCircuit, useSuffix;
|
||||||
if (result==RESULT_OK && isValidAddress(zz)) {
|
unsigned int checkSw, checkHw;
|
||||||
defaultDest = str;
|
if (extractDefaultsFromFilename(filename.substr(lastSep+1), checkDest, checkIdent, useCircuit, useSuffix, checkSw, checkHw)) {
|
||||||
size_t endDot = filename.find_first_of('.', firstDot+1);
|
defaultDest = filename.substr(lastSep+1, 2);
|
||||||
if (endDot>firstDot && endDot-firstDot<=6) { // potential ident, matches "^ZZ.IDENT."
|
if (!useCircuit.empty()) {
|
||||||
str = filename.substr(firstDot+1, endDot-firstDot-1); // IDENT
|
defaultCircuit = useCircuit;
|
||||||
if (str.find_first_of(' ')==string::npos) {
|
|
||||||
defaultCircuit = str;
|
|
||||||
size_t nextDot = filename.find_first_of('.', endDot+1);
|
|
||||||
if (nextDot!=string::npos && nextDot>endDot+1) { // potential index suffix, matches "^ZZ.IDENT.[0-9]*."
|
|
||||||
parseInt(filename.substr(endDot+1, nextDot-endDot-1).c_str(), 10, 1, 16, result, NULL);
|
|
||||||
if (result==RESULT_OK)
|
|
||||||
defaultSuffix = filename.substr(endDot, nextDot-endDot); // .[0-9]*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!useSuffix.empty()) {
|
||||||
|
defaultSuffix = useSuffix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,6 +302,75 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract default values from the file name.
|
||||||
|
* @param name the file name (without path) in the form "ZZ[.IDENT][.CIRCUIT][.SUFFIX][.SWXXXX][.HWXXXX][.*].csv".
|
||||||
|
* @param dest the output destination address ZZ (hex digits).
|
||||||
|
* @param ident the identification part IDENT (up to 5 characters, set to empty if not present).
|
||||||
|
* @param circuit the circuit part CIRCUIT (set to IDENT if not present).
|
||||||
|
* @param suffix the suffix part SUFFIX including the leading dot (decimal digit, set to empty if not present).
|
||||||
|
* @param software the software version part SWXXXX (BCD digits, set to @a UINT_MAX if not present).
|
||||||
|
* @param hardware the hardware version part HWXXXX (BCD digits, set to @a UINT_MAX if not present).
|
||||||
|
* @return true if at least the address and the identification part were extracted, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool extractDefaultsFromFilename(string name, unsigned char& dest, string& ident, string& circuit,
|
||||||
|
string& suffix, unsigned int& software, unsigned int& hardware)
|
||||||
|
{
|
||||||
|
ident = circuit = suffix = "";
|
||||||
|
software = hardware = UINT_MAX;
|
||||||
|
if (name.length()>4 && name.substr(name.length()-4)==".csv") {
|
||||||
|
name = name.substr(0, name.length()-3); // including trailing "."
|
||||||
|
}
|
||||||
|
size_t pos = name.find('.');
|
||||||
|
if (pos!=2) {
|
||||||
|
return false; // missing "ZZ."
|
||||||
|
}
|
||||||
|
result_t result = RESULT_OK;
|
||||||
|
dest = (unsigned char)parseInt(name.substr(0, pos).c_str(), 16, 0, 0xff, result, NULL);
|
||||||
|
if (result!=RESULT_OK || !isValidAddress(dest)) {
|
||||||
|
return false; // invalid "ZZ"
|
||||||
|
}
|
||||||
|
name.erase(0, pos);
|
||||||
|
if (name.length()>1) {
|
||||||
|
pos = name.rfind(".SW"); // check for ".SWxxxx."
|
||||||
|
if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
|
||||||
|
software = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
|
||||||
|
if (result!=RESULT_OK) {
|
||||||
|
return false; // invalid "SWxxxx"
|
||||||
|
}
|
||||||
|
name.erase(pos, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name.length()>1) {
|
||||||
|
pos = name.rfind(".HW"); // check for ".HWxxxx."
|
||||||
|
if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
|
||||||
|
hardware = parseInt(name.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL);
|
||||||
|
if (result!=RESULT_OK) {
|
||||||
|
return false; // invalid "HWxxxx"
|
||||||
|
}
|
||||||
|
name.erase(pos, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name.length()>1) {
|
||||||
|
pos = name.find('.', 1); // check for ".IDENT."
|
||||||
|
if (pos!=string::npos && pos>2 && pos<=6) { // up to 5 chars between two "."s, immediately after "ZZ."
|
||||||
|
ident = circuit = name.substr(1, pos-1);
|
||||||
|
name.erase(0, pos);
|
||||||
|
pos = name.find('.', 1); // check for ".CIRCUIT."
|
||||||
|
if (pos!=string::npos && (pos>2 || name[1]<'0' || name[1]>'9')) {
|
||||||
|
circuit = name.substr(1, pos-1);
|
||||||
|
name.erase(0, pos);
|
||||||
|
pos = name.find('.', 1); // check for ".SUFFIX."
|
||||||
|
}
|
||||||
|
if (pos!=string::npos && pos==2 && name[1]>='0' && name[1]<='9') {
|
||||||
|
suffix = name.substr(0, 2);
|
||||||
|
name.erase(0, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** whether this instance supports rows with defaults (starting with a star). */
|
/** whether this instance supports rows with defaults (starting with a star). */
|
||||||
|
|||||||
Reference in New Issue
Block a user