diff --git a/src/ebusd/Makefile.am b/src/ebusd/Makefile.am index 0b845b61..ca01fd59 100644 --- a/src/ebusd/Makefile.am +++ b/src/ebusd/Makefile.am @@ -10,9 +10,9 @@ ebusd_SOURCES = bushandler.cpp \ bushandler.h \ network.cpp \ network.h \ - baseloop.cpp \ - baseloop.h \ - ebusd.cpp + mainloop.cpp \ + mainloop.h \ + main.cpp ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ $(top_srcdir)/src/lib/ebus/libebus.a \ diff --git a/src/ebusd/baseloop.cpp b/src/ebusd/baseloop.cpp deleted file mode 100644 index df0f2f16..00000000 --- a/src/ebusd/baseloop.cpp +++ /dev/null @@ -1,645 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-2014 - * - * This file is part of ebusd. - * - * ebusd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ebusd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ebusd. If not, see http://www.gnu.org/licenses/. - */ - -#include "baseloop.h" -#include "logger.h" -#include "appl.h" -#include "data.h" -#include - -using namespace std; - -extern Logger& L; -extern Appl& A; - -BaseLoop::BaseLoop() -{ - // load messages and templates - m_templates = new DataFieldTemplates(); - m_messages = new MessageMap(); - loadMessages(); - - // exit if checkconfig is true - if (A.getOptVal("checkconfig") == true) { - m_port = NULL; - return; - } - - m_ownAddress = A.getOptVal("address") & 0xff; - const bool answer = A.getOptVal("answer"); - - const bool logRaw = A.getOptVal("lograwdata"); - - const bool dumpRaw = A.getOptVal("dump"); - const char* dumpRawFile = A.getOptVal("dumpfile"); - const long dumpRawMaxSize = A.getOptVal("dumpsize"); - - const unsigned int busLostRetries = A.getOptVal("acquireretries"); - const unsigned int failedSendRetries = A.getOptVal("sendretries"); - const unsigned int busAcquireWaitTime = A.getOptVal("acquiretimeout"); - const unsigned int slaveRecvTimeout = A.getOptVal("receivetimeout"); - const unsigned int lockCount = A.getOptVal("numbermasters"); - int pollInterval = A.getOptVal("pollinterval"); - if (pollInterval <= 0) { - m_pollActive = false; - pollInterval = 0; - } - else - m_pollActive = true; - - // create Port - m_port = new Port(A.getOptVal("device"), A.getOptVal("nodevicecheck"), logRaw, &BaseLoop::logRaw, dumpRaw, dumpRawFile, dumpRawMaxSize); - m_port->open(); - - if (m_port->isOpen() == false) - L.log(bus, error, "can't open %s", m_port->getDeviceName()); - - // create BusHandler - m_busHandler = new BusHandler(m_port, m_messages, - m_ownAddress, answer, - busLostRetries, failedSendRetries, - busAcquireWaitTime, slaveRecvTimeout, - lockCount, pollInterval); - m_busHandler->start("bushandler"); - - // create network - m_network = new Network(A.getOptVal("localhost"), A.getOptVal("port"), &m_netQueue); - m_network->start("network"); -} - -BaseLoop::~BaseLoop() -{ - if (m_network != NULL) { - delete m_network; - m_network = NULL; - } - - if (m_busHandler != NULL) { - m_busHandler->stop(); - m_busHandler->join(); - delete m_busHandler; - m_busHandler = NULL; - } - - if (m_port != NULL) { - delete m_port; - m_port = NULL; - } - - if (m_messages != NULL) { - delete m_messages; - m_messages = NULL; - } - - if (m_templates != NULL) { - delete m_templates; - m_templates = NULL; - } -} - -extern result_t loadConfigFiles(DataFieldTemplates* templates, MessageMap* messages, bool verbose=false); - -result_t BaseLoop::loadMessages() -{ - return loadConfigFiles(m_templates, m_messages); -} - -void BaseLoop::start() -{ - for (;;) { - string result; - - // recv new message from client - NetMessage* message = m_netQueue.remove(); - string data = message->getData(); - - time_t since, until; - time(&until); - bool listening = message->isListening(since); - if (listening == false) - since = until; - - if (data.length() > 0) { - data.erase(remove(data.begin(), data.end(), '\r'), data.end()); - data.erase(remove(data.begin(), data.end(), '\n'), data.end()); - - L.log(bas, event, ">>> %s", data.c_str()); - - // decode message - if (strcasecmp(data.c_str(), "STOP") != 0) - result = decodeMessage(data, listening); - else - result = "done"; - - L.log(bas, event, "<<< %s", result.c_str()); - result += "\n\n"; - } - if (listening == true) { - result += getUpdates(since, until); - } - - // send result to client - message->setResult(result, listening, until); - - // stop daemon - if (strcasecmp(data.c_str(), "STOP") == 0) - return; - } -} - -void BaseLoop::logRaw(const unsigned char byte, bool received) { - if (received == true) - L.log(bus, event, "<%02x", byte); - else - L.log(bus, event, ">%02x", byte); -} - -string BaseLoop::decodeMessage(const string& data, bool& listening) -{ - ostringstream result; - - // prepare data - string token, previous; - istringstream stream(data); - vector args; - bool escaped = false; - - while (getline(stream, token, ' ') != 0) { - if (escaped == true) { - args.pop_back(); - if (token.length() > 0 && token[token.length()-1] == '"') { - token = token.substr(0, token.length() - 1); - escaped = false; - } - token = previous + " " + token; - } - else if (token.length() == 0) // allow multiple space chars for a single delimiter - continue; - else if (token[0] == '"') { - token = token.substr(1); - if (token.length() > 0 && token[token.length()-1] == '"') - token = token.substr(0, token.length() - 1); - else - escaped = true; - } - args.push_back(token); - previous = token; - } - - if (args.size() == 0) - return "command missing"; - - size_t argPos = 1; - - switch (getCase(args[0])) { - case ct_invalid: - result << "command not found"; - break; - - case ct_read: { - time_t maxAge = 5*60; - bool verbose = false; - string clazz; - while (args.size() > argPos && args[argPos][0] == '-') { - if (args[argPos] == "-f") { - maxAge = 0; - } - else if (args[argPos] == "-v") { - verbose = true; - } - else if (args[argPos] == "-m") { - argPos++; - if (args.size() > argPos) { - result_t result; - maxAge = parseInt(args[argPos].c_str(), 10, 0, 24*60*60, result); - if (result != RESULT_OK) { - argPos = 0; // print usage - break; - } - } - else { - argPos = 0; // print usage - break; - } - } - else if (args[argPos] == "-c") { - argPos++; - if (argPos >= args.size()) { - argPos = 0; // print usage - break; - } - clazz = args[argPos]; - } - else { - argPos = 0; // print usage - break; - } - argPos++; - } - if (argPos == 0 || args.size() < argPos + 1 || args.size() > argPos + 2) { - result << "usage: 'read [-v] [-f] [-m seconds] [-c class] name [field]'"; - break; - } - if (args.size() == argPos + 2) - maxAge = 0; // force refresh to filter single field - - time_t now; - time(&now); - - Message* updateMessage = NULL; - if (maxAge > 0 && verbose == false) { - updateMessage = m_messages->find(clazz, args[argPos], false, true); - - if (updateMessage != NULL && updateMessage->getLastUpdateTime() + maxAge > now) { - result << updateMessage->getLastValue(); // TODO switch from last value to last master/slave to support verbose cached/polled values as well - break; - } // else: check poll data or read directly from bus - } - - Message* message = m_messages->find(clazz, args[argPos], false); - - if (message != NULL) { - if (maxAge > 0 && m_pollActive == true && message->getPollPriority() > 0 - && message->getLastUpdateTime() + maxAge > now) { - // get polldata - result << message->getLastValue(); - break; - } // else: read directly from bus - - SymbolString master; - istringstream input; - result_t ret = message->prepareMaster(m_ownAddress, master, input); - if (ret != RESULT_OK) { - L.log(bas, error, "prepare read: %s", getResultCode(ret)); - result << getResultCode(ret); - break; - } - L.log(bas, trace, "read cmd: %s", master.getDataStr().c_str()); - - // send message - SymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); - - if (ret == RESULT_OK) { - if (args.size() == argPos + 2) - ret = message->decode(pt_slaveData, slave, result, false, verbose, args[argPos + 1].c_str()); - else - ret = message->decode(pt_slaveData, slave, result, false, verbose); // decode data - } - if (ret != RESULT_OK) { - L.log(bas, error, "read: %s", getResultCode(ret)); - result << getResultCode(ret); - } - } - else if (updateMessage != NULL) { - result << "no data stored"; - } - else { - result << "message not defined"; - } - break; - } - case ct_write: { - if (args.size() > argPos && args[argPos] == "-h") { - argPos++; - - if (args.size() < argPos + 1) { - result << "usage: 'write -h ZZPBSBNNDx'"; - break; - } - - ostringstream msg; - msg << hex << setw(2) << setfill('0') << static_cast(m_ownAddress) << setw(0); - while (argPos < args.size()) { - if ((args[argPos].length() % 2) != 0) { - result << "invalid hex string"; - msg.str(""); - break; - } - msg << args[argPos++]; - } - if (msg.str().length() == 0) - break; - - SymbolString master(msg.str()); - if (isValidAddress(master[1]) == false) { - result << "invalid destination"; - break; - } - L.log(bas, event, "write hex cmd: %s", master.getDataStr().c_str()); - - // send message - SymbolString slave; - result_t ret = m_busHandler->sendAndWait(master, slave); - - if (ret == RESULT_OK) { - if (master[1] == BROADCAST || isMaster(master[1])) - result << "done"; - else - result << slave.getDataStr(); - } - if (ret != RESULT_OK) { - L.log(bas, error, "write hex: %s", getResultCode(ret)); - result << getResultCode(ret); - } - break; - } - - if (args.size() != argPos + 3) { - result << "usage: 'write class name value[;value]*' or 'write -h ZZPBSBNNDx'"; - break; - } - - Message* message = m_messages->find(args[argPos], args[argPos + 1], true); - - if (message != NULL) { - SymbolString master; - istringstream input(args[argPos + 2]); - result_t ret = message->prepareMaster(m_ownAddress, master, input); - if (ret != RESULT_OK) { - L.log(bas, error, "prepare write: %s", getResultCode(ret)); - result << getResultCode(ret); - break; - } - L.log(bas, trace, "write cmd: %s", master.getDataStr().c_str()); - - // send message - SymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); - - if (ret == RESULT_OK) { - if (master[1] == BROADCAST || isMaster(master[1])) - result << "done"; - else { - ret = message->decode(pt_slaveData, slave, result); // decode data - if (ret == RESULT_OK && result.str().empty() == true) - result << "done"; - } - } - if (ret != RESULT_OK) { - L.log(bas, error, "write: %s", getResultCode(ret)); - result << getResultCode(ret); - } - - } - else { - result << "message not defined"; - } - break; - } - case ct_find: { - bool verbose = false, withRead = true, withWrite = true, withPassive = true, first = true, onlyWithData = false; - string clazz; - while (args.size() > argPos && args[argPos][0] == '-') { - if (args[argPos] == "-v") - verbose = true; - else if (args[argPos] == "-r") { - if (first == true) { - first = false; - withWrite = withPassive = false; - } - withRead = true; - } - else if (args[argPos] == "-w") { - if (first == true) { - first = false; - withRead = withPassive = false; - } - withWrite = true; - } - else if (args[argPos] == "-p") { - if (first == true) { - first = false; - withRead = withWrite = false; - } - withPassive = true; - } - else if (args[argPos] == "-d") { - onlyWithData = true; - } - else if (args[argPos] == "-c") { - argPos++; - if (argPos >= args.size()) { - argPos = 0; // print usage - break; - } - clazz = args[argPos]; - } - else { - argPos = 0; // print usage - break; - } - argPos++; - } - if (argPos == 0 || args.size() < argPos || args.size() > argPos + 1) { - result << "usage: 'find [-v] [-r] [-w] [-p] [-d] [-c class] [name]'"; - break; - } - - deque messages; - if (args.size() == argPos) - messages = m_messages->findAll(clazz, "", -1, false, withRead, withWrite, withPassive); - else - messages = m_messages->findAll(clazz, args[argPos], -1, false, withRead, withWrite, withPassive); - - bool found = false; - char str[34]; - for (deque::iterator it = messages.begin(); it < messages.end();) { - Message* message = *it++; - unsigned char dstAddress = message->getDstAddress(); - if (dstAddress == SYN) - continue; - time_t lastup = message->getLastUpdateTime(); - if (onlyWithData == true && lastup == 0) - continue; - if (found == true) - result << endl; - result << message->getClass() << " " << message->getName() << " = "; - if (lastup == 0) - result << "no data stored"; - else - result << message->getLastValue(); - if (verbose == true) { - if (lastup == 0) - sprintf(str, "ZZ=%02x", dstAddress); - else { - struct tm* td = localtime(&lastup); - sprintf(str, "ZZ=%02x, lastup=%04d-%02d-%02d %02d:%02d:%02d", - dstAddress, td->tm_year+1900, td->tm_mon+1, td->tm_mday, - td->tm_hour, td->tm_min, td->tm_sec); - } - result << " [" << str << "]"; - } - found = true; - } - if (found == false) - result << "no message found"; - break; - } - case ct_listen: { - if (args.size() == argPos) { - if (listening == true) - return "listen continued"; - listening = true; - return "listen started"; - } - - if (args.size() != argPos+1 || args[argPos] != "stop") - return "usage: 'listen [stop]'"; - - listening = false; - return "listen stopped"; - } - case ct_scan: { - if (args.size() == argPos) { - result_t ret = m_busHandler->startScan(); - if (ret != RESULT_OK) { - L.log(bas, error, "scan: %s", getResultCode(ret)); - result << getResultCode(ret); - } - else - result << "scan initiated"; - break; - } - - if (strcasecmp(args[argPos].c_str(), "FULL") == 0) { - result_t ret = m_busHandler->startScan(true); - if (ret != RESULT_OK) { - L.log(bas, error, "full scan: %s", getResultCode(ret)); - result << getResultCode(ret); - } - else - result << "done"; - break; - } - - if (strcasecmp(args[argPos].c_str(), "RESULT") == 0) { - m_busHandler->formatScanResult(result); - break; - } - - result << "usage: 'scan'" << endl - << " 'scan full'" << endl - << " 'scan result'"; - break; - } - case ct_log: { - if (args.size() != argPos + 2 ) { - result << "usage: 'log areas area,area,..' (areas: bas|net|bus|upd|all)" << endl - << " 'log level level' (level: error|event|trace|debug)"; - break; - } - - if (strcasecmp(args[argPos].c_str(), "AREAS") == 0) { - L.setAreaMask(calcAreaMask(args[argPos + 1])); - result << "done"; - break; - } - - if (strcasecmp(args[argPos].c_str(), "LEVEL") == 0) { - L.setLevel(calcLevel(args[argPos + 1])); - result << "done"; - break; - } - - result << "usage: 'log areas area,area,..' (areas: bas|net|bus|upd|all)" << endl - << " 'log level level' (level: error|event|trace|debug)"; - break; - } - case ct_raw: { - if (args.size() != argPos) { - result << "usage: 'raw'"; - break; - } - - bool enabled = !m_port->getLogRaw(); - m_port->setLogRaw(enabled); - result << (enabled ? "raw output enabled" : "raw output disabled"); - break; - } - case ct_dump: { - if (args.size() != argPos) { - result << "usage: 'dump'"; - break; - } - - bool enabled = !m_port->getDumpRaw(); - m_port->setDumpRaw(enabled); - result << (enabled ? "dump enabled" : "dump disabled"); - break; - } - case ct_reload: { - if (args.size() != argPos) { - result << "usage: 'reload'"; - break; - } - - // create commands DB - result_t ret = loadMessages(); - if (ret == RESULT_OK) - result << "done"; - else - result << getResultCode(ret); - break; - } - case ct_help: - result << "commands:" << endl - << " read - read ebus values 'read [-v] [-f] [-m seconds] [-c class] name [field]'" << endl - << " write - write ebus values 'write class name value[;value]*' or 'write -h ZZPBSBNNDx'" << endl - << " find - find ebus values 'find [-v] [-r] [-w] [-p] [-d] [-c class] [name]'" << endl - << " listen - listen for updates 'listen [stop]'" << endl - << " scan - scan ebus known addresses 'scan'" << endl - << " - scan ebus all addresses 'scan full'" << endl - << " - show scan results 'scan result'" << endl - << " log - change log areas 'log areas area,area,..' (areas: bas|net|bus|upd|all)" << endl - << " - change log level 'log level level' (level: error|event|trace|debug)" << endl - << " raw - toggle log raw data 'raw'" << endl - << " dump - toggle dump state 'dump'" << endl - << " reload - reload ebus configuration 'reload'" << endl - << " stop - stop daemon 'stop'" << endl - << " quit - close connection 'quit'" << endl - << " help - print this page 'help'"; - break; - - } - - return result.str(); -} - -string BaseLoop::getUpdates(time_t since, time_t until) -{ - ostringstream result; - - deque messages; - messages = m_messages->findAll("", "", -1, false, true, true, true); - - for (deque::iterator it = messages.begin(); it < messages.end();) { - Message* message = *it++; - unsigned char dstAddress = message->getDstAddress(); - if (dstAddress == SYN) - continue; - time_t lastchg = message->getLastChangeTime(); - if (lastchg < since || lastchg >= until) - continue; - result << message->getClass() << " " << message->getName() << " = "; - result << message->getLastValue() << endl; - } - - return result.str(); -} diff --git a/src/ebusd/baseloop.h b/src/ebusd/baseloop.h deleted file mode 100644 index 2692b271..00000000 --- a/src/ebusd/baseloop.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-2014 - * - * This file is part of ebusd. - * - * ebusd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ebusd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ebusd. If not, see http://www.gnu.org/licenses/. - */ - -#ifndef BASELOOP_H_ -#define BASELOOP_H_ - -#include "message.h" -#include "network.h" -#include "bushandler.h" - -/** \file baseloop.h */ - -using namespace std; - -/** possible client commands */ -enum CommandType { - ct_read, //!< read ebus values - ct_write, //!< write ebus values - ct_find, //!< find values - ct_listen, //!< listen for updates to values - ct_scan, //!< scan ebus - ct_log, //!< logger settings - ct_raw, //!< toggle log raw data - ct_dump, //!< toggle dump state - ct_reload, //!< reload ebus configuration - ct_help, //!< print commands - ct_invalid //!< invalid -}; - -/** - * class baseloop which handle client messages. - */ -class BaseLoop -{ - -public: - /** - * Construct the base loop and create messaging, network and bus handling subsystems. - */ - BaseLoop(); - - /** - * Destructor. - */ - ~BaseLoop(); - - /** - * Load the message definitions. - * @return the result code. - */ - result_t loadMessages(); - - /** - * start baseloop instance. - */ - void start(); - - /** - * add a new network message to internal message queue. - * @param message the network message. - */ - void addMessage(NetMessage* message) { m_netQueue.add(message); } - - /** - * Create a log message for a received/sent raw data byte. - * @param byte the raw data byte. - * @param received true if the byte was received, false if it was sent. - */ - static void logRaw(const unsigned char byte, bool received); - -private: - - /** the @a DataFieldTemplates instance. */ - DataFieldTemplates* m_templates; - - /** the @a MessageMap instance. */ - MessageMap* m_messages; - - /** the own master address for sending on the bus. */ - unsigned char m_ownAddress; - - /** whether polling the messages is active. */ - bool m_pollActive; - - /** the @a Port instance. */ - Port* m_port; - - /** the @a BusHandler instance. */ - BusHandler* m_busHandler; - - /** the @a Network instance. */ - Network* m_network; - - /** queue for network messages */ - WQueue m_netQueue; - - /** - * compare client command with defined. - * @param item the client command to compare. - * @return the founded client command type. - */ - CommandType getCase(const string& item) - { - const char* str = item.c_str(); - if (strcasecmp(str, "R") == 0 || strcasecmp(str, "READ") == 0) return ct_read; - if (strcasecmp(str, "W") == 0 || strcasecmp(str, "WRITE") == 0) return ct_write; - if (strcasecmp(str, "F") == 0 || strcasecmp(str, "FIND") == 0) return ct_find; - if (strcasecmp(str, "L") == 0 || strcasecmp(str, "LISTEN") == 0) return ct_listen; - if (strcasecmp(str, "SCAN") == 0) return ct_scan; - if (strcasecmp(str, "LOG") == 0) return ct_log; - if (strcasecmp(str, "RAW") == 0) return ct_raw; - if (strcasecmp(str, "DUMP") == 0) return ct_dump; - if (strcasecmp(str, "RELOAD") == 0) return ct_reload; - if (strcasecmp(str, "H") == 0 || strcasecmp(str, "HELP") == 0) return ct_help; - - return ct_invalid; - } - - /** - * Decode and execute client message. - * @param data the data string to decode (may be empty). - * @param listening set to true when the client is in listening mode. - * @return result string to send back to client. - */ - string decodeMessage(const string& data, bool& listening); - - /** - * Get the updates received since the specified time. - * @param since the start time from which to add updates (inclusive). - * @param until the end time to which to add updates (exclusive). - * @return result string to send back to client. - */ - string getUpdates(time_t since, time_t until); - -}; - -#endif // BASELOOP_H_ diff --git a/src/ebusd/ebusd.cpp b/src/ebusd/ebusd.cpp deleted file mode 100644 index acd09147..00000000 --- a/src/ebusd/ebusd.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) Roland Jax 2012-2014 - * - * This file is part of ebusd. - * - * ebusd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ebusd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ebusd. If not, see http://www.gnu.org/licenses/. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "logger.h" -#include "daemon.h" -#include "appl.h" -#include "baseloop.h" -#include -#include -#include - - -using namespace std; - -Appl& A = Appl::Instance(); -Daemon& D = Daemon::Instance(); -Logger& L = Logger::Instance(); - -BaseLoop* baseloop = NULL; - -void define_args() -{ - - A.setVersion(""PACKAGE_STRING""); - - A.addText("Options:\n"); - - A.addOption("address", "a", OptVal(0xff), dt_hex, ot_mandatory, - "\tebus device address [FF]"); - - A.addOption("answer", "", OptVal(false), dt_bool, ot_none, - "\tanswers to requests from other devices"); - - A.addOption("foreground", "f", OptVal(false), dt_bool, ot_none, - "run in foreground\n"); - - A.addOption("device", "d", OptVal("/dev/ttyUSB0"), dt_string, ot_mandatory, - "\tebus device (serial or network) [/dev/ttyUSB0]"); - - A.addOption("nodevicecheck", "n", OptVal(false), dt_bool, ot_none, - "disable test of local ebus device\n"); - - A.addOption("acquiretimeout", "", OptVal(9400), dt_long, ot_mandatory, - "bus acquisition timeout in 'us' [9400]"); - - A.addOption("acquireretries", "", OptVal(2), dt_int, ot_mandatory, - "number retries to acquire ebus [2]"); - - A.addOption("sendretries", "", OptVal(2), dt_int, ot_mandatory, - "number retries send ebus command [2]"); - - A.addOption("receivetimeout", "", OptVal(15000), dt_long, ot_mandatory, - "receive timeout in 'us' [15000]"); - - A.addOption("numbermasters", "", OptVal(5), dt_int, ot_mandatory, - "max number of master bus participant [5]"); - - A.addOption("pollinterval", "", OptVal(5), dt_int, ot_mandatory, - "polling interval in 's' [5]\n"); - - A.addOption("configpath", "c", OptVal("/etc/ebusd"), dt_string, ot_mandatory, - "path to ebus configuration files [/etc/ebusd]"); - - A.addOption("checkconfig", "", OptVal(false), dt_bool, ot_none, - "check of configuration files\n"); - - A.addOption("port", "p", OptVal(8888), dt_int, ot_mandatory, - "\tlisten port [8888]"); - - A.addOption("localhost", "", OptVal(false), dt_bool, ot_none, - "listen localhost only\n"); - - A.addOption("logfile", "l", OptVal("/var/log/ebusd.log"), dt_string, ot_mandatory, - "\tlog file name [/var/log/ebusd.log]"); - - A.addOption("logareas", "", OptVal("all"), dt_string, ot_mandatory, - "\tlog areas - bas|net|bus|upd|all [all]"); - - A.addOption("loglevel", "", OptVal("trace"), dt_string, ot_mandatory, - "\tlog level - error|event|trace|debug [event]"); - - A.addOption("lograwdata", "", OptVal(false), dt_bool, ot_none, - "log raw data (bytes)\n"); - - A.addOption("dump", "D", OptVal(false), dt_bool, ot_none, - "\tenable dump"); - - A.addOption("dumpfile", "", OptVal("/tmp/ebus_dump.bin"), dt_string, ot_mandatory, - "\tdump file name [/tmp/ebus_dump.bin]"); - - A.addOption("dumpsize", "", OptVal(100), dt_long, ot_mandatory, - "\tmax size for dump file in 'kB' [100]\n"); -} - -void shutdown() -{ - // stop threads - if (baseloop != NULL) { - delete baseloop; - baseloop = NULL; - } - - // reset all signal handlers to default - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - - // delete daemon pid file - if (D.status() == true) - D.stop(); - - // stop logger - L.log(bas, event, "ebusd stopped"); - L.stop(); - L.join(); - - exit(EXIT_SUCCESS); -} - -void signal_handler(int sig) -{ - switch (sig) { - case SIGHUP: - L.log(bas, event, "SIGHUP received"); - break; - case SIGINT: - L.log(bas, event, "SIGINT received"); - shutdown(); - break; - case SIGTERM: - L.log(bas, event, "SIGTERM received"); - shutdown(); - break; - default: - L.log(bas, event, "undefined signal %s", strsignal(sig)); - break; - } -} - -/** - * Read the configuration files from the specified path. - * @param path the path from which to read the files. - * @param extension the filename extension of the files to read. - * @param logFunc the function to call for logging, or @a NULL to be silent. - * @param templates the available @a DataFieldTemplates. - * @param messages the @a MessageMap to load the messages into. - * @param verbose whether to verbosely log problems. - * @return the result code. - */ -static result_t readConfigFiles(const string path, const string extension, DataFieldTemplates* templates, MessageMap* messages, bool verbose) -{ - DIR* dir = opendir(path.c_str()); - - if (dir == NULL) - return RESULT_ERR_NOTFOUND; - - dirent* d = readdir(dir); - - while (d != NULL) { - if (d->d_type == DT_DIR) { - string fn = d->d_name; - - if (fn != "." && fn != "..") { - const string p = path + "/" + d->d_name; - result_t result = readConfigFiles(p, extension, templates, messages, verbose); - if (result != RESULT_OK) - return result; - } - } - else if (d->d_type == DT_REG || d->d_type == DT_LNK) { - string fn = d->d_name; - - if (fn.find(extension, (fn.length() - extension.length())) != string::npos - && fn != "_templates" + extension) { - const string p = path + "/" + d->d_name; - result_t result = messages->readFromFile(p, templates, verbose); - if (result != RESULT_OK) - return result; - } - } - - d = readdir(dir); - } - closedir(dir); - - return RESULT_OK; -}; - -/** - * Load the message definitions from the configuration files. - * @param templates the @a DataFieldTemplates to load the templates into. - * @param messages the @a MessageMap to load the messages into. - * @param verbose whether to verbosely log problems. - * @return the result code. - */ -result_t loadConfigFiles(DataFieldTemplates* templates, MessageMap* messages, bool verbose=false) { - string path = A.getOptVal("configpath"); - L.log(bas, trace, "path to ebus configuration files: %s", path.c_str()); - messages->clear(); - templates->clear(); - result_t result = templates->readFromFile(path+"/_templates.csv", NULL, verbose); - if (result == RESULT_OK) - L.log(bas, trace, "read templates"); - else - L.log(bas, error, "error reading templates: %s", getResultCode(result)); - - result = readConfigFiles(path, ".csv", templates, messages, verbose); - if (result == RESULT_OK) - L.log(bas, trace, "read config files"); - else - L.log(bas, error, "error reading config files: %s", getResultCode(result)); - - L.log(bas, event, "message DB: %d ", messages->size()); - L.log(bas, event, "updates DB: %d ", messages->size(true)); - L.log(bas, event, "polling DB: %d ", messages->sizePoll()); - - return result; -} - - -int main(int argc, char* argv[]) -{ - // define arguments and application variables - define_args(); - - // parse arguments - if (A.parseArgs(argc, argv) == false) - return EXIT_SUCCESS; - - if (A.getOptVal("checkconfig") == true) { - L += new LogConsole(calcAreaMask(A.getOptVal("logareas")), - calcLevel(A.getOptVal("loglevel")), - "logconsole"); - - L.log(bas, event, "ebusd started"); - - DataFieldTemplates templates; - MessageMap messages; - - loadConfigFiles(&templates, &messages, true); - - messages.clear(); - templates.clear(); - - shutdown(); - - return 0; - } - - if (A.getOptVal("foreground") == true) { - L += new LogConsole(calcAreaMask(A.getOptVal("logareas")), - calcLevel(A.getOptVal("loglevel")), - "logconsole"); - } - else { - // make me daemon - D.run("/var/run/ebusd.pid"); - L += new LogFile(calcAreaMask(A.getOptVal("logareas")), - calcLevel(A.getOptVal("loglevel")), - "logfile", A.getOptVal("logfile")); - } - - // trap signals that we expect to receive - signal(SIGHUP, signal_handler); - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - - // start logger - L.start("logger"); - // wait for logger be ready - usleep(100000); - L.log(bas, event, "ebusd started"); - - // create baseloop - baseloop = new BaseLoop(); - baseloop->start(); - - // shutdown - shutdown(); -} -