diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index bd3454ae..595df761 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -70,6 +70,7 @@ static struct options opt = { -1, // latency CONFIG_PATH, // configPath false, // scanConfig + BROADCAST, // initialScan 0, // checkConfig 5, // pollInterval 0x31, // address @@ -144,7 +145,7 @@ static const struct argp_option argpoptions[] = { {NULL, 0, NULL, 0, "Message configuration options:", 2 }, {"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 }, - {"scanconfig", 's', NULL, 0, "Pick CSV config files matching initial scan. If combined with --checkconfig, you can add scan message data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 }, + {"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, default is broadcast ident message). If combined with --checkconfig, you can add scan message data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 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 }, {"pollinterval", O_POLINT, "SEC", 0, "Poll for data every SEC seconds (0=disable) [5]", 0 }, @@ -224,7 +225,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) case O_INISND: // --initsend opt->initialSend = true; break; - case O_DEVLAT: // --latency + case O_DEVLAT: // --latency=10000 opt->latency = parseInt(arg, 10, 0, 200000, result); if (result != RESULT_OK) { argp_error(state, "invalid latency"); @@ -240,12 +241,28 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) } opt->configPath = arg; break; - case 's': // --scanconfig + case 's': // --scanconfig[=ADDR] (ADDR=|full|) opt->scanConfig = true; if (opt->readOnly) { argp_error(state, "cannot combine readonly with scanconfig/answer/generatesyn"); return EINVAL; } + if (arg != NULL) { + if (arg[0] == 0 || strcmp("none", arg) == 0) { + opt->initialScan = ESC; + } else if (strcmp("full", arg) == 0) { + opt->initialScan = SYN; + } else { + opt->initialScan = (unsigned char)parseInt(arg, 16, 0x00, 0xff, result); + if (!isValidAddress(opt->initialScan)) { + argp_error(state, "invalid initial scan address"); + return EINVAL; + } + if (isMaster(opt->initialScan)) { + opt->initialScan = (unsigned char)(opt->initialScan+5); + } + } + } break; case O_CHKCFG: // --checkconfig if (opt->checkConfig==0) @@ -344,7 +361,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) case O_LOCAL: // --localhost opt->localOnly = true; break; - case O_HTTPPT: // --httpport + case O_HTTPPT: // --httpport=0 opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, result); if (result != RESULT_OK) { argp_error(state, "invalid port"); @@ -897,8 +914,9 @@ int main(int argc, char* argv[]) struct argp argp = { argpoptions, parse_opt, NULL, argpdoc, NULL, NULL, NULL }; int arg_index = -1; setenv("ARGP_HELP_FMT", "no-dup-args-note", 0); - if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &arg_index, &opt) != 0) + if (argp_parse(&argp, argc, argv, ARGP_IN_ORDER, &arg_index, &opt) != 0) { return EINVAL; + } s_messageMap = new MessageMap(opt.checkConfig && opt.scanConfig && arg_index >= argc); if (opt.checkConfig) { diff --git a/src/ebusd/main.h b/src/ebusd/main.h index f53f64a2..1e28b510 100644 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -37,6 +37,7 @@ struct options const char* configPath; //!< path to CSV configuration files [/etc/ebusd] bool scanConfig; //!< pick configuration files matching initial scan + unsigned char initialScan; //!< the initial address to scan for scanconfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address) int checkConfig; //!< check CSV config files (!=0) and optionally dump (2), then stop int pollInterval; //!< poll interval in seconds, 0 to disable [5] diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index e7ddf9f5..60dcb8ef 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -42,7 +42,7 @@ static const char* columnNames[] = { static const size_t columnCount = sizeof(columnNames) / sizeof(char*); MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* messages) - : m_device(device), m_messages(messages), m_address(opt.address), m_scanConfig(opt.scanConfig), m_enableHex(opt.enableHex) + : m_device(device), m_messages(messages), m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.initialScan), m_enableHex(opt.enableHex) { // setup Device m_device->setLogRaw(opt.logRaw); @@ -96,7 +96,7 @@ MainLoop::~MainLoop() void MainLoop::run() { - bool running = true; + bool running = true, reload = true; time_t lastTaskRun, now; int taskDelay = 5; unsigned char lastScanAddress = 0; // 0 is known to be a master @@ -115,6 +115,31 @@ void MainLoop::run() } else if (now > lastTaskRun+taskDelay) { logDebug(lf_main, "performing regular tasks"); if (m_scanConfig) { + if (m_initialScan != ESC && reload && m_busHandler->hasSignal()) { + result_t result = RESULT_ERR_NO_SIGNAL; + if (m_initialScan == SYN) { + logNotice(lf_main, "initiating full scan"); + result = m_busHandler->startScan(true); + } else { + logNotice(lf_main, "starting initial scan for %2.2x", m_initialScan); + SymbolString slave(false); + result = m_busHandler->scanAndWait(m_initialScan, slave); + Message* message = m_messages->getScanMessage(m_initialScan); + if (result == RESULT_OK && message != NULL) { + ostringstream ret; + result = message->decodeLastData(ret, 0, true); // decode data + if (result == RESULT_OK) { + logNotice(lf_main, "initial scan result: %2.2x%s", m_initialScan, ret.str().c_str()); + } + } + } + if (result != RESULT_OK) { + logError(lf_main, "initial scan failed: %s", getResultCode(result)); + } + if (result != RESULT_ERR_NO_SIGNAL) { + reload = false; + } + } bool scanned = false; lastScanAddress = m_busHandler->getNextScanAddress(lastScanAddress, scanned); if (lastScanAddress==SYN) { @@ -164,7 +189,7 @@ void MainLoop::run() bool connected = true; if (request.length() > 0) { logDebug(lf_main, ">>> %s", request.c_str()); - result = decodeMessage(request, message->isHttp(), connected, listening, running); + result = decodeMessage(request, message->isHttp(), connected, listening, running, reload); if (result.length() == 0 && !message->isHttp()) result = getResultCode(RESULT_EMPTY); @@ -188,7 +213,7 @@ void MainLoop::run() } } -string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, bool& running) +string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, bool& running, bool& reload) { ostringstream result; @@ -272,8 +297,10 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return executeRaw(args); if (strcasecmp(str, "DUMP") == 0) return executeDump(args); - if (strcasecmp(str, "RELOAD") == 0) + if (strcasecmp(str, "RELOAD") == 0) { + reload = true; return executeReload(args); + } if (strcasecmp(str, "STOP") == 0) return executeStop(args, running); if (strcasecmp(str, "Q") == 0 || strcasecmp(str, "QUIT") == 0) @@ -993,6 +1020,8 @@ string MainLoop::executeScan(vector &args) result_t result; unsigned char dstAddress = (unsigned char)parseInt(args[1].c_str(), 16, 0, 0xff, result); + if (result == RESULT_OK && !isValidAddress(dstAddress, false)) + result = RESULT_ERR_INVALID_ADDR; if (result != RESULT_OK) return getResultCode(result); @@ -1001,7 +1030,7 @@ string MainLoop::executeScan(vector &args) if (result != RESULT_OK) return getResultCode(result); - Message* message = m_messages->getScanMessage(dstAddress); // never NULL due to scanAndWait() == RESULT_OK + Message* message = m_messages->getScanMessage(dstAddress); // never NULL due to scanAndWait() == RESULT_OK && dstAddress != BROADCAST ostringstream ret; ret << hex << setw(2) << setfill('0') << static_cast(dstAddress); result = message->decodeLastData(ret, 0, true); // decode data diff --git a/src/ebusd/mainloop.h b/src/ebusd/mainloop.h index ecc0ba5a..34c2efa1 100644 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -72,6 +72,9 @@ private: /** whether to pick configuration files matching initial scan. */ const bool m_scanConfig; + /** the initial address to scan for @a m_scanConfig (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */ + const unsigned char m_initialScan; + /** whether to enable the hex command. */ const bool m_enableHex; @@ -94,9 +97,10 @@ private: * @param isHttp true for HTTP message. * @param listening set to true when the client is in listening mode. * @param running set to false when the server shall be stopped. + * @param reload set to true when the configuration files were reloaded. * @return result string to send back to the client. */ - string decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, bool& running); + string decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, bool& running, bool& reload); /** * Parse the hex master message from the remaining arguments.