removed unused files
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -1,645 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 <iomanip>
|
||||
|
||||
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<bool>("checkconfig") == true) {
|
||||
m_port = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ownAddress = A.getOptVal<int>("address") & 0xff;
|
||||
const bool answer = A.getOptVal<bool>("answer");
|
||||
|
||||
const bool logRaw = A.getOptVal<bool>("lograwdata");
|
||||
|
||||
const bool dumpRaw = A.getOptVal<bool>("dump");
|
||||
const char* dumpRawFile = A.getOptVal<const char*>("dumpfile");
|
||||
const long dumpRawMaxSize = A.getOptVal<long>("dumpsize");
|
||||
|
||||
const unsigned int busLostRetries = A.getOptVal<unsigned int>("acquireretries");
|
||||
const unsigned int failedSendRetries = A.getOptVal<unsigned int>("sendretries");
|
||||
const unsigned int busAcquireWaitTime = A.getOptVal<unsigned int>("acquiretimeout");
|
||||
const unsigned int slaveRecvTimeout = A.getOptVal<unsigned int>("receivetimeout");
|
||||
const unsigned int lockCount = A.getOptVal<unsigned int>("numbermasters");
|
||||
int pollInterval = A.getOptVal<unsigned int>("pollinterval");
|
||||
if (pollInterval <= 0) {
|
||||
m_pollActive = false;
|
||||
pollInterval = 0;
|
||||
}
|
||||
else
|
||||
m_pollActive = true;
|
||||
|
||||
// create Port
|
||||
m_port = new Port(A.getOptVal<const char*>("device"), A.getOptVal<bool>("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<bool>("localhost"), A.getOptVal<int>("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<string> 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<unsigned>(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<Message*> 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<Message*>::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<Message*> messages;
|
||||
messages = m_messages->findAll("", "", -1, false, true, true, true);
|
||||
|
||||
for (deque<Message*>::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();
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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<NetMessage*> 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_
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) Roland Jax 2012-2014 <ebusd@liwest.at>
|
||||
*
|
||||
* 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 <config.h>
|
||||
#endif
|
||||
|
||||
#include "logger.h"
|
||||
#include "daemon.h"
|
||||
#include "appl.h"
|
||||
#include "baseloop.h"
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
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<const char*>("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<bool>("checkconfig") == true) {
|
||||
L += new LogConsole(calcAreaMask(A.getOptVal<const char*>("logareas")),
|
||||
calcLevel(A.getOptVal<const char*>("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<bool>("foreground") == true) {
|
||||
L += new LogConsole(calcAreaMask(A.getOptVal<const char*>("logareas")),
|
||||
calcLevel(A.getOptVal<const char*>("loglevel")),
|
||||
"logconsole");
|
||||
}
|
||||
else {
|
||||
// make me daemon
|
||||
D.run("/var/run/ebusd.pid");
|
||||
L += new LogFile(calcAreaMask(A.getOptVal<const char*>("logareas")),
|
||||
calcLevel(A.getOptVal<const char*>("loglevel")),
|
||||
"logfile", A.getOptVal<const char*>("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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user