mainloop: moved instruction execution to main loop, do not send intial scan when readonly, added "--inject" option, allow --readonly with --scanconfig[=none], store scans initiated by other participants, removed unused code
This commit is contained in:
+23
-13
@@ -384,6 +384,7 @@ void BusHandler::run() {
|
|||||||
lastTime += 2;
|
lastTime += 2;
|
||||||
logNotice(lf_bus, "bus started with own address %2.2x/%2.2x%s", m_ownMasterAddress, m_ownSlaveAddress,
|
logNotice(lf_bus, "bus started with own address %2.2x/%2.2x%s", m_ownMasterAddress, m_ownSlaveAddress,
|
||||||
m_answer?" in answer mode":"");
|
m_answer?" in answer mode":"");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (m_device->isValid() && !m_reconnect) {
|
if (m_device->isValid() && !m_reconnect) {
|
||||||
result_t result = handleSymbol();
|
result_t result = handleSymbol();
|
||||||
@@ -569,7 +570,6 @@ result_t BusHandler::handleSymbol() {
|
|||||||
// receive next symbol (optionally check reception of sent symbol)
|
// receive next symbol (optionally check reception of sent symbol)
|
||||||
symbol_t recvSymbol;
|
symbol_t recvSymbol;
|
||||||
result = m_device->recv(timeout+m_transferLatency, recvSymbol);
|
result = m_device->recv(timeout+m_transferLatency, recvSymbol);
|
||||||
|
|
||||||
if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0
|
if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0
|
||||||
&& timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) {
|
&& timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) {
|
||||||
// check if acting as AUTO-SYN generator is required
|
// check if acting as AUTO-SYN generator is required
|
||||||
@@ -1102,6 +1102,21 @@ void BusHandler::receiveCompleted() {
|
|||||||
logNotice(lf_update, "unknown MM cmd: %s", m_command.getStr().c_str());
|
logNotice(lf_update, "unknown MM cmd: %s", m_command.getStr().c_str());
|
||||||
} else {
|
} else {
|
||||||
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getStr().c_str(), m_response.getStr().c_str());
|
logNotice(lf_update, "unknown MS cmd: %s / %s", m_command.getStr().c_str(), m_response.getStr().c_str());
|
||||||
|
if (m_command.size() >= 5 && m_command[2] == 0x07 && m_command[3] == 0x04) {
|
||||||
|
Message* message = m_messages->getScanMessage(dstAddress);
|
||||||
|
if (message && (message->getLastUpdateTime() == 0 || message->getLastSlaveData().getDataSize() < 10)) {
|
||||||
|
result_t result = message->storeLastData(m_command, m_response);
|
||||||
|
if (result == RESULT_OK) {
|
||||||
|
ostringstream output;
|
||||||
|
result = message->decodeLastData(output, 0, true);
|
||||||
|
if (result == RESULT_OK) {
|
||||||
|
string str = output.str();
|
||||||
|
setScanResult(dstAddress, 0, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logNotice(lf_update, "store %2.2x ident: %s", dstAddress, getResultCode(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_messages->invalidateCache(message);
|
m_messages->invalidateCache(message);
|
||||||
@@ -1141,7 +1156,9 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool&
|
|||||||
if (scanMessage == NULL) {
|
if (scanMessage == NULL) {
|
||||||
return RESULT_ERR_NOTFOUND;
|
return RESULT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
if (m_device->isReadOnly()) {
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
deque<Message*> messages = m_messages->findAll("scan", "", levels, true);
|
deque<Message*> messages = m_messages->findAll("scan", "", levels, true);
|
||||||
auto it = messages.begin();
|
auto it = messages.begin();
|
||||||
while (it != messages.end()) {
|
while (it != messages.end()) {
|
||||||
@@ -1463,6 +1480,7 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool
|
|||||||
result = loadScanConfigFile(m_messages, dstAddress, file);
|
result = loadScanConfigFile(m_messages, dstAddress, file);
|
||||||
}
|
}
|
||||||
if (result == RESULT_OK) {
|
if (result == RESULT_OK) {
|
||||||
|
executeInstructions(m_messages);
|
||||||
setScanConfigLoaded(dstAddress, file);
|
setScanConfigLoaded(dstAddress, file);
|
||||||
if (!hasAdditionalScanMessages && m_messages->hasAdditionalScanMessages()) {
|
if (!hasAdditionalScanMessages && m_messages->hasAdditionalScanMessages()) {
|
||||||
// additional scan messages now available
|
// additional scan messages now available
|
||||||
@@ -1499,7 +1517,7 @@ void BusHandler::formatGrabResult(const bool unknown, ostringstream& output, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress, bool onlyScanned) {
|
symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) {
|
||||||
if (lastAddress == SYN) {
|
if (lastAddress == SYN) {
|
||||||
return SYN;
|
return SYN;
|
||||||
}
|
}
|
||||||
@@ -1507,22 +1525,14 @@ symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress, bool onlyScanned)
|
|||||||
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) {
|
if (!isValidAddress(lastAddress, false) || isMaster(lastAddress)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (onlyScanned) {
|
if ((m_seenAddresses[lastAddress]&(SEEN|LOAD_INIT)) == SEEN) {
|
||||||
if ((m_seenAddresses[lastAddress]&(LOAD_INIT|SCAN_DONE)) == SCAN_DONE) {
|
|
||||||
return lastAddress;
|
|
||||||
}
|
|
||||||
} else if ((m_seenAddresses[lastAddress]&(SEEN|LOAD_INIT)) == SEEN) {
|
|
||||||
return lastAddress;
|
return lastAddress;
|
||||||
}
|
}
|
||||||
symbol_t master = getMasterAddress(lastAddress);
|
symbol_t master = getMasterAddress(lastAddress);
|
||||||
if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
|
if (master == SYN || (m_seenAddresses[master]&SEEN) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (onlyScanned) {
|
if ((m_seenAddresses[lastAddress]&LOAD_INIT) == 0) {
|
||||||
if ((m_seenAddresses[lastAddress]&(LOAD_INIT|SCAN_DONE)) == SCAN_DONE) {
|
|
||||||
return lastAddress;
|
|
||||||
}
|
|
||||||
} else if ((m_seenAddresses[lastAddress]&LOAD_INIT) == 0) {
|
|
||||||
return lastAddress;
|
return lastAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-3
@@ -413,6 +413,19 @@ class BusHandler : public WaitThread {
|
|||||||
*/
|
*/
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject a message from outside and treat it as regularly retrieved from the bus.
|
||||||
|
* @param master the @a MasterSymbolString with the master data.
|
||||||
|
* @param slave the @a SlaveSymbolString with the slave data.
|
||||||
|
*/
|
||||||
|
void injectMessage(MasterSymbolString& master, SlaveSymbolString& slave) {
|
||||||
|
m_command = master;
|
||||||
|
m_response = slave;
|
||||||
|
m_addressConflict = true; // avoid conflict messages
|
||||||
|
receiveCompleted();
|
||||||
|
m_addressConflict = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message on the bus and wait for the answer.
|
* Send a message on the bus and wait for the answer.
|
||||||
* @param master the @a MasterSymbolString with the master data to send.
|
* @param master the @a MasterSymbolString with the master data to send.
|
||||||
@@ -489,7 +502,7 @@ class BusHandler : public WaitThread {
|
|||||||
* Send a scan message on the bus and wait for the answer.
|
* Send a scan message on the bus and wait for the answer.
|
||||||
* @param dstAddress the destination slave address to send to.
|
* @param dstAddress the destination slave address to send to.
|
||||||
* @param loadScanConfig true to immediately load the message definitions matching the scan result.
|
* @param loadScanConfig true to immediately load the message definitions matching the scan result.
|
||||||
* @param reload true to fully reload the scan results.
|
* @param reload true to fully reload the scan results, false when the slave ID was already retrieved.
|
||||||
* @return the result code.
|
* @return the result code.
|
||||||
*/
|
*/
|
||||||
result_t scanAndWait(symbol_t dstAddress, bool loadScanConfig = false, bool reload = false);
|
result_t scanAndWait(symbol_t dstAddress, bool loadScanConfig = false, bool reload = false);
|
||||||
@@ -541,10 +554,9 @@ class BusHandler : public WaitThread {
|
|||||||
/**
|
/**
|
||||||
* Get the next slave address that still needs to be scanned or loaded.
|
* Get the next slave address that still needs to be scanned or loaded.
|
||||||
* @param lastAddress the last returned slave address, or 0 for returning the first one.
|
* @param lastAddress the last returned slave address, or 0 for returning the first one.
|
||||||
* @param onlyScanned true to return only already scanned addresses.
|
|
||||||
* @return the next slave address that still needs to be scanned or loaded, or @a SYN.
|
* @return the next slave address that still needs to be scanned or loaded, or @a SYN.
|
||||||
*/
|
*/
|
||||||
symbol_t getNextScanAddress(symbol_t lastAddress, bool onlyScanned = false);
|
symbol_t getNextScanAddress(symbol_t lastAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the state of the participant to configuration @a LOADED.
|
* Set the state of the participant to configuration @a LOADED.
|
||||||
|
|||||||
+70
-39
@@ -86,11 +86,12 @@ static struct options opt = {
|
|||||||
|
|
||||||
CONFIG_PATH, // configPath
|
CONFIG_PATH, // configPath
|
||||||
false, // scanConfig
|
false, // scanConfig
|
||||||
BROADCAST, // initialScan
|
0, // initialScan
|
||||||
getenv("LANG"), // preferLanguage
|
getenv("LANG"), // preferLanguage
|
||||||
false, // checkConfig
|
false, // checkConfig
|
||||||
false, // dumpConfig
|
false, // dumpConfig
|
||||||
5, // pollInterval
|
5, // pollInterval
|
||||||
|
false, // injectMessages
|
||||||
|
|
||||||
0x31, // address
|
0x31, // address
|
||||||
false, // answer
|
false, // answer
|
||||||
@@ -177,13 +178,16 @@ static const struct argp_option argpoptions[] = {
|
|||||||
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 },
|
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 },
|
||||||
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
|
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
|
||||||
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
|
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
|
||||||
"default is broadcast ident message). If combined with --checkconfig, you can add scan message data as "
|
"default is broadcast ident message). If combined with --checkconfig and --inject, you can add scan message "
|
||||||
"arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
|
"data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".",
|
||||||
|
0 },
|
||||||
{"configlang", O_CFGLNG, "LANG", 0,
|
{"configlang", O_CFGLNG, "LANG", 0,
|
||||||
"Prefer LANG in multilingual configuration files [system default language]", 0 },
|
"Prefer LANG in multilingual configuration files [system default language]", 0 },
|
||||||
{"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 },
|
{"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 },
|
||||||
{"dumpconfig", O_DMPCFG, NULL, 0, "Check and dump CSV config files, then stop", 0 },
|
{"dumpconfig", O_DMPCFG, NULL, 0, "Check and dump CSV config files, then stop", 0 },
|
||||||
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
{"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 },
|
||||||
|
{"inject", 'i', NULL, 0, "Inject remaining arguments as already seen messages (e.g. "
|
||||||
|
"\"FF08070400/0AB5454850303003277201\")", 0 },
|
||||||
|
|
||||||
{NULL, 0, NULL, 0, "eBUS options:", 3 },
|
{NULL, 0, NULL, 0, "eBUS options:", 3 },
|
||||||
{"address", 'a', "ADDR", 0, "Use ADDR as own bus address [31]", 0 },
|
{"address", 'a', "ADDR", 0, "Use ADDR as own bus address [31]", 0 },
|
||||||
@@ -261,13 +265,18 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
opt->noDeviceCheck = true;
|
opt->noDeviceCheck = true;
|
||||||
break;
|
break;
|
||||||
case 'r': // --readonly
|
case 'r': // --readonly
|
||||||
if (opt->answer || opt->generateSyn) {
|
if (opt->answer || opt->generateSyn || opt->initialSend
|
||||||
argp_error(state, "cannot combine readonly with answer/generatesyn");
|
|| (opt->scanConfig && opt->initialScan != 0 && opt->initialScan != ESC)) {
|
||||||
|
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->readOnly = true;
|
opt->readOnly = true;
|
||||||
break;
|
break;
|
||||||
case O_INISND: // --initsend
|
case O_INISND: // --initsend
|
||||||
|
if (opt->readOnly) {
|
||||||
|
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
opt->initialSend = true;
|
opt->initialSend = true;
|
||||||
break;
|
break;
|
||||||
case O_DEVLAT: // --latency=10000
|
case O_DEVLAT: // --latency=10000
|
||||||
@@ -307,6 +316,10 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
opt->initialScan = getSlaveAddress(opt->initialScan);
|
opt->initialScan = getSlaveAddress(opt->initialScan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (opt->readOnly && opt->initialScan != ESC) {
|
||||||
|
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case O_CFGLNG: // --configlang=LANG
|
case O_CFGLNG: // --configlang=LANG
|
||||||
@@ -330,6 +343,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'i': // --inject
|
||||||
|
opt->injectMessages = true;
|
||||||
|
break;
|
||||||
|
|
||||||
// eBUS options:
|
// eBUS options:
|
||||||
case 'a': // --address=31
|
case 'a': // --address=31
|
||||||
@@ -341,7 +357,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case O_ANSWER: // --answer
|
case O_ANSWER: // --answer
|
||||||
if (opt->readOnly) {
|
if (opt->readOnly) {
|
||||||
argp_error(state, "cannot combine readonly with answer/generatesyn");
|
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->answer = true;
|
opt->answer = true;
|
||||||
@@ -383,7 +399,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
case O_GENSYN: // --generatesyn
|
case O_GENSYN: // --generatesyn
|
||||||
if (opt->readOnly) {
|
if (opt->readOnly) {
|
||||||
argp_error(state, "cannot combine readonly with answer/generatesyn");
|
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
opt->generateSyn = true;
|
opt->generateSyn = true;
|
||||||
@@ -539,7 +555,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARGP_KEY_ARG:
|
case ARGP_KEY_ARG:
|
||||||
if (!opt->checkConfig) {
|
if (!opt->injectMessages) {
|
||||||
argp_error(state, "invalid arguments starting with \"%s\"", arg);
|
argp_error(state, "invalid arguments starting with \"%s\"", arg);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@@ -830,11 +846,6 @@ void readMessage(Message* message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method for executing all loaded and resolvable instructions.
|
|
||||||
* @param messages the @a MessageMap instance.
|
|
||||||
* @param verbose whether to verbosely log all problems.
|
|
||||||
*/
|
|
||||||
void executeInstructions(MessageMap* messages, bool verbose) {
|
void executeInstructions(MessageMap* messages, bool verbose) {
|
||||||
string errorDescription;
|
string errorDescription;
|
||||||
result_t result = messages->resolveConditions(errorDescription, verbose);
|
result_t result = messages->resolveConditions(errorDescription, verbose);
|
||||||
@@ -875,13 +886,12 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
|
|||||||
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result),
|
logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result),
|
||||||
errorDescription.c_str());
|
errorDescription.c_str());
|
||||||
}
|
}
|
||||||
executeInstructions(messages, verbose);
|
|
||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose) {
|
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose) {
|
||||||
Message* message = messages->getScanMessage(address);
|
Message* message = messages->getScanMessage(address);
|
||||||
if (!message) {
|
if (!message || message->getLastUpdateTime() == 0) {
|
||||||
return RESULT_ERR_NOTFOUND;
|
return RESULT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
const SlaveSymbolString& data = message->getLastSlaveData();
|
const SlaveSymbolString& data = message->getLastSlaveData();
|
||||||
@@ -1042,10 +1052,33 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
|
|||||||
}
|
}
|
||||||
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);
|
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);
|
||||||
relativeFile = best.substr(strlen(opt.configPath)+1);
|
relativeFile = best.substr(strlen(opt.configPath)+1);
|
||||||
executeInstructions(messages, verbose);
|
|
||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parseMessage(const string& arg, MasterSymbolString& master, SlaveSymbolString& slave, bool onlyMasterSlave) {
|
||||||
|
size_t pos = arg.find_first_of('/');
|
||||||
|
if (pos == string::npos) {
|
||||||
|
logError(lf_main, "invalid message %s: missing \"/\"", arg.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result_t result = master.parseHex(arg.substr(0, pos));
|
||||||
|
if (result == RESULT_OK) {
|
||||||
|
result = slave.parseHex(arg.substr(pos+1));
|
||||||
|
}
|
||||||
|
if (result != RESULT_OK) {
|
||||||
|
logError(lf_main, "invalid message %s: %s", arg.c_str(), getResultCode(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (master.size() < 5) { // skip QQ ZZ PB SB NN
|
||||||
|
logError(lf_main, "invalid message %s: master part too short", arg.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isMaster(master[0])) {
|
||||||
|
logError(lf_main, "invalid message %s: QQ is no master", arg.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main function.
|
* Main function.
|
||||||
@@ -1063,6 +1096,9 @@ int main(int argc, char* argv[]) {
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!opt.readOnly && opt.scanConfig && opt.initialScan == 0) {
|
||||||
|
opt.initialScan = BROADCAST;
|
||||||
|
}
|
||||||
if (opt.logAreas != -1 || opt.logLevel != ll_COUNT) {
|
if (opt.logAreas != -1 || opt.logLevel != ll_COUNT) {
|
||||||
setFacilitiesLogLevel(LF_ALL, ll_none);
|
setFacilitiesLogLevel(LF_ALL, ll_none);
|
||||||
setFacilitiesLogLevel(opt.logAreas, opt.logLevel);
|
setFacilitiesLogLevel(opt.logAreas, opt.logLevel);
|
||||||
@@ -1073,27 +1109,12 @@ int main(int argc, char* argv[]) {
|
|||||||
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
|
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
|
||||||
|
|
||||||
result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc);
|
result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc);
|
||||||
|
executeInstructions(s_messageMap, true);
|
||||||
|
MasterSymbolString master;
|
||||||
|
SlaveSymbolString slave;
|
||||||
while (result == RESULT_OK && opt.scanConfig && arg_index < argc) {
|
while (result == RESULT_OK && opt.scanConfig && arg_index < argc) {
|
||||||
// check scan config for each passed ident message
|
// check scan config for each passed ident message
|
||||||
string arg = argv[arg_index++];
|
if (!parseMessage(argv[arg_index++], master, slave, true)) {
|
||||||
size_t pos = arg.find_first_of('/');
|
|
||||||
if (pos == string::npos) {
|
|
||||||
logError(lf_main, "invalid scan message %s: missing \"/\"", arg.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MasterSymbolString master;
|
|
||||||
SlaveSymbolString slave;
|
|
||||||
result_t res = master.parseHex(arg.substr(0, pos));
|
|
||||||
if (res == RESULT_OK) {
|
|
||||||
res = slave.parseHex(arg.substr(pos+1));
|
|
||||||
}
|
|
||||||
if (res != RESULT_OK) {
|
|
||||||
logError(lf_main, "invalid scan message %s: %s", arg.c_str(), getResultCode(res));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (master.size() < 5) { // skip QQ ZZ PB SB NN
|
|
||||||
logError(lf_main, "invalid scan message %s: master part too short", arg.c_str());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
symbol_t address = master[1];
|
symbol_t address = master[1];
|
||||||
@@ -1103,7 +1124,8 @@ int main(int argc, char* argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
message->storeLastData(master, slave);
|
message->storeLastData(master, slave);
|
||||||
string file;
|
string file;
|
||||||
res = loadScanConfigFile(s_messageMap, address, file, true);
|
result_t res = loadScanConfigFile(s_messageMap, address, file, true);
|
||||||
|
executeInstructions(s_messageMap, true);
|
||||||
if (res == RESULT_OK) {
|
if (res == RESULT_OK) {
|
||||||
logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str());
|
logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str());
|
||||||
}
|
}
|
||||||
@@ -1139,12 +1161,21 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// load configuration files
|
// load configuration files
|
||||||
loadConfigFiles(s_messageMap);
|
loadConfigFiles(s_messageMap);
|
||||||
if (s_messageMap->sizeConditions() > 0 && opt.pollInterval == 0) {
|
|
||||||
logError(lf_main, "conditions require a poll interval > 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the MainLoop and start it
|
// create the MainLoop and start it
|
||||||
s_mainLoop = new MainLoop(opt, device, s_messageMap);
|
s_mainLoop = new MainLoop(opt, device, s_messageMap);
|
||||||
|
if (opt.injectMessages) {
|
||||||
|
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||||
|
MasterSymbolString master;
|
||||||
|
SlaveSymbolString slave;
|
||||||
|
while (arg_index < argc) {
|
||||||
|
// add each passed message
|
||||||
|
if (!parseMessage(argv[arg_index++], master, slave, false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
busHandler->injectMessage(master, slave);
|
||||||
|
}
|
||||||
|
}
|
||||||
s_mainLoop->start("mainloop");
|
s_mainLoop->start("mainloop");
|
||||||
|
|
||||||
// wait for end of MainLoop
|
// wait for end of MainLoop
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct options {
|
|||||||
bool checkConfig; //!< check CSV config files, then stop
|
bool checkConfig; //!< check CSV config files, then stop
|
||||||
bool dumpConfig; //!< dump CSV config files, then stop
|
bool dumpConfig; //!< dump CSV config files, then stop
|
||||||
unsigned int pollInterval; //!< poll interval in seconds, 0 to disable [5]
|
unsigned int pollInterval; //!< poll interval in seconds, 0 to disable [5]
|
||||||
|
bool injectMessages; //!< inject remaining arguments as already seen messages
|
||||||
|
|
||||||
symbol_t address; //!< own bus address [31]
|
symbol_t address; //!< own bus address [31]
|
||||||
bool answer; //!< answer to requests from other masters
|
bool answer; //!< answer to requests from other masters
|
||||||
@@ -111,6 +112,13 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose = false, bool denyRe
|
|||||||
*/
|
*/
|
||||||
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose = false);
|
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for executing all loaded and resolvable instructions.
|
||||||
|
* @param messages the @a MessageMap instance.
|
||||||
|
* @param verbose whether to verbosely log all problems.
|
||||||
|
*/
|
||||||
|
void executeInstructions(MessageMap* messages, bool verbose = false);
|
||||||
|
|
||||||
} // namespace ebusd
|
} // namespace ebusd
|
||||||
|
|
||||||
#endif // EBUSD_MAIN_H_
|
#endif // EBUSD_MAIN_H_
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ result_t UserList::addFromFile(map<string, string>& row, vector< map<string, str
|
|||||||
|
|
||||||
MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* messages)
|
MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* messages)
|
||||||
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
|
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
|
||||||
m_address(opt.address), m_scanConfig(opt.scanConfig),
|
m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.readOnly ? ESC : opt.initialScan),
|
||||||
m_initialScan(opt.initialScan), m_enableHex(opt.enableHex), m_shutdown(false) {
|
m_polling(opt.pollInterval>0), m_enableHex(opt.enableHex), m_shutdown(false) {
|
||||||
// open Device
|
// open Device
|
||||||
result_t result = m_device->open();
|
result_t result = m_device->open();
|
||||||
if (result != RESULT_OK) {
|
if (result != RESULT_OK) {
|
||||||
@@ -287,6 +287,13 @@ void MainLoop::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (reload && m_busHandler->hasSignal()) {
|
||||||
|
reload = false;
|
||||||
|
// execute initial instructions
|
||||||
|
executeInstructions(m_messages);
|
||||||
|
if (m_messages->sizeConditions() > 0 && !m_polling) {
|
||||||
|
logError(lf_main, "conditions require a poll interval > 0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!m_shutdown && now > nextCheckRun) {
|
if (!m_shutdown && now > nextCheckRun) {
|
||||||
TCPClient client;
|
TCPClient client;
|
||||||
|
|||||||
@@ -349,6 +349,9 @@ class MainLoop : public Thread, DeviceListener {
|
|||||||
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
* (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */
|
||||||
const symbol_t m_initialScan;
|
const symbol_t m_initialScan;
|
||||||
|
|
||||||
|
/** true when the poll interval is non zero. */
|
||||||
|
const bool m_polling;
|
||||||
|
|
||||||
/** whether to enable the hex command. */
|
/** whether to enable the hex command. */
|
||||||
const bool m_enableHex;
|
const bool m_enableHex;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user