Merge branch 'master' of git://github.com/yuhu-/ebusd

Conflicts:
	src/lib/ebus/data.cpp
	src/lib/ebus/data.h
	src/lib/ebus/test/test_data.cpp
This commit is contained in:
john30
2014-11-20 09:30:27 +01:00
59 changed files with 1906 additions and 1594 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
SUBDIRS = src/lib/ebus src/lib/ebus/test src/lib/utils src/ebusd src/ebusctl SUBDIRS = src/lib/utils src/lib/ebus src/lib/ebus/test src/ebusd src/ebusctl
distclean-local: distclean-local:
-rm -rf autom4te.cache -rm -rf autom4te.cache
+21 -30
View File
@@ -13,6 +13,7 @@ Features
* collect data of cycle messages * collect data of cycle messages
* poll messages and collect received data * poll messages and collect received data
* write raw data into dump files (for debugging purpose) * write raw data into dump files (for debugging purpose)
* scan ebus to identifies bus participants
* available daemon commands: * available daemon commands:
- get fetch data from ebus participant - get fetch data from ebus participant
@@ -20,6 +21,10 @@ Features
- cyc fetch data from collected cycle messages - cyc fetch data from collected cycle messages
- hex send given hex value to ebus (ZZPBSBNNDx) - hex send given hex value to ebus (ZZPBSBNNDx)
- scan scan kown slave addresses (collected)
- scan full scan all possible slave addresses
- scan result show scanning results
- log areas change log areas - log areas change log areas
- log level change log level - log level change log level
@@ -29,15 +34,27 @@ Features
- reload reload ebus configuration - reload reload ebus configuration
- stop stop daemon - stop stop daemon
- quit close connection - quit close connection
- help print help page - help print help page
Dependency vendor specific configuration files for ebusd
---------- ---------------------------------------------
* glibc
See https://github.com/yuhu-/ebus-configuration
ebusctl - client program for ebusd
----------------------------------
server commands:
* connect to ebusd (socket) and execute server commands (commands see above)
local commands:
* 'feed' ebusd with raw data from dump files (or telnet) to ebusd
Build Build
@@ -48,32 +65,6 @@ $ make
$ make install $ make install
Daemon Configuration
--------------------
See ./ebusd -h
Vendor specific configuration files
-----------------------------------
See https://github.com/yuhu-/ebus-configuration
Tools
-----
ebusctl - client program for ebusd.
local commands:
* 'feed' ebusd with raw data from dump files (or telnet) to ebusd
* 'scan' ebus and identifies the participants
remote commands:
* connect to ebusd (socket) and execute server commands (see above)
See ./ebusctl -h
For usage and further information take a look on help page. For usage and further information take a look on help page.
+15 -2
View File
@@ -3,13 +3,26 @@ AC_INIT([ebusd], [0.5.0], [ebusd@liwest.at], [ebusd], [https://github.com/yuhu-/
AC_PROG_CXX AC_PROG_CXX
AC_CHECK_HEADERS([arpa/inet.h \
dirent.h \
fcntl.h \
netdb.h \
poll.h \
pthread.h \
sys/ioctl.h \
termios.h])
AC_CHECK_LIB([pthread], [pthread_setname_np],
AC_DEFINE([HAVE_PTHREAD_SETNAME_NP], [1], ["Define to 1 if pthread has pthread_setname_np"]),
AC_MSG_RESULT([Could not find pthread_setname_np in pthread]))
AC_CONFIG_AUX_DIR([build]) AC_CONFIG_AUX_DIR([build])
AC_CONFIG_SRCDIR([src/ebusd/main.cpp]) AC_CONFIG_SRCDIR([src/ebusd/ebusd.cpp])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
src/lib/utils/Makefile
src/lib/ebus/Makefile src/lib/ebus/Makefile
src/lib/ebus/test/Makefile src/lib/ebus/test/Makefile
src/lib/utils/Makefile
src/ebusd/Makefile src/ebusd/Makefile
src/ebusctl/Makefile]) src/ebusctl/Makefile])
+52 -219
View File
@@ -17,179 +17,63 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "appl.h"
#include "port.h" #include "port.h"
#include "decode.h" #include "decode.h"
#include "appl.h"
#include "tcpsocket.h" #include "tcpsocket.h"
#include <iostream> #include <iostream>
#include <sstream>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <cstdlib>
#include <utility>
#include <unistd.h> #include <unistd.h>
using namespace libebus; Appl& A = Appl::Instance(true);
Appl& A = Appl::Instance();
void define_args() void define_args()
{ {
A.addArgs("COMMAND {ARGS...}\n\n" A.setVersion("ebusctl is part of """PACKAGE_STRING"");
" local commands:\n"
" 'scan' scans the bus and identifies the participants\n\n"
" 'feed' sends a dump file to a local virtual serial device\n"
" (hint: socat -d -d pty,raw,echo=0 pty,raw,echo=0)\n\n"
" remote commands:\n"
" send 'help' to server", 1);
A.addItem("p_device", Appl::Param("/dev/ttyUSB60"), "d", "device", A.addText(" 'help' show server commands\n\n"
"virtual serial device (/dev/ttyUSB60)", " 'feed' sends a dump file to a local serial device (pts)\n"
Appl::type_string, Appl::opt_mandatory); " (hint: socat -d -d pty,raw,echo=0 pty,raw,echo=0)\n\n"
"Options:\n");
A.addItem("p_file", Appl::Param(""), "f", "file", A.addOption("device", "d", OptVal("/dev/ttyUSB60"), dt_string, ot_mandatory,
"dump file with raw data", "virtual serial device (/dev/ttyUSB60)");
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_time", Appl::Param(10000), "t", "time", A.addOption("file", "f", OptVal("/tmp/ebus_dump.bin"),dt_string, ot_mandatory,
"delay between 2 bytes in 'us' (10000)\n", "dump file name (/tmp/ebus_dump.bin)");
Appl::type_long, Appl::opt_mandatory);
A.addItem("p_server", Appl::Param("localhost"), "s", "server", A.addOption("time", "t", OptVal(10000), dt_long, ot_mandatory,
"name or ip (localhost)", "delay between 2 bytes in 'us' (10000)\n");
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_port", Appl::Param(8888), "p", "port", A.addOption("server", "s", OptVal("localhost"), dt_string, ot_mandatory,
"port (8888)\n", "name or ip (localhost)");
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_help", Appl::Param(false), "h", "help", A.addOption("port", "p", OptVal(8888), dt_int, ot_mandatory,
"print this message", "port (8888)\n");
Appl::type_bool, Appl::opt_none);
} }
template<typename T, size_t N>T * end(T (&ra)[N]) { return ra + N; }
const char *sinit[] = {"02", "04", "05", "06", "08", "09", "0A", "0B", "0C",
"0E", "12", "14", "15", "16", "18", "19", "1A", "1B",
"1C", "1D", "1E", "20", "21", "22", "23", "24", "25",
"26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E",
"2F", "32", "34", "35", "36", "38", "39", "3A", "3B",
"3C", "3D", "3E", "40", "41", "42", "43", "44", "45",
"46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E",
"4F", "50", "51", "52", "53", "54", "55", "56", "57",
"58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60",
"61", "62", "63", "64", "65", "66", "67", "68", "69",
"6A", "6B", "6C", "6D", "6E", "6F", "72", "74", "75",
"76", "78", "79", "7A", "7B", "7C", "7D", "7E", "80",
"81", "82", "83", "84", "85", "86", "87", "88", "89",
"8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92",
"93", "94", "95", "96", "97", "98", "99", "9A", "9B",
"9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4",
"A5", "A6", "A7", "A8", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8",
"B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1",
"C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA",
"CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3",
"D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC",
"DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5",
"E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE",
"EF", "F2", "F4", "F5", "F6", "F8", "F9", "FA", "FB",
"FC", "FD"};
static std::vector<std::string> s(sinit, end(sinit));
static std::map<std::string, std::string> manufacturer;
static void addManufacturer()
{
manufacturer.insert(std::make_pair("06", "Karl Dungs GmbH"));
manufacturer.insert(std::make_pair("0f", "FH Braunschweig/Wolfenbüttel"));
manufacturer.insert(std::make_pair("10", "TEM AG für Elektronik Intertem Vertriebs AG"));
manufacturer.insert(std::make_pair("11", "Lamberti Elektronik"));
manufacturer.insert(std::make_pair("14", "CEB Compagnie Européenne de Brûleurs S.A."));
manufacturer.insert(std::make_pair("15", "Landis & Staefa"));
manufacturer.insert(std::make_pair("16", "FERRO Wärmetechnik GmbH & Co.KG"));
manufacturer.insert(std::make_pair("17", "MONDIAL electronic Ges.mbH"));
manufacturer.insert(std::make_pair("18", "Wikon Kommunikationstechnik GmbH"));
manufacturer.insert(std::make_pair("19", "Wolf GmbH"));
manufacturer.insert(std::make_pair("20", "RAWE Electronic GmbH"));
manufacturer.insert(std::make_pair("30", "Satronic AG"));
manufacturer.insert(std::make_pair("40", "ENCON Electronics"));
manufacturer.insert(std::make_pair("50", "G. Kromschröder AG"));
manufacturer.insert(std::make_pair("60", "Eberle Controls GmbH"));
manufacturer.insert(std::make_pair("65", "EBV Elektronikbau"));
manufacturer.insert(std::make_pair("75", "Grässlin GmbH & Co.KG"));
manufacturer.insert(std::make_pair("85", "Motoren und Ventilatoren Landshut GmbH"));
manufacturer.insert(std::make_pair("95", "SIG Berger Lahr GmbH & Co KG"));
manufacturer.insert(std::make_pair("c0", "Toby AG"));
manufacturer.insert(std::make_pair("c5", "Max Weishaupt GmbH"));
manufacturer.insert(std::make_pair("a5", "Theben Zeitschaltautomatik"));
manufacturer.insert(std::make_pair("a7", "Thermowatt s.p.a."));
manufacturer.insert(std::make_pair("b5", "Joh. Vaillant GmbH & Co."));
}
void scanVaillant(TCPSocket* socket, const std::string address)
{
Decode* help = NULL;
std::ostringstream sstr;
for (int i = 24; i < 28; i++) {
// build message
std::string message("hex ms ");
message += address;
message += "b50901";
std::stringstream ss;
ss << i;
message += ss.str();
socket->send(message.c_str(), message.size());
char data[256];
size_t datalen;
datalen = socket->recv(data, sizeof(data)-1);
data[datalen] = '\0';
std::string item(data);
help = new DecodeSTR(item.substr(18,18));
sstr << help->decode();
delete help;
}
std::cout << " s/n: '" << sstr.str().substr(1,28) << "' item: '" << sstr.str().substr(7,10) << "'";
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
// define Arguments and Application variables // define arguments and application variables
define_args(); define_args();
// parse Arguments // parse arguments
if (A.parseArgs(argc, argv) == false) { A.parseArgs(argc, argv);
A.printArgs();
exit(EXIT_FAILURE);
}
// print Help
if (A.getParam<bool>("p_help") == true) {
A.printArgs();
exit(EXIT_SUCCESS);
}
if (strcasecmp(A.getArg(0).c_str(), "feed") == 0) { if (strcasecmp(A.getArg(0).c_str(), "feed") == 0) {
std::string dev(A.getParam<const char*>("p_device")); std::string dev(A.getOptVal<const char*>("device"));
Port port(dev, true); Port port(dev, true);
port.open(); port.open();
if(port.isOpen() == true) { if(port.isOpen() == true) {
std::cout << "openPort successful." << std::endl; std::cout << "openPort successful." << std::endl;
std::fstream file(A.getParam<const char*>("p_file"), std::ios::in | std::ios::binary); std::fstream file(A.getOptVal<const char*>("file"), std::ios::in | std::ios::binary);
if(file.is_open() == true) { if(file.is_open() == true) {
@@ -199,103 +83,52 @@ int main(int argc, char* argv[])
<< static_cast<unsigned>(byte) << std::endl; << static_cast<unsigned>(byte) << std::endl;
port.send(&byte, 1); port.send(&byte, 1);
usleep(A.getParam<long>("p_time")); usleep(A.getOptVal<long>("time"));
} }
file.close(); file.close();
} else {
std::cout << "error opening file " << A.getParam<const char*>("p_file") << std::endl;
} }
else
std::cout << "error opening file " << A.getOptVal<const char*>("file") << std::endl;
port.close(); port.close();
if(port.isOpen() == false) if(port.isOpen() == false)
std::cout << "closePort successful." << std::endl; std::cout << "closePort successful." << std::endl;
} else { } else
std::cout << "error opening device " << A.getParam<const char*>("p_device") << std::endl; std::cout << "error opening device " << A.getOptVal<const char*>("device") << std::endl;
} }
else {
} else {
TCPClient* client = new TCPClient(); TCPClient* client = new TCPClient();
TCPSocket* socket = client->connect(A.getParam<const char*>("p_server"), A.getParam<int>("p_port")); TCPSocket* socket = client->connect(A.getOptVal<const char*>("server"), A.getOptVal<int>("port"));
if (socket != NULL) { if (socket != NULL) {
// build message
if (strcasecmp(A.getArg(0).c_str(), "scan") == 0) { std::string message(A.getArg(0));
addManufacturer(); for (int i = 1; i < A.numArgs(); i++) {
message += " ";
// send command to all slaves message += A.getArg(i);
for (size_t i = 0; i < s.size(); i++) {
// build message
std::string message("hex ms ");
message += s[i];
message += "070400";
socket->send(message.c_str(), message.size());
char data[1024];
size_t datalen;
datalen = socket->recv(data, sizeof(data)-1);
data[datalen] = '\0';
// decode answer
if (strncmp(&data[0], "-", 1) != 0) {
std::string item(data);
std::ostringstream ident;
Decode* help = NULL;
help = new DecodeSTR(item.substr(18,10));
ident << help->decode();
delete help;
std::cout << s[i] << ": '" << manufacturer.find(item.substr(16,2))->second
<< "' ident: '" << std::setw(5) << std::setfill(' ') << ident.str()
<< "' sw: '" << item.substr(28,2)
<< "." << item.substr(30,2)
<< "' hw: '" << item.substr(32,2)
<< "." << item.substr(34,2)
<< "'";
if (item.substr(16,2) == "b5")
scanVaillant(socket, s[i]);
std::cout << std::endl;
}
sleep(2);
}
} else {
// build message
std::string message(A.getArg(0));
for (size_t i = 1; i < A.numArg(); i++) {
message += " ";
message += A.getArg(i);
}
socket->send(message.c_str(), message.size());
char data[1024];
size_t datalen;
datalen = socket->recv(data, sizeof(data)-1);
data[datalen] = '\0';
std::cout << data;
} }
socket->send(message.c_str(), message.size());
char data[1024];
size_t datalen;
datalen = socket->recv(data, sizeof(data)-1);
data[datalen] = '\0';
std::cout << data;
delete socket; delete socket;
} else {
std::cout << "error connecting to " << A.getParam<const char*>("p_server")
<< ":" << A.getParam<int>("p_port") << std::endl;
} }
else
std::cout << "error connecting to " << A.getOptVal<const char*>("server")
<< ":" << A.getOptVal<int>("port") << std::endl;
delete client; delete client;
} }
return 0; return 0;
} }
+5 -6
View File
@@ -6,16 +6,15 @@ AM_CXXFLAGS = -fpic \
bin_PROGRAMS = ebusd bin_PROGRAMS = ebusd
ebusd_SOURCES = message.h \ ebusd_SOURCES = dump.cpp \
connection.cpp \ dump.h \
connection.h \ busloop.cpp \
busloop.h \
network.cpp \ network.cpp \
network.h \ network.h \
ebusloop.cpp \
ebusloop.h \
baseloop.cpp \ baseloop.cpp \
baseloop.h \ baseloop.h \
main.cpp ebusd.cpp
ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \ ebusd_LDADD = $(top_srcdir)/src/lib/utils/libutils.a \
$(top_srcdir)/src/lib/ebus/libebus.a \ $(top_srcdir)/src/lib/ebus/libebus.a \
+112 -86
View File
@@ -22,42 +22,41 @@
#include "logger.h" #include "logger.h"
#include "appl.h" #include "appl.h"
extern LogInstance& L; extern Logger& L;
extern Appl& A; extern Appl& A;
BaseLoop::BaseLoop() BaseLoop::BaseLoop()
{ {
// create Commands DB // create commands DB
m_commands = ConfigCommands(A.getParam<const char*>("p_ebusconfdir"), CSV).getCommands(); m_commands = ConfigCommands(A.getOptVal<const char*>("ebusconfdir"), CSV).getCommands();
L.log(bas, trace, "ebus configuration dir: %s", A.getParam<const char*>("p_ebusconfdir")); L.log(bas, trace, "ebus configuration dir: %s", A.getOptVal<const char*>("ebusconfdir"));
L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB()); L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB());
L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB());
L.log(bas, event, " polling DB: %d ", m_commands->sizePolDB()); L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());
// create EBusLoop // create busloop
m_ebusloop = new EBusLoop(m_commands); m_busloop = new BusLoop(m_commands);
m_ebusloop->start("ebusloop"); m_busloop->start("busloop");
// create Network // create network
m_network = new Network(A.getParam<bool>("p_localhost")); m_network = new Network(A.getOptVal<bool>("localhost"), &m_netQueue);
m_network->addQueue(&m_queue);
m_network->start("network"); m_network->start("network");
} }
BaseLoop::~BaseLoop() BaseLoop::~BaseLoop()
{ {
// free Network // free network
if (m_network != NULL) if (m_network != NULL)
delete m_network; delete m_network;
// free EBusLoop // free busloop
if (m_ebusloop != NULL) { if (m_busloop != NULL) {
m_ebusloop->stop(); m_busloop->stop();
m_ebusloop->join(); m_busloop->join();
delete m_ebusloop; delete m_busloop;
} }
// free Commands DB // free commands DB
if (m_commands != NULL) if (m_commands != NULL)
delete m_commands; delete m_commands;
} }
@@ -68,7 +67,7 @@ void BaseLoop::start()
std::string result; std::string result;
// recv new message from client // recv new message from client
Message* message = m_queue.remove(); NetMessage* message = m_netQueue.remove();
std::string data = message->getData(); std::string data = message->getData();
data.erase(std::remove(data.begin(), data.end(), '\r'), data.end()); data.erase(std::remove(data.begin(), data.end(), '\r'), data.end());
@@ -86,10 +85,8 @@ void BaseLoop::start()
// send result to client // send result to client
result += '\n'; result += '\n';
Connection* connection = static_cast<Connection*>(message->getSource()); message->setResult(result);
connection->addResult(Message(result)); message->sendSignal();
delete message;
// stop daemon // stop daemon
if (strcasecmp(data.c_str(), "STOP") == 0) if (strcasecmp(data.c_str(), "STOP") == 0)
@@ -132,7 +129,7 @@ std::string BaseLoop::decodeMessage(const std::string& data)
// polling data // polling data
if (strcasecmp(m_commands->getCmdType(index).c_str(), "P") == 0) { if (strcasecmp(m_commands->getCmdType(index).c_str(), "P") == 0) {
// get polldata // get polldata
polldata = m_commands->getPolData(index); polldata = m_commands->getPollData(index);
if (polldata != "") { if (polldata != "") {
// decode data // decode data
Command* command = new Command(index, (*m_commands)[index], polldata); Command* command = new Command(index, (*m_commands)[index], polldata);
@@ -148,30 +145,30 @@ std::string BaseLoop::decodeMessage(const std::string& data)
break; break;
} }
std::string ebusCommand(A.getParam<const char*>("p_address")); std::string busCommand(A.getOptVal<const char*>("address"));
ebusCommand += m_commands->getEbusCommand(index); busCommand += m_commands->getBusCommand(index);
std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); std::transform(busCommand.begin(), busCommand.end(), busCommand.begin(), tolower);
BusCommand* busCommand = new BusCommand(ebusCommand, false); BusMessage* message = new BusMessage(busCommand, false, false);
L.log(bas, trace, " msg: %s", ebusCommand.c_str()); L.log(bas, trace, " msg: %s", busCommand.c_str());
// send busCommand // send message
m_ebusloop->addBusCommand(busCommand); m_busloop->addMessage(message);
busCommand->waitSignal(); message->waitSignal();
if (!busCommand->isErrorResult()) { if (!message->isErrorResult()) {
// decode data // decode data
Command* command = new Command(index, (*m_commands)[index], busCommand->getMessageStr()); // TODO use getCommand()+getResult() Command* command = new Command(index, (*m_commands)[index], message->getMessageStr()); // TODO use getCommand()+getResult()
// return result // return result
result << command->calcResult(cmd); result << command->calcResult(cmd);
delete command; delete command;
} else { } else {
L.log(bas, error, " %s", busCommand->getResultCodeCStr()); L.log(bas, error, " %s", message->getResultCodeCStr());
result << busCommand->getResultCodeCStr(); result << message->getResultCodeCStr();
} }
delete busCommand; delete message;
} else { } else {
result << "ebus command not found"; result << "ebus command not found";
@@ -189,43 +186,43 @@ std::string BaseLoop::decodeMessage(const std::string& data)
if (index >= 0) { if (index >= 0) {
std::string ebusCommand(A.getParam<const char*>("p_address")); std::string busCommand(A.getOptVal<const char*>("address"));
ebusCommand += m_commands->getEbusCommand(index); busCommand += m_commands->getBusCommand(index);
// encode data // encode data
Command* command = new Command(index, (*m_commands)[index], cmd[3]); Command* command = new Command(index, (*m_commands)[index], cmd[3]);
std::string value = command->calcData(); std::string value = command->calcData();
if (value[0] != '-') { if (value[0] != '-') {
ebusCommand += value; busCommand += value;
} else { } else {
L.log(bas, error, " %s", value.c_str()); L.log(bas, error, " %s", value.c_str());
delete command; delete command;
break; break;
} }
std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); std::transform(busCommand.begin(), busCommand.end(), busCommand.begin(), tolower);
BusCommand* busCommand = new BusCommand(ebusCommand, false); BusMessage* message = new BusMessage(busCommand, false, false);
L.log(bas, event, " msg: %s", ebusCommand.c_str()); L.log(bas, event, " msg: %s", busCommand.c_str());
// send busCommand // send message
m_ebusloop->addBusCommand(busCommand); m_busloop->addMessage(message);
busCommand->waitSignal(); message->waitSignal();
if (!busCommand->isErrorResult()) { if (!message->isErrorResult()) {
// decode result // decode result
if (busCommand->getType()==broadcast) if (message->getType()==broadcast)
result << "done"; result << "done";
else if (busCommand->getMessageStr().substr(busCommand->getMessageStr().length()-8) == "00000000") // TODO use getResult() else if (message->getMessageStr().substr(message->getMessageStr().length()-8) == "00000000") // TODO use getResult()
result << "done"; result << "done";
else else
result << "error"; result << "error";
} else { } else {
L.log(bas, error, " %s", busCommand->getResultCodeCStr()); L.log(bas, error, " %s", message->getResultCodeCStr());
result << busCommand->getResultCodeCStr(); result << message->getResultCodeCStr();
} }
delete busCommand; delete message;
delete command; delete command;
} else { } else {
@@ -269,37 +266,63 @@ std::string BaseLoop::decodeMessage(const std::string& data)
} }
{ {
std::string ebusCommand(A.getParam<const char*>("p_address")); std::string busCommand(A.getOptVal<const char*>("address"));
cmd[1].erase(std::remove_if(cmd[1].begin(), cmd[1].end(), isspace), cmd[1].end()); cmd[1].erase(std::remove_if(cmd[1].begin(), cmd[1].end(), isspace), cmd[1].end());
ebusCommand += cmd[1]; busCommand += cmd[1];
std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); std::transform(busCommand.begin(), busCommand.end(), busCommand.begin(), tolower);
BusCommand* busCommand = new BusCommand(ebusCommand, false); BusMessage* message = new BusMessage(busCommand, false, false);
L.log(bas, trace, " msg: %s", ebusCommand.c_str()); L.log(bas, trace, " msg: %s", busCommand.c_str());
// send busCommand // send message
m_ebusloop->addBusCommand(busCommand); m_busloop->addMessage(message);
busCommand->waitSignal(); message->waitSignal();
if (busCommand->isErrorResult()) { if (message->isErrorResult()) {
L.log(bas, error, " %s", busCommand->getResultCodeCStr()); L.log(bas, error, " %s", message->getResultCodeCStr());
result << busCommand->getResultCodeCStr(); result << message->getResultCodeCStr();
} else { } else {
result << busCommand->getMessageStr(); // TODO use getCommand()+getResult() result << message->getMessageStr(); // TODO use getCommand()+getResult()
} }
delete busCommand; delete message;
} }
break; break;
case scan:
if (cmd.size() == 1) {
m_busloop->scan();
result << "done";
break;
}
if (strcasecmp(cmd[1].c_str(), "FULL") == 0) {
m_busloop->scan(true);
result << "done";
break;
}
if (strcasecmp(cmd[1].c_str(), "RESULT") == 0) {
// TODO format scan results
for (size_t i = 0; i < m_commands->sizeScanDB(); i++)
result << m_commands->getScanData(i) << std::endl;
break;
}
result << "usage: 'scan'" << std::endl
<< " 'scan full'" << std::endl
<< " 'scan result'";
break;
case log: case log:
if (cmd.size () != 3 ) { if (cmd.size() != 3 ) {
result << "usage: 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl result << "usage: 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl
<< " 'log level level' (level: error|event|trace|debug)"; << " 'log level level' (level: error|event|trace|debug)";
break; break;
} }
// ToDo: check for possible areas and level // TODO: check for possible areas and level
if (strcasecmp(cmd[1].c_str(), "AREAS") == 0) { if (strcasecmp(cmd[1].c_str(), "AREAS") == 0) {
L.getSink(0)->setAreas(calcAreas(cmd[2])); L.getSink(0)->setAreas(calcAreas(cmd[2]));
result << "done"; result << "done";
@@ -323,7 +346,7 @@ std::string BaseLoop::decodeMessage(const std::string& data)
break; break;
} }
m_ebusloop->raw(); m_busloop->raw();
result << "done"; result << "done";
break; break;
@@ -333,7 +356,7 @@ std::string BaseLoop::decodeMessage(const std::string& data)
break; break;
} }
m_ebusloop->dump(); m_busloop->dump();
result << "done"; result << "done";
break; break;
@@ -344,16 +367,16 @@ std::string BaseLoop::decodeMessage(const std::string& data)
} }
{ {
// create Commands DB // create commands DB
Commands* commands = ConfigCommands(A.getParam<const char*>("p_ebusconfdir"), CSV).getCommands(); Commands* commands = ConfigCommands(A.getOptVal<const char*>("ebusconfdir"), CSV).getCommands();
L.log(bas, trace, "ebus configuration dir: %s", A.getParam<const char*>("p_ebusconfdir")); L.log(bas, trace, "ebus configuration dir: %s", A.getOptVal<const char*>("ebusconfdir"));
L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB()); L.log(bas, event, "commands DB: %d ", m_commands->sizeCmdDB());
L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB()); L.log(bas, event, " cycle DB: %d ", m_commands->sizeCycDB());
L.log(bas, event, " polling DB: %d ", m_commands->sizePolDB()); L.log(bas, event, " polling DB: %d ", m_commands->sizePollDB());
delete m_commands; delete m_commands;
m_commands = commands; m_commands = commands;
m_ebusloop->newCommands(m_commands); m_busloop->reload(m_commands);
result << "done"; result << "done";
break; break;
@@ -361,18 +384,21 @@ std::string BaseLoop::decodeMessage(const std::string& data)
case help: case help:
result << "commands:" << std::endl result << "commands:" << std::endl
<< " get - fetch ebus data 'get class cmd (sub)'" << std::endl << " get - fetch ebus data 'get class cmd (sub)'" << std::endl
<< " set - set ebus values 'set class cmd value'" << std::endl << " set - set ebus values 'set class cmd value'" << std::endl
<< " cyc - fetch cycle data 'cyc class cmd (sub)'" << std::endl << " cyc - fetch cycle data 'cyc class cmd (sub)'" << std::endl
<< " hex - send given hex value 'hex type value' (value: ZZPBSBNNDx)" << std::endl << std::endl << " hex - send given hex value 'hex type value' (value: ZZPBSBNNDx)" << std::endl << std::endl
<< " log - change log areas 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl << " scan - scan ebus kown addresses 'scan'" << std::endl
<< " - change log level 'log level level' (level: error|event|trace|debug)" << std::endl << std::endl << " - scan ebus all addresses 'scan full'" << std::endl
<< " raw - toggle log raw data" << std::endl << " - show results 'scan result'" << std::endl << std::endl
<< " dump - toggle dump state" << std::endl << std::endl << " log - change log areas 'log areas area,area,..' (areas: bas|net|bus|cyc|all)" << std::endl
<< " reload - reload ebus configuration" << std::endl << std::endl << " - change log level 'log level level' (level: error|event|trace|debug)" << std::endl << std::endl
<< " stop - stop daemon" << std::endl << " raw - toggle log raw data 'raw'" << std::endl
<< " quit - close connection" << std::endl << std::endl << " dump - toggle dump state 'dump'" << std::endl << std::endl
<< " help - print this page"; << " reload - reload ebus configuration 'reload'" << std::endl << std::endl
<< " stop - stop daemon 'stop'" << std::endl
<< " quit - close connection 'quit'" << std::endl << std::endl
<< " help - print this page 'help'";
break; break;
default: default:
+6 -7
View File
@@ -22,10 +22,7 @@
#include "commands.h" #include "commands.h"
#include "network.h" #include "network.h"
#include "ebusloop.h" #include "busloop.h"
using namespace libebus;
class BaseLoop class BaseLoop
{ {
@@ -36,20 +33,21 @@ public:
void start(); void start();
void addMessage(Message* message) { m_queue.add(message); } void addMessage(NetMessage* message) { m_netQueue.add(message); }
private: private:
Commands* m_commands; Commands* m_commands;
EBusLoop* m_ebusloop; BusLoop* m_busloop;
Network* m_network; Network* m_network;
WQueue<Message*> m_queue; WQueue<NetMessage*> m_netQueue;
enum ClientCommand { enum ClientCommand {
get, // get ebus data get, // get ebus data
set, // set ebus value set, // set ebus value
cyc, // fetch cycle data cyc, // fetch cycle data
hex, // send hex value hex, // send hex value
scan, // scan ebus
log, // logger settings log, // logger settings
raw, // toggle log raw data raw, // toggle log raw data
dump, // toggle dump state dump, // toggle dump state
@@ -64,6 +62,7 @@ private:
if (strcasecmp(item.c_str(), "SET") == 0) return set; if (strcasecmp(item.c_str(), "SET") == 0) return set;
if (strcasecmp(item.c_str(), "CYC") == 0) return cyc; if (strcasecmp(item.c_str(), "CYC") == 0) return cyc;
if (strcasecmp(item.c_str(), "HEX") == 0) return hex; if (strcasecmp(item.c_str(), "HEX") == 0) return hex;
if (strcasecmp(item.c_str(), "SCAN") == 0) return scan;
if (strcasecmp(item.c_str(), "LOG") == 0) return log; if (strcasecmp(item.c_str(), "LOG") == 0) return log;
if (strcasecmp(item.c_str(), "RAW") == 0) return raw; if (strcasecmp(item.c_str(), "RAW") == 0) return raw;
if (strcasecmp(item.c_str(), "DUMP") == 0) return dump; if (strcasecmp(item.c_str(), "DUMP") == 0) return dump;
+217 -83
View File
@@ -17,37 +17,84 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#include "ebusloop.h" #include "busloop.h"
#include "logger.h" #include "logger.h"
#include "appl.h" #include "appl.h"
#include <iomanip>
extern LogInstance& L; extern Logger& L;
extern Appl& A; extern Appl& A;
EBusLoop::EBusLoop(Commands* commands) BusMessage::BusMessage(const std::string command, const bool poll, const bool scan)
: m_commands(commands), m_stop(false), m_lockCounter(0), m_priorRetry(false) : m_poll(poll), m_scan(scan), m_command(command), m_result(), m_resultCode(RESULT_OK)
{ {
m_port = new Port(A.getParam<const char*>("p_device"), A.getParam<bool>("p_nodevicecheck")); unsigned char dstAddress = m_command[1];
if (dstAddress == BROADCAST)
m_type = broadcast;
else if (isMaster(dstAddress) == true)
m_type = masterMaster;
else
m_type = masterSlave;
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
BusMessage::~BusMessage()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
const std::string BusMessage::getMessageStr()
{
std::string result;
if (m_resultCode >= 0) {
if (m_type == masterSlave) {
result = m_command.getDataStr();
result += "00";
result += m_result.getDataStr();
result += "00";
}
else
result = "success";
}
else
result = "error: "+std::string(getResultCodeCStr());
return result;
}
BusLoop::BusLoop(Commands* commands)
: m_commands(commands), m_stop(false), m_lockCounter(0),
m_priorRetry(false), m_scan(false), m_scanFull(false), m_scanIndex(0)
{
m_port = new Port(A.getOptVal<const char*>("device"), A.getOptVal<bool>("nodevicecheck"));
m_port->open(); m_port->open();
if (m_port->isOpen() == false) if (m_port->isOpen() == false)
L.log(bus, error, "can't open %s", A.getParam<const char*>("p_device")); L.log(bus, error, "can't open %s", A.getOptVal<const char*>("device"));
m_dump = new Dump(A.getParam<const char*>("p_dumpfile"), A.getParam<long>("p_dumpsize")); m_dump = new Dump(A.getOptVal<const char*>("dumpfile"), A.getOptVal<long>("dumpsize"));
m_dumpState = A.getParam<bool>("p_dump"); m_dumpState = A.getOptVal<bool>("dump");
m_logRawData = A.getParam<bool>("p_lograwdata"); m_logRawData = A.getOptVal<bool>("lograwdata");
m_pollInterval = A.getParam<int>("p_pollinterval"); m_pollInterval = A.getOptVal<int>("pollinterval");
m_recvTimeout = A.getParam<long>("p_recvtimeout"); m_recvTimeout = A.getOptVal<long>("recvtimeout");
m_sendRetries = A.getParam<int>("p_sendretries"); m_sendRetries = A.getOptVal<int>("sendretries");
m_lockRetries = A.getParam<int>("p_lockretries"); m_lockRetries = A.getOptVal<int>("lockretries");
m_acquireTime = A.getOptVal<long>("acquiretime");
} }
EBusLoop::~EBusLoop() BusLoop::~BusLoop()
{ {
if (m_port->isOpen() == true) if (m_port->isOpen() == true)
m_port->close(); m_port->close();
@@ -56,7 +103,7 @@ EBusLoop::~EBusLoop()
delete m_dump; delete m_dump;
} }
void* EBusLoop::run() void* BusLoop::run()
{ {
int sendRetries = 0; int sendRetries = 0;
int lockRetries = 0; int lockRetries = 0;
@@ -70,15 +117,19 @@ void* EBusLoop::run()
if (m_port->isOpen() == true) { if (m_port->isOpen() == true) {
ssize_t numBytes; ssize_t numBytes;
// add poll command // add poll or scan command
if (m_commands->sizePolDB() > 0) { if (m_commands->sizePollDB() > 0 || m_scan == true) {
// check polling delta // check polling delta
time(&pollEnd); time(&pollEnd);
pollDelta = difftime(pollEnd, pollStart); pollDelta = difftime(pollEnd, pollStart);
// add new polling command to send // add new polling command to send
if (pollDelta >= m_pollInterval) { if (pollDelta >= m_pollInterval) {
addPollCommand(); if (m_scan == true)
addScanMessage();
else
addPollMessage();
time(&pollStart); time(&pollStart);
} }
} }
@@ -95,64 +146,67 @@ void* EBusLoop::run()
collectCycData(numBytes); collectCycData(numBytes);
// send command // send command
if (m_sstr.size() == 0 && m_lockCounter == 0 && m_sendBuffer.size() > 0) { if (m_sstr.size() == 0 && m_lockCounter == 0 && m_busQueue.size() > 0) {
// acquire Bus // acquire Bus
int busResult = acquireBus(); int busResult = acquireBus();
// send bus command // send bus command
if (busResult == RESULT_BUS_ACQUIRED) { if (busResult == RESULT_BUS_ACQUIRED) {
BusCommand* busCommand = sendCommand(); BusMessage* message = sendCommand();
L.log(bus, trace, " %s", busCommand->getMessageStr().c_str()); L.log(bus, trace, " %s", message->getMessageStr().c_str());
if (busCommand->isErrorResult() == true) { if (message->isErrorResult() == true) {
if (sendRetries < m_sendRetries) { if (sendRetries < m_sendRetries) {
sendRetries++; sendRetries++;
L.log(bus, trace, " send retry %d", sendRetries); L.log(bus, trace, " send retry %d", sendRetries);
busCommand->setResult(std::string(), RESULT_OK); message->setResult(std::string(), RESULT_OK);
} }
else { else {
sendRetries = 0;
L.log(bus, event, " send retry failed", sendRetries); L.log(bus, event, " send retry failed", sendRetries);
if (busCommand->isPoll() == true) if (message->isPoll() == true)
delete m_sendBuffer.remove(); delete m_busQueue.remove();
else else
busCommand->sendSignal(); message->sendSignal();
sendRetries = 0;
} }
} }
else { else {
sendRetries = 0; sendRetries = 0;
if (busCommand->isPoll() == true) {
m_commands->storePolData(busCommand->getMessageStr().c_str()); // TODO use getResult() if (message->isPoll() == true) {
delete busCommand; if (message->isScan() == true)
m_commands->storeScanData(message->getMessageStr().c_str());
else
m_commands->storePollData(message->getMessageStr().c_str()); // TODO use getResult()
delete message;
} }
else else
busCommand->sendSignal(); message->sendSignal();
} }
lockRetries = 0; lockRetries = 0;
m_lockCounter = A.getParam<int>("p_lockcounter"); m_lockCounter = A.getOptVal<int>("lockcounter");
} }
else if (busResult == RESULT_ERR_BUS_LOST) { else if (busResult == RESULT_ERR_BUS_LOST) {
L.log(bus, trace, " acquire bus failed"); L.log(bus, trace, " acquire bus failed");
if (lockRetries >= m_lockRetries) { if (lockRetries >= m_lockRetries) {
L.log(bus, event, " lock bus failed");
BusCommand* busCommand = m_sendBuffer.remove();
if (busCommand->isPoll() == true)
delete busCommand;
else
busCommand->sendSignal();
lockRetries = 0; lockRetries = 0;
L.log(bus, event, " lock bus failed");
BusMessage* message = m_busQueue.remove();
if (message->isPoll() == true)
delete message;
else
message->sendSignal();
} }
else { else {
lockRetries++; lockRetries++;
L.log(bus, trace, " lock retry %d", lockRetries); L.log(bus, trace, " lock retry %d", lockRetries);
} }
m_lockCounter = A.getParam<int>("p_lockcounter"); m_lockCounter = A.getOptVal<int>("lockcounter");
} }
} }
@@ -164,7 +218,7 @@ void* EBusLoop::run()
m_port->open(); m_port->open();
if (m_port->isOpen() == false) if (m_port->isOpen() == false)
L.log(bus, error, "can't open %s", A.getParam<const char*>("p_device")); L.log(bus, error, "can't open %s", A.getOptVal<const char*>("device"));
} }
@@ -180,7 +234,7 @@ void* EBusLoop::run()
return NULL; return NULL;
} }
unsigned char EBusLoop::fetchByte() unsigned char BusLoop::fetchByte()
{ {
unsigned char byte; unsigned char byte;
@@ -196,7 +250,7 @@ unsigned char EBusLoop::fetchByte()
return byte; return byte;
} }
void EBusLoop::collectCycData(const int numRecv) void BusLoop::collectCycData(const int numRecv)
{ {
// cycle bytes // cycle bytes
for (int i = 0; i < numRecv; i++) { for (int i = 0; i < numRecv; i++) {
@@ -231,33 +285,43 @@ void EBusLoop::collectCycData(const int numRecv)
} }
} }
void EBusLoop::analyseCycData() void BusLoop::analyseCycData()
{ {
L.log(bus, trace, "%s", m_sstr.getDataStr().c_str()); static bool skipfirst = false;
int index = m_commands->storeCycData(m_sstr.getDataStr()); if (skipfirst == true) {
L.log(bus, trace, "%s", m_sstr.getDataStr().c_str());
if (index == -1) { int index = m_commands->storeCycData(m_sstr.getDataStr());
L.log(bus, debug, " command not found");
} if (index == -1) {
else if (index == -2) { L.log(bus, debug, " command not found");
L.log(bus, debug, " no commands defined"); }
} else if (index == -2) {
else if (index == -3) { L.log(bus, debug, " no commands defined");
L.log(bus, debug, " search skipped - string too short"); }
} else if (index == -3) {
else { L.log(bus, debug, " search skipped - string too short");
std::string tmp; }
tmp += (*m_commands)[index][1]; else {
tmp += " "; std::string tmp;
tmp += (*m_commands)[index][2]; tmp += (*m_commands)[index][1];
L.log(bus, event, " cycle [%4d] %s", index, tmp.c_str()); tmp += " ";
tmp += (*m_commands)[index][2];
L.log(bus, event, " cycle [%4d] %s", index, tmp.c_str());
}
// collect Slave address
if (index != -3)
collectSlave();
} }
else
skipfirst = true;
} }
void EBusLoop::addPollCommand() void BusLoop::addPollMessage()
{ {
int index = m_commands->nextPolCommand(); int index = m_commands->nextPollCommand();
if (index < 0) { if (index < 0) {
L.log(bus, error, "polling index out of range"); L.log(bus, error, "polling index out of range");
} }
@@ -269,23 +333,23 @@ void EBusLoop::addPollCommand()
tmp += (*m_commands)[index][2]; tmp += (*m_commands)[index][2];
L.log(bus, event, " polling [%4d] %s", index, tmp.c_str()); L.log(bus, event, " polling [%4d] %s", index, tmp.c_str());
std::string ebusCommand(A.getParam<const char*>("p_address")); std::string busCommand(A.getOptVal<const char*>("address"));
ebusCommand += m_commands->getEbusCommand(index); busCommand += m_commands->getBusCommand(index);
std::transform(ebusCommand.begin(), ebusCommand.end(), ebusCommand.begin(), tolower); std::transform(busCommand.begin(), busCommand.end(), busCommand.begin(), tolower);
BusCommand* busCommand = new BusCommand(ebusCommand, true); BusMessage* message = new BusMessage(busCommand, true, false);
L.log(bus, trace, " msg: %s", ebusCommand.c_str()); L.log(bus, trace, " msg: %s", busCommand.c_str());
addBusCommand(busCommand); addMessage(message);
} }
} }
int EBusLoop::acquireBus() int BusLoop::acquireBus()
{ {
unsigned char recvByte, sendByte; unsigned char recvByte, sendByte;
ssize_t numRecv, numSend; ssize_t numRecv, numSend;
sendByte = m_sendBuffer.next()->getCommand()[0]; sendByte = m_busQueue.next()->getCommand()[0];
// send QQ // send QQ
numSend = m_port->send(&sendByte); numSend = m_port->send(&sendByte);
@@ -294,6 +358,9 @@ int EBusLoop::acquireBus()
return RESULT_ERR_SEND; return RESULT_ERR_SEND;
} }
// wait ~4200 usec for receive
usleep(m_acquireTime);
// receive 1 byte - must be QQ // receive 1 byte - must be QQ
numRecv = m_port->recv(0); numRecv = m_port->recv(0);
@@ -334,17 +401,17 @@ int EBusLoop::acquireBus()
return RESULT_ERR_EXTRA_DATA; return RESULT_ERR_EXTRA_DATA;
} }
BusCommand* EBusLoop::sendCommand() BusMessage* BusLoop::sendCommand()
{ {
unsigned char recvByte; unsigned char recvByte;
std::string result; std::string result;
SymbolString slaveData; SymbolString slaveData;
int retval = RESULT_OK; int retval = RESULT_OK;
BusCommand* busCommand = m_sendBuffer.next(); BusMessage* message = m_busQueue.next();
// send ZZ PB SB NN Dx CRC // send ZZ PB SB NN Dx CRC
SymbolString command = busCommand->getCommand(); SymbolString command = message->getCommand();
for (size_t i = 1; i < command.size(); i++) { for (size_t i = 1; i < command.size(); i++) {
retval = sendByte(command[i]); retval = sendByte(command[i]);
if (retval < 0) if (retval < 0)
@@ -352,7 +419,7 @@ BusCommand* EBusLoop::sendCommand()
} }
// BC -> send SYN // BC -> send SYN
if (busCommand->getType() == broadcast) { if (message->getType() == broadcast) {
sendByte(SYN); sendByte(SYN);
goto on_exit; goto on_exit;
} }
@@ -387,7 +454,7 @@ BusCommand* EBusLoop::sendCommand()
} }
// MM -> send SYN // MM -> send SYN
if (busCommand->getType() == masterMaster) { if (message->getType() == masterMaster) {
sendByte(SYN); sendByte(SYN);
goto on_exit; goto on_exit;
} }
@@ -437,16 +504,16 @@ on_exit:
while (m_port->size() != 0) while (m_port->size() != 0)
recvByte = fetchByte(); recvByte = fetchByte();
busCommand->setResult(slaveData, retval); message->setResult(slaveData, retval);
if (retval == RESULT_OK) if (retval == RESULT_OK)
return m_sendBuffer.remove(); return m_busQueue.remove();
else else
return busCommand; return message;
} }
int EBusLoop::sendByte(const unsigned char sendByte) int BusLoop::sendByte(const unsigned char sendByte)
{ {
unsigned char recvByte; unsigned char recvByte;
ssize_t numRecv, numSend; ssize_t numRecv, numSend;
@@ -471,7 +538,7 @@ int EBusLoop::sendByte(const unsigned char sendByte)
return RESULT_OK; return RESULT_OK;
} }
int EBusLoop::recvSlaveAck(unsigned char& recvByte) int BusLoop::recvSlaveAck(unsigned char& recvByte)
{ {
ssize_t numRecv; ssize_t numRecv;
@@ -498,7 +565,7 @@ int EBusLoop::recvSlaveAck(unsigned char& recvByte)
return RESULT_OK; return RESULT_OK;
} }
int EBusLoop::recvSlaveData(SymbolString& result) int BusLoop::recvSlaveData(SymbolString& result)
{ {
unsigned char recvByte, calcCrc = 0; unsigned char recvByte, calcCrc = 0;
ssize_t numRecv; ssize_t numRecv;
@@ -544,3 +611,70 @@ int EBusLoop::recvSlaveData(SymbolString& result)
return RESULT_OK; return RESULT_OK;
} }
void BusLoop::collectSlave()
{
std::vector<unsigned char>::iterator it;
for (int i = 0; i < 2; i++) {
bool found = false;
unsigned char mm = m_sstr[i];
if (i == 0) {
if (mm == 0xFF)
mm = 0x04;
else
mm += 0x05;
}
for (it = m_slave.begin(); it != m_slave.end(); it++)
if ((*it) == mm)
found = true;
if (found == false && isMaster(mm) == false && mm != BROADCAST) {
m_slave.push_back(mm);
L.log(bus, event, " new slave: %d %02x", m_slave.size(), m_slave.back());
}
}
}
void BusLoop::addScanMessage()
{
std::string busCommand(A.getOptVal<const char*>("address"));
std::stringstream sstr;
if (m_scanFull == true) {
for (; m_scanIndex <= 0xFF; m_scanIndex++) {
if (isMaster(m_scanIndex) == false && m_scanIndex != SYN
&& m_scanIndex != ESC && m_scanIndex != BROADCAST) {
sstr << std::nouppercase << std::setw(2) << std::setfill('0')
<< std::hex << m_scanIndex;
break;
}
}
}
else {
sstr << std::nouppercase << std::setw(2) << std::setfill('0')
<< std::hex << static_cast<unsigned>(m_slave[m_scanIndex]);
if (m_scanIndex+1 >= m_slave.size())
m_scan = false;
}
if (m_scanIndex > 0xFF)
m_scan = false;
else {
m_scanIndex++;
busCommand += sstr.str();
busCommand += "070400";
std::transform(busCommand.begin(), busCommand.end(), busCommand.begin(), tolower);
L.log(bus, event, " scanning address %s", sstr.str().c_str());
BusMessage* message = new BusMessage(busCommand, true, true);
L.log(bus, trace, " msg: %s", busCommand.c_str());
addMessage(message);
}
}
+62 -14
View File
@@ -17,38 +17,77 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef EBUSLOOP_H_ #ifndef BUSLOOP_H_
#define EBUSLOOP_H_ #define BUSLOOP_H_
#include "commands.h" #include "commands.h"
#include "port.h" #include "port.h"
#include "dump.h" #include "dump.h"
#include "buscommand.h"
#include "wqueue.h" #include "wqueue.h"
#include "thread.h" #include "thread.h"
#include "symbol.h"
#include "result.h"
/** the maximum time [us] allowed for retrieving a byte from an addressed slave */ /** the maximum time [us] allowed for retrieving a byte from an addressed slave */
#define RECV_TIMEOUT 10000 #define RECV_TIMEOUT 10000
using namespace libebus; enum MessageType { invalid, broadcast, masterMaster, masterSlave };
class BusMessage
class EBusLoop : public Thread
{ {
public: public:
EBusLoop(Commands* commands); BusMessage(const std::string command, const bool poll, const bool scan);
~EBusLoop(); ~BusMessage();
MessageType getType() const { return m_type; }
bool isPoll() const { return m_poll; }
bool isScan() const { return m_scan; }
SymbolString getCommand() const { return m_command; }
SymbolString getResult() const { return m_result; }
bool isErrorResult() const { return m_resultCode < 0; }
const char* getResultCodeCStr() const { return getResultCode(m_resultCode); }
void setResult(const SymbolString result, const int resultCode)
{ m_result = result; m_resultCode = resultCode; }
const std::string getMessageStr();
void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout
void sendSignal() { pthread_cond_signal(&m_cond); }
private:
MessageType m_type;
bool m_poll;
bool m_scan;
SymbolString m_command;
SymbolString m_result;
int m_resultCode;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
class BusLoop : public Thread
{
public:
BusLoop(Commands* commands);
~BusLoop();
void* run(); void* run();
void stop() { m_stop = true; } void stop() { m_stop = true; }
void addBusCommand(BusCommand* busCommand) { m_sendBuffer.add(busCommand); } void addMessage(BusMessage* message) { m_busQueue.add(message); }
void dump() { m_dumpState == true ? m_dumpState = false : m_dumpState = true ; } void dump() { m_dumpState == true ? m_dumpState = false : m_dumpState = true ; }
void raw() { m_logRawData == true ? m_logRawData = false : m_logRawData = true ; } void raw() { m_logRawData == true ? m_logRawData = false : m_logRawData = true ; }
void newCommands(Commands* commands) { m_commands = commands; } void reload(Commands* commands) { m_commands = commands; }
void scan(const bool full=false) { m_scan = true; m_scanFull = full; m_scanIndex = 0; }
private: private:
Commands* m_commands; Commands* m_commands;
@@ -64,24 +103,33 @@ private:
int m_lockCounter; int m_lockCounter;
bool m_priorRetry; bool m_priorRetry;
WQueue<BusCommand*> m_sendBuffer; WQueue<BusMessage*> m_busQueue;
SymbolString m_sstr; SymbolString m_sstr;
double m_pollInterval; double m_pollInterval;
long m_recvTimeout; long m_recvTimeout;
int m_sendRetries; int m_sendRetries;
int m_lockRetries; int m_lockRetries;
long m_acquireTime;
std::vector<unsigned char> m_slave;
bool m_scan;
bool m_scanFull;
size_t m_scanIndex;
unsigned char fetchByte(); unsigned char fetchByte();
void collectCycData(const int numRecv); void collectCycData(const int numRecv);
void analyseCycData(); void analyseCycData();
void addPollCommand(); void addPollMessage();
int acquireBus(); int acquireBus();
BusCommand* sendCommand(); BusMessage* sendCommand();
int sendByte(const unsigned char sendByte); int sendByte(const unsigned char sendByte);
int recvSlaveAck(unsigned char& recvByte); int recvSlaveAck(unsigned char& recvByte);
int recvSlaveData(SymbolString& result); int recvSlaveData(SymbolString& result);
void collectSlave();
void addScanMessage();
}; };
#endif // EBUSLOOP_H_ #endif // BUSLOOP_H_
-111
View File
@@ -1,111 +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 "connection.h"
#include "logger.h"
#include <cstring>
extern LogInstance& L;
int Connection::m_count = -1;
void Connection::addResult(Message message)
{
Message* tmp = new Message(Message(message));
m_result.add(tmp);
}
void* Connection::run()
{
m_running = true;
int maxfd;
fd_set checkfds;
struct timeval timeout;
FD_ZERO(&checkfds);
FD_SET(m_notify.notifyFD(), &checkfds);
FD_SET(m_socket->getFD(), &checkfds);
(m_notify.notifyFD() > m_socket->getFD()) ?
(maxfd = m_notify.notifyFD()) : (maxfd = m_socket->getFD());
for (;;) {
fd_set readfds;
int ret;
// set select timeout 10 secs
timeout.tv_sec = 10;
timeout.tv_usec = 0;
// set readfds to inital checkfds
readfds = checkfds;
ret = select(maxfd + 1, &readfds, NULL, NULL, &timeout);
if (ret == 0) {
continue;
}
// new data from notify
if (FD_ISSET(m_notify.notifyFD(), &readfds))
break;
// new data from socket
if (FD_ISSET(m_socket->getFD(), &readfds)) {
char data[256];
size_t datalen;
if (m_socket->isValid() == true)
datalen = m_socket->recv(data, sizeof(data)-1);
else
break;
// removed closed socket
if (datalen <= 0 || strncasecmp(data, "quit", 4) == 0)
break;
// send data
data[datalen] = '\0';
m_data->add(new Message(data, this));
// wait for result
L.log(net, debug, "[%08x] wait for result", getID());
Message* message = m_result.remove();
L.log(net, debug, "[%08x] result added", getID());
std::string result(message->getData());
if (m_socket->isValid() == true)
m_socket->send(result.c_str(), result.size());
else
break;
delete message;
}
}
delete m_socket;
m_running = false;
L.log(net, trace, "[%08x] connection closed", getID());
return NULL;
}
-58
View File
@@ -1,58 +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 CONNECTION_H_
#define CONNECTION_H_
#include "tcpsocket.h"
#include "wqueue.h"
#include "notify.h"
#include "thread.h"
#include "message.h"
class Connection : public Thread
{
public:
Connection(TCPSocket* socket, WQueue<Message*>* data)
: m_socket(socket), m_data(data), m_running(false) { m_count++; }
~Connection() { m_count--; }
void addResult(Message message);
void* run();
void stop() const { m_notify.notify(); }
bool isRunning() const { return m_running; }
pthread_t getID() { return this->self(); }
int numConnections() const { return m_count; }
private:
TCPSocket* m_socket;
WQueue<Message*>* m_data;
WQueue<Message*> m_result;
Notify m_notify;
bool m_running;
static int m_count;
};
#endif // CONNECTION_H_
+4 -11
View File
@@ -21,25 +21,22 @@
#include <fstream> #include <fstream>
#include <cstdio> #include <cstdio>
namespace libebus
{
int Dump::write(const char* byte) int Dump::write(const char* byte)
{ {
int ret = 0; int ret = 0;
std::ofstream fs(m_filename.c_str(), std::ios::out | std::ios::binary | std::ios::app); std::ofstream fs(m_name.c_str(), std::ios::out | std::ios::binary | std::ios::app);
if (fs == 0) if (fs == 0)
return -1; return -1;
fs.write(byte, 1); fs.write(byte, 1);
if (fs.tellp() >= m_filesize * 1024) { if (fs.tellp() >= m_size * 1024) {
std::string oldfile; std::string oldfile;
oldfile += m_filename; oldfile += m_name;
oldfile += ".old"; oldfile += ".old";
ret = rename(m_filename.c_str(), oldfile.c_str()); ret = rename(m_name.c_str(), oldfile.c_str());
} }
fs.close(); fs.close();
@@ -47,7 +44,3 @@ int Dump::write(const char* byte)
return ret; return ret;
} }
} //namespace
+18 -23
View File
@@ -17,28 +17,25 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBEBUS_DUMP_H_ #ifndef DUMP_H_
#define LIBEBUS_DUMP_H_ #define DUMP_H_
#include <string> #include <string>
namespace libebus
{
/** /**
* @brief Class for writing raw bytes to binary file. * @brief class for writing raw bytes to binary file.
*/ */
class Dump class Dump
{ {
public: public:
/** /**
* @brief Create a new instance to write dump files. * @brief create a new instance to write dump files.
* @param filename which will be used for dumping raw bytes. * @param name the file name of dump file.
* @param filesize max. Size of the dump file, before switching. * @param size the max. size of the dump file, before switching.
*/ */
Dump(std::string filename, long filesize) Dump(std::string name, long size)
: m_filename(filename), m_filesize(filesize) {} : m_name(name), m_size(size) {}
/** /**
* @brief write byte to dump file. * @brief write byte to dump file.
@@ -48,26 +45,24 @@ public:
int write(const char* byte); int write(const char* byte);
/** /**
* @brief setter for dump file name. * @brief set the name of dump file.
* @param filename which will be used for dumping raw bytes. * @param name the file name of dump file.
*/ */
void setFilename(const std::string& filename) { m_filename = filename; } void setName(const std::string& name) { m_name = name; }
/** /**
* @brief setter for max size of dump file. * @brief set the max size of dump file.
* @param filesize max. Size of the dump file, before switching. * @param size the max. size of the dump file, before switching.
*/ */
void setFilesize(const long filesize) { m_filesize = filesize; } void setSize(const long size) { m_size = size; }
private: private:
/** the name of dump file*/ /** the name of dump file*/
std::string m_filename; std::string m_name;
/** max. size of dump file */ /** max. size of dump file */
long m_filesize; long m_size;
}; };
#endif // DUMP_H_
} //namespace
#endif // LIBEBUS_DUMP_H_
+185
View File
@@ -0,0 +1,185 @@
/*
* 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>
Appl& A = Appl::Instance();
Daemon& D = Daemon::Instance();
Logger& L = Logger::Instance();
BaseLoop* baseloop;
void define_args()
{
A.setVersion(""PACKAGE_STRING"");
A.addText("Options:\n");
A.addOption("address", "a", OptVal("FF"), dt_string, ot_mandatory,
"\tebus device address (FF)");
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 valid ebus device test\n");
A.addOption("sendretries", "s", OptVal(2), dt_int, ot_mandatory,
"number retries send ebus command (2)");
A.addOption("lockretries", "", OptVal(2), dt_int, ot_mandatory,
"number retries to lock ebus (2)");
A.addOption("lockcounter", "", OptVal(5), dt_int, ot_mandatory,
"number of SYN to unlock send function (5)");
A.addOption("recvtimeout", "", OptVal(15000), dt_long, ot_mandatory,
"receive timeout in 'us' (15000)");
A.addOption("acquiretime", "", OptVal(4200), dt_long, ot_mandatory,
"waiting time for bus acquire in 'us' (4200)\n");
A.addOption("pollinterval", "", OptVal(5), dt_int, ot_mandatory,
"polling interval in 's' (5)\n");
A.addOption("ebusconfdir", "e", OptVal("/etc/ebusd"), dt_string, ot_mandatory,
"directory for ebus configuration (/etc/ebusd)\n");
A.addOption("foreground", "f", OptVal(false), dt_bool, ot_none,
"run in foreground\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|cyc|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
delete baseloop;
// 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;
}
}
int main(int argc, char* argv[])
{
// define arguments and application variables
define_args();
// parse arguments
A.parseArgs(argc, argv);
// make me daemon
if (A.getOptVal<bool>("foreground") == true) {
L += new LogConsole(calcAreas(A.getOptVal<const char*>("logareas")),
calcLevel(A.getOptVal<const char*>("loglevel")),
"logconsole");
} else {
D.run("/var/run/ebusd.pid");
L += new LogFile(calcAreas(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();
}
-216
View File
@@ -1,216 +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 "logger.h"
#include "daemon.h"
#include "appl.h"
#include "baseloop.h"
#include <csignal>
using namespace libebus;
Appl& A = Appl::Instance();
Daemon& D = Daemon::Instance();
LogInstance& L = LogInstance::Instance();
BaseLoop* baseloop;
void define_args()
{
A.addArgs("", 0);
A.addItem("p_address", Appl::Param("FF"), "a", "address",
"\tebus device address (FF)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_device", Appl::Param("/dev/ttyUSB0"), "d", "device",
"\tebus device (serial or network) (/dev/ttyUSB0)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_nodevicecheck", Appl::Param(false), "n", "nodevicecheck",
"disable valid ebus device test\n",
Appl::type_bool, Appl::opt_none);
A.addItem("p_sendretries", Appl::Param(2), "s", "sendretries",
"number retries send ebus command (2)",
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_lockretries", Appl::Param(2), "", "lockretries",
"number retries to lock ebus (2)",
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_lockcounter", Appl::Param(5), "", "lockcounter",
"number of SYN to unlock send function (5)",
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_recvtimeout", Appl::Param(15000), "", "recvtimeout",
"receive timeout in 'us' (15000)\n",
Appl::type_long, Appl::opt_mandatory);
A.addItem("p_pollinterval", Appl::Param(5), "", "pollinterval",
"polling interval in 's' (5)\n",
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_ebusconfdir", Appl::Param("/etc/ebusd"), "e", "ebusconfdir",
"directory for ebus configuration (/etc/ebusd)\n",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_foreground", Appl::Param(false), "f", "foreground",
"run in foreground\n",
Appl::type_bool, Appl::opt_none);
A.addItem("p_port", Appl::Param(8888), "p", "port",
"\tlisten port (8888)",
Appl::type_int, Appl::opt_mandatory);
A.addItem("p_localhost", Appl::Param(false), "", "localhost",
"listen localhost only\n",
Appl::type_bool, Appl::opt_none);
A.addItem("p_logfile", Appl::Param("/var/log/ebusd.log"), "l", "logfile",
"\tlog file name (/var/log/ebusd.log)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_logareas", Appl::Param("all"), "", "logareas",
"\tlog areas - bas|net|bus|cyc|all (all)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_loglevel", Appl::Param("trace"), "", "loglevel",
"\tlog level - error|event|trace|debug (event)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_lograwdata", Appl::Param(false), "", "lograwdata",
"log raw data (bytes)\n",
Appl::type_bool, Appl::opt_none);
A.addItem("p_dump", Appl::Param(false), "D", "dump",
"\tenable dump",
Appl::type_bool, Appl::opt_none);
A.addItem("p_dumpfile", Appl::Param("/tmp/ebus_dump.bin"), "", "dumpfile",
"\tdump file name (/tmp/ebus_dump.bin)",
Appl::type_string, Appl::opt_mandatory);
A.addItem("p_dumpsize", Appl::Param(100), "", "dumpsize",
"\tmax size for dump file in 'kB' (100)\n",
Appl::type_long, Appl::opt_mandatory);
A.addItem("p_settings", Appl::Param(false), "", "settings",
"\tprint daemon settings\n",
Appl::type_bool, Appl::opt_none);
A.addItem("p_help", Appl::Param(false), "h", "help",
"\tprint this message",
Appl::type_bool, Appl::opt_none);
}
void shutdown()
{
// stop threads
delete baseloop;
// 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;
}
}
int main(int argc, char* argv[])
{
// define Arguments and Application variables
define_args();
// parse Arguments
if (A.parseArgs(argc, argv) == false) {
A.printArgs();
exit(EXIT_FAILURE);
}
// print Help
if (A.getParam<bool>("p_help") == true) {
A.printArgs();
exit(EXIT_SUCCESS);
}
// print Daemon settings
if (A.getParam<bool>("p_settings") == true)
A.printSettings();
// make me Daemon
if (A.getParam<bool>("p_foreground") == true) {
L += new LogConsole(calcAreas(A.getParam<const char*>("p_logareas")),
calcLevel(A.getParam<const char*>("p_loglevel")),
"logconsole");
} else {
D.run("/var/run/ebusd.pid");
L += new LogFile(calcAreas(A.getParam<const char*>("p_logareas")),
calcLevel(A.getParam<const char*>("p_loglevel")),
"logfile", A.getParam<const char*>("p_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();
}
+107 -31
View File
@@ -20,19 +20,98 @@
#include "network.h" #include "network.h"
#include "logger.h" #include "logger.h"
#include "appl.h" #include "appl.h"
#include <cstring>
#include <poll.h>
extern LogInstance& L; extern Logger& L;
extern Appl& A; extern Appl& A;
int Connection::m_ids = 0;
Network::Network(const bool localhost) : m_listening(false), m_running(false) void* Connection::run()
{ {
if (localhost == true) m_running = true;
m_Server = new TCPServer(A.getParam<int>("p_port"), "127.0.0.1");
else
m_Server = new TCPServer(A.getParam<int>("p_port"), "0.0.0.0");
if (m_Server != NULL && m_Server->start() == 0) int ret, nfds = 2;
struct pollfd fds[nfds];
struct timespec tdiff;
// set select timeout 10 secs
tdiff.tv_sec = 10;
tdiff.tv_nsec = 0;
memset(fds, 0, sizeof(fds));
fds[0].fd = m_notify.notifyFD();
fds[0].events = POLLIN;
fds[1].fd = m_socket->getFD();
fds[1].events = POLLIN;
for (;;) {
// wait for new fd event
ret = ppoll(fds, nfds, &tdiff, NULL);
if (ret == 0) {
continue;
}
// new data from notify
if (fds[0].revents & POLLIN)
break;
// new data from socket
if (fds[1].revents & POLLIN) {
char data[256];
size_t datalen;
if (m_socket->isValid() == true)
datalen = m_socket->recv(data, sizeof(data)-1);
else
break;
// removed closed socket
if (datalen <= 0 || strcasecmp(data, "QUIT") == 0)
break;
// send data
data[datalen] = '\0';
NetMessage message(data);
m_netQueue->add(&message);
// wait for result
L.log(net, debug, "[%05d] wait for result", getID());
message.waitSignal();
L.log(net, debug, "[%05d] result added", getID());
std::string result = message.getResult();
if (m_socket->isValid() == true)
m_socket->send(result.c_str(), result.size());
else
break;
}
}
delete m_socket;
m_running = false;
L.log(net, trace, "[%05d] connection closed", getID());
return NULL;
}
Network::Network(const bool local, WQueue<NetMessage*>* netQueue)
: m_netQueue(netQueue), m_listening(false), m_running(false)
{
if (local == true)
m_tcpServer = new TCPServer(A.getOptVal<int>("port"), "127.0.0.1");
else
m_tcpServer = new TCPServer(A.getOptVal<int>("port"), "0.0.0.0");
if (m_tcpServer != NULL && m_tcpServer->start() == 0)
m_listening = true; m_listening = true;
} }
@@ -50,7 +129,7 @@ Network::~Network()
if (m_running == true) if (m_running == true)
stop(); stop();
delete m_Server; delete m_tcpServer;
} }
void* Network::run() void* Network::run()
@@ -60,53 +139,50 @@ void* Network::run()
m_running = true; m_running = true;
int maxfd; int ret, nfds = 2;
fd_set checkfds; struct pollfd fds[nfds];
struct timeval timeout; struct timespec tdiff;
FD_ZERO(&checkfds); // set select timeout 1 secs
FD_SET(m_notify.notifyFD(), &checkfds); tdiff.tv_sec = 1;
FD_SET(m_Server->getFD(), &checkfds); tdiff.tv_nsec = 0;
(m_notify.notifyFD() > m_Server->getFD()) ? memset(fds, 0, sizeof(fds));
(maxfd = m_notify.notifyFD()) : (maxfd = m_Server->getFD());
fds[0].fd = m_notify.notifyFD();
fds[0].events = POLLIN;
fds[1].fd = m_tcpServer->getFD();
fds[1].events = POLLIN;
for (;;) { for (;;) {
fd_set readfds; // wait for new fd event
int ret; ret = ppoll(fds, nfds, &tdiff, NULL);
// set select timeout 1 secs
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// set readfds to inital checkfds
readfds = checkfds;
ret = select(maxfd + 1, &readfds, NULL, NULL, &timeout);
if (ret == 0) { if (ret == 0) {
cleanConnections(); cleanConnections();
continue; continue;
} }
// new data from notify // new data from notify
if (FD_ISSET(m_notify.notifyFD(), &readfds)) { if (fds[0].revents & POLLIN) {
m_running = false; m_running = false;
break; break;
} }
// new data from socket // new data from socket
if (FD_ISSET(m_Server->getFD(), &readfds)) { if (fds[1].revents & POLLIN) {
TCPSocket* socket = m_Server->newSocket(); TCPSocket* socket = m_tcpServer->newSocket();
if (socket == NULL) if (socket == NULL)
continue; continue;
Connection* connection = new Connection(socket, m_queue); Connection* connection = new Connection(socket, m_netQueue);
if (connection == NULL) if (connection == NULL)
continue; continue;
connection->start("connection"); connection->start("connection");
m_connections.push_back(connection); m_connections.push_back(connection);
L.log(net, trace, "[%08x] connection opened %s", connection->getID(), socket->getIP().c_str()); L.log(net, trace, "[%05d] connection opened %s", connection->getID(), socket->getIP().c_str());
} }
} }
+194 -6
View File
@@ -20,30 +20,218 @@
#ifndef NETWORK_H_ #ifndef NETWORK_H_
#define NETWORK_H_ #define NETWORK_H_
#include "connection.h" #include "tcpsocket.h"
#include "wqueue.h"
#include "notify.h"
#include "thread.h"
#include <string>
/** forward declaration for class connection */
class Connection;
/**
* @brief class for data/message transfer between connection and baseloop.
*/
class NetMessage
{
public:
/**
* @brief constructs a new instance with message and source client address.
* @param data from client.
*/
NetMessage(const std::string data) : m_data(data)
{
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
/**
* @brief destructor.
*/
~NetMessage()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
/**
* @brief copy constructor.
* @param src message object for copy.
*/
NetMessage(const NetMessage& src) : m_data(src.m_data) {}
/**
* @brief get the data string.
* @return the data string.
*/
std::string getData() const { return m_data; }
/**
* @brief get the result string.
* @return the result string.
*/
std::string getResult() const { return m_result; }
/**
* @brief set the result string.
* @return the result string.
*/
void setResult(const std::string result) { m_result = result; }
/**
* @brief wait on notification.
*/
void waitSignal()
{
pthread_mutex_lock(&m_mutex);
while (m_result.size() == 0)
pthread_cond_wait(&m_cond, &m_mutex);
pthread_mutex_unlock(&m_mutex);
}
/**
* @brief send notification.
*/
void sendSignal()
{
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
private:
/** the data string */
std::string m_data;
/** the result string */
std::string m_result;
/** mutex variable for exclusive lock */
pthread_mutex_t m_mutex;
/** condition variable for exclusive lock */
pthread_cond_t m_cond;
};
/**
* @brief class connection which handle client and baseloop communication.
*/
class Connection : public Thread
{
public:
/**
* @brief create a new connection instance.
* @param socket the tcp socket for communication.
* @param netQueue the remote queue for network messages.
*/
Connection(TCPSocket* socket, WQueue<NetMessage*>* netQueue)
: m_socket(socket), m_netQueue(netQueue), m_running(false)
{ m_id = ++m_ids; }
/**
* @brief endless loop for connection instance.
* @return void pointer.
*/
void* run();
/**
* @brief closs active connection.
*/
void stop() const { m_notify.notify(); }
/**
* @brief status of connection instance.
* @return true if connection is running.
*/
bool isRunning() const { return m_running; }
/**
* @brief return own connection id.
* @return id of current connection.
*/
int getID() { return m_id; }
private:
/** the tcp socket instance */
TCPSocket* m_socket;
/** remote queue for network messages */
WQueue<NetMessage*>* m_netQueue;
/** notification object for shutdown procedure */
Notify m_notify;
/** true if this instance is running */
bool m_running;
/** id of current connection*/
int m_id;
/** sumary for opened connections */
static int m_ids;
};
/**
* @brief class network which listening on tcp socket for incoming connections.
*/
class Network : public Thread class Network : public Thread
{ {
public: public:
Network(const bool localhost); /**
* @brief create a new network instance and listening for incoming connections.
* @param local true to accept connections only for local host.
* @param netQueue the remote queue for network messages.
*/
Network(const bool local, WQueue<NetMessage*>* netQueue);
/**
* @brief destructor.
*/
~Network(); ~Network();
void addQueue(WQueue<Message*>* queue) { m_queue = queue; } /**
* @brief endless loop for network instance.
* @return void pointer.
*/
void* run(); void* run();
/**
* @brief shutdown network subsystem.
*/
void stop() const { m_notify.notify(); usleep(100000); } void stop() const { m_notify.notify(); usleep(100000); }
private: private:
/** container for active connections */
std::list<Connection*> m_connections; std::list<Connection*> m_connections;
WQueue<Message*>* m_queue;
TCPServer* m_Server; /** remote queue for network messages */
WQueue<NetMessage*>* m_netQueue;
/** the tcp server instance */
TCPServer* m_tcpServer;
/** notification object for shutdown procedure */
Notify m_notify; Notify m_notify;
/** true if this instance is listening */
bool m_listening; bool m_listening;
/** true if this instance is running */
bool m_running; bool m_running;
/**
* @brief clean inactive connections from container.
*/
void cleanConnections(); void cleanConnections();
}; };
#endif // NETWORK_H_ #endif // NETWORK_H_
-4
View File
@@ -12,16 +12,12 @@ libebus_a_SOURCES = result.cpp \
data.h \ data.h \
port.cpp \ port.cpp \
port.h \ port.h \
buscommand.cpp \
buscommand.h \
command.cpp \ command.cpp \
command.h \ command.h \
commands.cpp \ commands.cpp \
commands.h \ commands.h \
configfile.cpp \ configfile.cpp \
configfile.h \ configfile.h \
dump.cpp \
dump.h \
decode.cpp \ decode.cpp \
decode.h \ decode.h \
encode.cpp \ encode.cpp \
-69
View File
@@ -1,69 +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 "buscommand.h"
namespace libebus
{
BusCommand::BusCommand(const std::string commandStr, const bool isPoll)
: m_isPoll(isPoll), m_command(commandStr), m_result(), m_resultCode(RESULT_OK)
{
unsigned char dstAddress = m_command[1];
if (dstAddress == BROADCAST)
m_type = broadcast;
else if (isMaster(dstAddress) == true)
m_type = masterMaster;
else
m_type = masterSlave;
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}
BusCommand::~BusCommand()
{
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
const std::string BusCommand::getMessageStr()
{
std::string result;
if (m_resultCode >= 0) {
if (m_type == masterSlave) {
result = m_command.getDataStr();
result += "00";
result += m_result.getDataStr();
result += "00";
}
else
result = "success";
}
else
result = "error: "+std::string(getResultCodeCStr());
return result;
}
} //namespace
-70
View File
@@ -1,70 +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 LIBEBUS_BUSCOMMAND_H_
#define LIBEBUS_BUSCOMMAND_H_
#include "symbol.h"
#include "result.h"
namespace libebus
{
enum CommandType { invalid, broadcast, masterMaster, masterSlave };
class BusCommand
{
public:
BusCommand(const std::string command, const bool isPoll);
~BusCommand();
CommandType getType() const { return m_type; }
bool isPoll() const { return m_isPoll; }
SymbolString getCommand() const { return m_command; }
SymbolString getResult() const { return m_result; }
bool isErrorResult() const { return m_resultCode < 0; }
const char* getResultCodeCStr() const { return libebus::getResultCodeCStr(m_resultCode); }
void setResult(const SymbolString result, const int resultCode)
{ m_result = result; m_resultCode = resultCode; }
const std::string getMessageStr();
void waitSignal() { pthread_cond_wait(&m_cond, &m_mutex); } // TODO timeout
void sendSignal() { pthread_cond_signal(&m_cond); }
private:
CommandType m_type;
bool m_isPoll;
SymbolString m_command;
SymbolString m_result;
int m_resultCode;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
} //namespace
#endif // LIBEBUS_BUSCOMMAND_H_
-7
View File
@@ -27,10 +27,6 @@
#include <vector> #include <vector>
#include <cstring> #include <cstring>
namespace libebus
{
std::string Command::calcData() std::string Command::calcData()
{ {
// encode - only first entry will be encoded // encode - only first entry will be encoded
@@ -340,6 +336,3 @@ void Command::encode(const std::string& data, const std::string& type,
delete help; delete help;
} }
} //namespace
-7
View File
@@ -23,10 +23,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace libebus
{
typedef std::vector<std::string> cmd_t; typedef std::vector<std::string> cmd_t;
typedef cmd_t::const_iterator cmdCI_t; typedef cmd_t::const_iterator cmdCI_t;
@@ -63,7 +59,4 @@ private:
}; };
} //namespace
#endif // LIBEBUS_COMMAND_H_ #endif // LIBEBUS_COMMAND_H_
+33 -26
View File
@@ -25,16 +25,12 @@
#include <vector> #include <vector>
#include <cstring> #include <cstring>
namespace libebus
{
Commands::~Commands() Commands::~Commands()
{ {
for (mapCI_t iter = m_polDB.begin(); iter != m_polDB.end(); ++iter) for (mapCI_t iter = m_pollDB.begin(); iter != m_pollDB.end(); ++iter)
delete iter->second; delete iter->second;
m_polDB.clear(); m_pollDB.clear();
for (mapCI_t iter = m_cycDB.begin(); iter != m_cycDB.end(); ++iter) for (mapCI_t iter = m_cycDB.begin(); iter != m_cycDB.end(); ++iter)
delete iter->second; delete iter->second;
@@ -55,7 +51,7 @@ void Commands::addCommand(const cmd_t& command)
if (strcasecmp(command[0].c_str(),"P") == 0) { if (strcasecmp(command[0].c_str(),"P") == 0) {
Command* cmd = new Command(m_cmdDB.size()-1, command); Command* cmd = new Command(m_cmdDB.size()-1, command);
m_polDB.insert(pair_t(m_cmdDB.size()-1, cmd)); m_pollDB.insert(pair_t(m_cmdDB.size()-1, cmd));
} }
} }
@@ -127,7 +123,7 @@ int Commands::findCommand(const std::string& data) const
return -1; return -1;
} }
std::string Commands::getEbusCommand(const int index) const std::string Commands::getBusCommand(const int index) const
{ {
cmd_t command = m_cmdDB.at(index); cmd_t command = m_cmdDB.at(index);
std::string cmd; std::string cmd;
@@ -163,7 +159,7 @@ int Commands::storeCycData(const std::string& data) const
// walk through commands // walk through commands
for (; iter != m_cycDB.end(); iter++) { for (; iter != m_cycDB.end(); iter++) {
std::string command = getEbusCommand(iter->first); std::string command = getBusCommand(iter->first);
// skip wrong search string length // skip wrong search string length
if (command.length() > search.length()) if (command.length() > search.length())
@@ -188,35 +184,35 @@ std::string Commands::getCycData(int index) const
return ""; return "";
} }
int Commands::nextPolCommand() int Commands::nextPollCommand()
{ {
size_t index = 0; size_t index = 0;
m_polIndex++; m_pollIndex++;
if (m_polIndex == m_polDB.size()) if (m_pollIndex == m_pollDB.size())
m_polIndex = 0; m_pollIndex = 0;
mapCI_t iter = m_polDB.begin(); mapCI_t iter = m_pollDB.begin();
for (; iter != m_polDB.end(); iter++, index++) for (; iter != m_pollDB.end(); iter++, index++)
if (index == m_polIndex) if (index == m_pollIndex)
return iter->first; return iter->first;
return -1; return -1;
} }
void Commands::storePolData(const std::string& data) const void Commands::storePollData(const std::string& data) const
{ {
// prepare string for searching command // prepare string for searching command
std::string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2)); std::string search(data.substr(2, 8 + strtol(data.substr(8,2).c_str(), NULL, 16) * 2));
mapCI_t iter = m_polDB.begin(); mapCI_t iter = m_pollDB.begin();
// walk through commands // walk through commands
for (; iter != m_polDB.end(); iter++) { for (; iter != m_pollDB.end(); iter++) {
std::string command = getEbusCommand(iter->first); std::string command = getBusCommand(iter->first);
// skip wrong search string length // skip wrong search string length
if (command.length() > search.length()) if (command.length() > search.length())
@@ -228,15 +224,29 @@ void Commands::storePolData(const std::string& data) const
} }
} }
std::string Commands::getPolData(int index) const std::string Commands::getPollData(const int index) const
{ {
mapCI_t iter = m_polDB.find(index); mapCI_t iter = m_pollDB.find(index);
if (iter != m_polDB.end()) if (iter != m_pollDB.end())
return iter->second->getData(); return iter->second->getData();
else else
return ""; return "";
} }
void Commands::storeScanData(const std::string& data)
{
std::vector<std::string>::const_iterator iter = m_scanDB.begin();
bool found = false;
// walk through scan data
for (; iter != m_scanDB.end(); iter++)
if (data == (*iter))
found = true;
if (found == false)
m_scanDB.push_back(data);
}
void Commands::printCommand(const cmd_t& command) const void Commands::printCommand(const cmd_t& command) const
{ {
if (command.size() == 0) if (command.size() == 0)
@@ -246,6 +256,3 @@ void Commands::printCommand(const cmd_t& command) const
std::cout << *i << ';'; std::cout << *i << ';';
} }
} //namespace
+14 -15
View File
@@ -25,10 +25,6 @@
#include <vector> #include <vector>
#include <map> #include <map>
namespace libebus
{
typedef std::vector<cmd_t> cmdDB_t; typedef std::vector<cmd_t> cmdDB_t;
typedef cmdDB_t::const_iterator cmdDBCI_t; typedef cmdDB_t::const_iterator cmdDBCI_t;
@@ -40,7 +36,7 @@ class Commands
{ {
public: public:
Commands() : m_polIndex(-1) {} Commands() : m_pollIndex(-1) {}
~Commands(); ~Commands();
void addCommand(const cmd_t& command); void addCommand(const cmd_t& command);
@@ -48,33 +44,36 @@ public:
std::size_t sizeCmdDB() const { return m_cmdDB.size(); } std::size_t sizeCmdDB() const { return m_cmdDB.size(); }
std::size_t sizeCycDB() const { return m_cycDB.size(); } std::size_t sizeCycDB() const { return m_cycDB.size(); }
std::size_t sizePolDB() const { return m_polDB.size(); } std::size_t sizePollDB() const { return m_pollDB.size(); }
std::size_t sizeScanDB() const { return m_scanDB.size(); }
cmd_t const& operator[](const std::size_t& index) const { return m_cmdDB[index]; } cmd_t const& operator[](const std::size_t& index) const { return m_cmdDB[index]; }
int findCommand(const std::string& data) const; int findCommand(const std::string& data) const;
std::string getCmdType(const int index) const { return std::string(m_cmdDB.at(index)[0]); } std::string getCmdType(const int index) const { return std::string(m_cmdDB.at(index)[0]); }
std::string getEbusCommand(const int index) const; std::string getBusCommand(const int index) const;
int storeCycData(const std::string& data) const; int storeCycData(const std::string& data) const;
std::string getCycData(int index) const; std::string getCycData(int index) const;
int nextPolCommand(); int nextPollCommand();
void storePolData(const std::string& data) const; void storePollData(const std::string& data) const;
std::string getPolData(int index) const; std::string getPollData(const int index) const;
void storeScanData(const std::string& data);
std::string getScanData(const int index) const { return m_scanDB[index]; }
private: private:
cmdDB_t m_cmdDB; cmdDB_t m_cmdDB;
map_t m_cycDB; map_t m_cycDB;
map_t m_polDB; map_t m_pollDB;
size_t m_polIndex; size_t m_pollIndex;
std::vector<std::string> m_scanDB;
void printCommand(const cmd_t& command) const; void printCommand(const cmd_t& command) const;
}; };
} //namespace
#endif // LIBEBUS_COMMANDS_H_ #endif // LIBEBUS_COMMANDS_H_
-7
View File
@@ -22,10 +22,6 @@
#include <fstream> #include <fstream>
#include <dirent.h> #include <dirent.h>
namespace libebus
{
void ConfigFileCSV::parse(std::istream& is, Commands& commands) void ConfigFileCSV::parse(std::istream& is, Commands& commands)
{ {
std::string line; std::string line;
@@ -132,6 +128,3 @@ void ConfigCommands::addFiles(const std::string path, const std::string extensio
closedir(dir); closedir(dir);
}; };
} //namespace
+16 -18
View File
@@ -24,21 +24,18 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace libebus
{
/** available file endings / types. */ /** available file endings / types. */
enum FileType { CSV, XML }; enum FileType { CSV, XML };
/** /**
* @brief Base class for config files. * @brief base class for config files.
*/ */
class ConfigFile class ConfigFile
{ {
public: public:
/** /**
* @brief Destructor. * @brief destructor.
*/ */
virtual ~ConfigFile() {} virtual ~ConfigFile() {}
@@ -52,14 +49,14 @@ public:
}; };
/** /**
* @brief Class for CSV config files. * @brief class for CSV config files.
*/ */
class ConfigFileCSV : public ConfigFile class ConfigFileCSV : public ConfigFile
{ {
public: public:
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~ConfigFileCSV() {} ~ConfigFileCSV() {}
@@ -73,14 +70,14 @@ public:
}; };
/** /**
* @brief Class for XML config files. * @brief class for XML config files.
*/ */
class ConfigFileXML : public ConfigFile class ConfigFileXML : public ConfigFile
{ {
public: public:
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~ConfigFileXML() {} ~ConfigFileXML() {}
@@ -95,32 +92,32 @@ public:
/** /**
* @brief Class for class Device. * @brief class for class device.
*/ */
class ConfigCommands class ConfigCommands
{ {
public: public:
/** /**
* @brief Set file type and add recursive files from given path. * @brief set file type and add recursive files from given path.
* @param path to configuration files. * @param path to configuration files.
* @param Filetype to parse. * @param filetype to parse.
*/ */
ConfigCommands(const std::string path, const FileType type); ConfigCommands(const std::string path, const FileType type);
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~ConfigCommands() { delete m_configfile; } ~ConfigCommands() { delete m_configfile; }
/** /**
* @brief setter for file type. * @brief setter for file type.
* @param FileType of files. * @param filetype of files.
*/ */
void setType(const FileType type); void setType(const FileType type);
/** /**
* @brief Parse files for commands and store them into commands instance. * @brief parse files for commands and store them into commands instance.
* @return a commands instance * @return a commands instance
*/ */
Commands* getCommands(); Commands* getCommands();
@@ -128,10 +125,13 @@ public:
private: private:
/** the configfile instance */ /** the configfile instance */
ConfigFile* m_configfile; ConfigFile* m_configfile;
/** main path for configuration files */ /** main path for configuration files */
std::string m_path; std::string m_path;
/** valid file extension */ /** valid file extension */
std::string m_extension; std::string m_extension;
/** vector of configuration files */ /** vector of configuration files */
std::vector<std::string> m_files; std::vector<std::string> m_files;
@@ -144,7 +144,5 @@ private:
}; };
} //namespace
#endif // LIBEBUS_CONFIGFILE_H_ #endif // LIBEBUS_CONFIGFILE_H_
Regular → Executable
-7
View File
@@ -29,9 +29,6 @@
#include <typeinfo> #include <typeinfo>
#include <math.h> #include <math.h>
namespace libebus
{
/** the known data field types. */ /** the known data field types. */
static const dataType_t dataTypes[] = { static const dataType_t dataTypes[] = {
{"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space {"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space
@@ -895,7 +892,6 @@ result_t ValueListDataField::writeSymbols(std::istringstream& input,
return RESULT_ERR_INVALID_ARG; // value assignment not found return RESULT_ERR_INVALID_ARG; // value assignment not found
} }
DataFieldSet::~DataFieldSet() DataFieldSet::~DataFieldSet()
{ {
while (m_fields.empty() == false) { while (m_fields.empty() == false) {
@@ -976,6 +972,3 @@ result_t DataFieldSet::write(std::istringstream& input, SymbolString& masterData
return RESULT_OK; return RESULT_OK;
} }
} //namespace
Regular → Executable
-6
View File
@@ -26,10 +26,6 @@
#include <vector> #include <vector>
#include <map> #include <map>
namespace libebus
{
/** the message part in which a data field is stored. */ /** the message part in which a data field is stored. */
enum PartType { enum PartType {
pt_template, // special part type for templates (relative offset) pt_template, // special part type for templates (relative offset)
@@ -501,6 +497,4 @@ protected:
}; };
} //namespace
#endif // LIBEBUS_DATA_H_ #endif // LIBEBUS_DATA_H_
-7
View File
@@ -26,10 +26,6 @@
#include <vector> #include <vector>
#include <cstring> #include <cstring>
namespace libebus
{
Decode::Decode(const std::string& data, const std::string& factor) Decode::Decode(const std::string& data, const std::string& factor)
: m_data(data) : m_data(data)
{ {
@@ -347,6 +343,3 @@ std::string DecodeTTM::decode()
return result.str(); return result.str();
} }
} //namespace
-7
View File
@@ -22,10 +22,6 @@
#include <string> #include <string>
namespace libebus
{
class Decode class Decode
{ {
@@ -285,7 +281,4 @@ public:
}; };
} //namespace
#endif // LIBEBUS_DECODE_H_ #endif // LIBEBUS_DECODE_H_
-7
View File
@@ -26,10 +26,6 @@
#include <vector> #include <vector>
#include <cstring> #include <cstring>
namespace libebus
{
Encode::Encode(const std::string& data, const std::string& factor) Encode::Encode(const std::string& data, const std::string& factor)
: m_data(data) : m_data(data)
{ {
@@ -364,6 +360,3 @@ std::string EncodeTTM::encode()
return result.str(); return result.str();
} }
} //namespace
-7
View File
@@ -22,10 +22,6 @@
#include <string> #include <string>
namespace libebus
{
class Encode class Encode
{ {
@@ -285,7 +281,4 @@ public:
}; };
} //namespace
#endif // LIBEBUS_ENCODE_H_ #endif // LIBEBUS_ENCODE_H_
+14 -22
View File
@@ -20,19 +20,11 @@
#include "port.h" #include "port.h"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <termios.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <unistd.h> #include <poll.h>
namespace libebus
{
bool Device::isOpen() bool Device::isOpen()
{ {
@@ -72,18 +64,23 @@ ssize_t Device::recvBytes(const long timeout, size_t maxCount)
return -1; // TODO RESULT_ERR_DEVICE return -1; // TODO RESULT_ERR_DEVICE
if (timeout > 0) { if (timeout > 0) {
fd_set readfds; int ret, nfds = 1;
struct timeval tdiff; struct pollfd fds[nfds];
struct timespec tdiff;
// set select timeout // set select timeout
tdiff.tv_sec = 0; tdiff.tv_sec = 0;
tdiff.tv_usec = timeout; tdiff.tv_nsec = timeout*1000;
FD_ZERO(&readfds); memset(fds, 0, sizeof(fds));
FD_SET(m_fd, &readfds);
if (select(m_fd + 1, &readfds, NULL, NULL, &tdiff) != 1) fds[0].fd = m_fd;
return -2; // TODO RESULT_ERR_TIMEOUT fds[0].events = POLLIN;
ret = ppoll(fds, nfds, &tdiff, NULL);
if (ret == -1) return -1; // TODO RESULT_ERR_DEVICE
if (ret == 0) return -2; // TODO RESULT_ERR_TIMEOUT
} }
if (maxCount > sizeof(m_buffer)) if (maxCount > sizeof(m_buffer))
@@ -141,7 +138,7 @@ void DeviceSerial::openDevice(const std::string deviceName, const bool noDeviceC
newSettings.c_cc[VTIME] = 0; newSettings.c_cc[VTIME] = 0;
// empty device buffer // empty device buffer
tcflush(m_fd, TCIOFLUSH); tcflush(m_fd, TCIFLUSH);
// activate new settings of serial device // activate new settings of serial device
tcsetattr(m_fd, TCSANOW, &newSettings); tcsetattr(m_fd, TCSANOW, &newSettings);
@@ -255,8 +252,3 @@ void Port::setType(const DeviceType type)
}; };
}; };
} //namespace
+18 -18
View File
@@ -25,9 +25,6 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
namespace libebus
{
/** available device types. */ /** available device types. */
enum DeviceType { SERIAL, NETWORK }; enum DeviceType { SERIAL, NETWORK };
@@ -39,19 +36,19 @@ enum DeviceType { SERIAL, NETWORK };
/** /**
* @brief Base class for input devices. * @brief base class for input devices.
*/ */
class Device class Device
{ {
public: public:
/** /**
* @brief Constructs a new instance. * @brief constructs a new instance.
*/ */
Device() : m_fd(-1), m_open(false), m_noDeviceCheck(false) {} Device() : m_fd(-1), m_open(false), m_noDeviceCheck(false) {}
/** /**
* @brief Destructor. * @brief destructor.
*/ */
virtual ~Device() {} virtual ~Device() {}
@@ -74,7 +71,7 @@ public:
bool isOpen(); bool isOpen();
/** /**
* @brief sendBytes write bytes into opened file descriptor. * @brief sendBytes write bytes to opened file descriptor.
* @param buffer data to send. * @param buffer data to send.
* @param nbytes number of bytes to send. * @param nbytes number of bytes to send.
* @return number of written bytes or -1 if an error has occured. * @return number of written bytes or -1 if an error has occured.
@@ -83,7 +80,7 @@ public:
/** /**
* @brief recvBytes read bytes from opened file descriptor. * @brief recvBytes read bytes from opened file descriptor.
* @param timeout max time out for new input data. * @param timeoutmax time for new input data [usec].
* @param maxCount max size of receive buffer. * @param maxCount max size of receive buffer.
* @return number of read bytes or -1 if an error has occured. * @return number of read bytes or -1 if an error has occured.
*/ */
@@ -104,12 +101,16 @@ public:
protected: protected:
/** if of file descriptor */ /** if of file descriptor */
int m_fd; int m_fd;
/** state of device*/ /** state of device*/
bool m_open; bool m_open;
/** state of device check */ /** state of device check */
bool m_noDeviceCheck; bool m_noDeviceCheck;
/** queue for received bytes */ /** queue for received bytes */
std::queue<unsigned char> m_recvBuffer; std::queue<unsigned char> m_recvBuffer;
/** receive buffer */ /** receive buffer */
unsigned char m_buffer[MAX_READ_SIZE]; unsigned char m_buffer[MAX_READ_SIZE];
@@ -123,14 +124,14 @@ private:
}; };
/** /**
* @brief Class for serial input device. * @brief class for serial input device.
*/ */
class DeviceSerial : public Device class DeviceSerial : public Device
{ {
public: public:
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~DeviceSerial() { closeDevice(); } ~DeviceSerial() { closeDevice(); }
@@ -153,14 +154,14 @@ private:
}; };
/** /**
* @brief Class for network input device. * @brief class for network input device.
*/ */
class DeviceNetwork : public Device class DeviceNetwork : public Device
{ {
public: public:
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~DeviceNetwork() { closeDevice(); } ~DeviceNetwork() { closeDevice(); }
@@ -181,21 +182,21 @@ private:
}; };
/** /**
* @brief Wrapper class for class Device. * @brief wrapper class for class device.
*/ */
class Port class Port
{ {
public: public:
/** /**
* @brief Constructs a new instance and determine device type. * @brief constructs a new instance and determine device type.
* @param deviceName to determine device type. * @param deviceName to determine device type.
* @param noDeviceCheck en-/disable device check. * @param noDeviceCheck en-/disable device check.
*/ */
Port(const std::string deviceName, const bool noDeviceCheck); Port(const std::string deviceName, const bool noDeviceCheck);
/** /**
* @brief Destructor. * @brief destructor.
*/ */
~Port() { delete m_device; } ~Port() { delete m_device; }
@@ -248,8 +249,10 @@ public:
private: private:
/** the device name */ /** the device name */
std::string m_deviceName; std::string m_deviceName;
/** the device instance */ /** the device instance */
Device* m_device; Device* m_device;
/** true if device check is disabled */ /** true if device check is disabled */
bool m_noDeviceCheck; bool m_noDeviceCheck;
@@ -261,7 +264,4 @@ private:
}; };
} //namespace
#endif // LIBEBUS_PORT_H_ #endif // LIBEBUS_PORT_H_
+1 -6
View File
@@ -19,10 +19,7 @@
#include "result.h" #include "result.h"
namespace libebus const char* getResultCode(result_t resultCode) {
{
const char* getResultCodeCStr(result_t resultCode) {
switch (resultCode) { switch (resultCode) {
case RESULT_ERR_SEND: return "ERR_SEND: send error"; case RESULT_ERR_SEND: return "ERR_SEND: send error";
case RESULT_ERR_EXTRA_DATA: return "ERR_EXTRA_DATA: received bytes > sent bytes"; case RESULT_ERR_EXTRA_DATA: return "ERR_EXTRA_DATA: received bytes > sent bytes";
@@ -43,5 +40,3 @@ const char* getResultCodeCStr(result_t resultCode) {
} }
} }
} //namespace
+1 -8
View File
@@ -20,10 +20,6 @@
#ifndef LIBEBUS_RESULT_H_ #ifndef LIBEBUS_RESULT_H_
#define LIBEBUS_RESULT_H_ #define LIBEBUS_RESULT_H_
namespace libebus
{
static const int RESULT_OK = 0; static const int RESULT_OK = 0;
static const int RESULT_BUS_ACQUIRED = 1; // bus successfully acquired static const int RESULT_BUS_ACQUIRED = 1; // bus successfully acquired
@@ -54,9 +50,6 @@ typedef int result_t;
* @param resultCode the result code (see RESULT_ constants). * @param resultCode the result code (see RESULT_ constants).
* @return the string corresponding to the result code. * @return the string corresponding to the result code.
*/ */
const char* getResultCodeCStr(result_t resultCode); const char* getResultCode(result_t resultCode);
} //namespace
#endif // LIBEBUS_RESULT_H_ #endif // LIBEBUS_RESULT_H_
-4
View File
@@ -22,9 +22,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
namespace libebus
{
/** /**
* @brief CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1. * @brief CRC8 lookup table for the polynom 0x9b = x^8 + x^7 + x^4 + x^3 + x^1 + 1.
*/ */
@@ -190,4 +187,3 @@ bool isMaster(unsigned char addr) {
&& ((addrLo == 0x0) || (addrLo == 0x1) || (addrLo == 0x3) || (addrLo == 0x7) || (addrLo == 0xF)); && ((addrLo == 0x0) || (addrLo == 0x1) || (addrLo == 0x3) || (addrLo == 0x7) || (addrLo == 0xF));
} }
} //namespace
-7
View File
@@ -25,10 +25,6 @@
#include <sstream> #include <sstream>
#include <queue> #include <queue>
namespace libebus
{
static const unsigned char ESC = 0xA9; // escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA static const unsigned char ESC = 0xA9; // escape symbol, either followed by 0x00 for the value 0xA9, or 0x01 for the value 0xAA
static const unsigned char SYN = 0xAA; // synchronization symbol static const unsigned char SYN = 0xAA; // synchronization symbol
static const unsigned char ACK = 0x00; // positive acknowledge static const unsigned char ACK = 0x00; // positive acknowledge
@@ -139,7 +135,4 @@ private:
*/ */
bool isMaster(unsigned char addr); bool isMaster(unsigned char addr);
} //namespace
#endif // LIBEBUS_SYMBOL_H_ #endif // LIBEBUS_SYMBOL_H_
-2
View File
@@ -25,8 +25,6 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
using namespace libebus;
// will be part of cfg csv class // will be part of cfg csv class
void readCSV(std::istream& is, Commands& commands){ void readCSV(std::istream& is, Commands& commands){
std::string line; std::string line;
-3
View File
@@ -24,9 +24,6 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
using namespace libebus;
int main() { int main() {
std::string dir("test"); std::string dir("test");
Regular → Executable
+3 -5
View File
@@ -21,8 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
using namespace libebus;
void verify(bool expectFailMatch, std::string type, std::string input, void verify(bool expectFailMatch, std::string type, std::string input,
bool match, std::string expectStr, std::string gotStr) bool match, std::string expectStr, std::string gotStr)
{ {
@@ -217,7 +215,7 @@ int main()
if (result != RESULT_OK) { if (result != RESULT_OK) {
std::cout << "\"" << check[0] << "\": create error: " std::cout << "\"" << check[0] << "\": create error: "
<< getResultCodeCStr(result) << std::endl; << getResultCode(result) << std::endl;
continue; continue;
} }
if (fields == NULL) { if (fields == NULL) {
@@ -256,7 +254,7 @@ int main()
<< check[2] << "< OK" << std::endl; << check[2] << "< OK" << std::endl;
else if (result != RESULT_OK) { else if (result != RESULT_OK) {
std::cout << " read " << fields->getName() << " >" << check[2] << "< error: " std::cout << " read " << fields->getName() << " >" << check[2] << "< error: "
<< getResultCodeCStr(result) << std::endl; << getResultCode(result) << std::endl;
} }
else { else {
bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0; bool match = strcasecmp(output.str().c_str(), expectStr.c_str()) == 0;
@@ -276,7 +274,7 @@ int main()
} }
else if (result != RESULT_OK) { else if (result != RESULT_OK) {
std::cout << " write " << fields->getName() << " >" std::cout << " write " << fields->getName() << " >"
<< expectStr << "< error: " << getResultCodeCStr(result) << std::endl; << expectStr << "< error: " << getResultCode(result) << std::endl;
} }
else { else {
bool match = mstr == writeMstr && sstr == writeSstr; bool match = mstr == writeMstr && sstr == writeSstr;
-4
View File
@@ -21,10 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
using namespace libebus;
int main() int main()
{ {
Decode* help_dec = NULL; Decode* help_dec = NULL;
-4
View File
@@ -21,10 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
using namespace libebus;
int main() int main()
{ {
Encode* help_enc = NULL; Encode* help_enc = NULL;
-2
View File
@@ -21,8 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
using namespace libebus;
int main () int main ()
{ {
std::string dev("/dev/ttyUSB20"); std::string dev("/dev/ttyUSB20");
-2
View File
@@ -21,8 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
using namespace libebus;
int main () int main ()
{ {
SymbolString sstr = SymbolString("10feb5050427a915aa"); SymbolString sstr = SymbolString("10feb5050427a915aa");
+7 -5
View File
@@ -4,18 +4,20 @@ AM_CXXFLAGS = -fpic \
noinst_LIBRARIES = libutils.a noinst_LIBRARIES = libutils.a
libutils_a_SOURCES = wqueue.h \ libutils_a_SOURCES = appl.cpp \
notify.h \
appl.cpp \
appl.h \ appl.h \
daemon.cpp \ daemon.cpp \
daemon.h \ daemon.h \
logger.cpp \ logger.cpp \
logger.h \ logger.h \
notify.cpp \
notify.h \
tcpsocket.cpp \
tcpsocket.h \
thread.cpp \ thread.cpp \
thread.h \ thread.h \
tcpsocket.cpp \ wqueue.h
tcpsocket.h
distclean-local: distclean-local:
-rm -f Makefile.in -rm -f Makefile.in
+150 -121
View File
@@ -22,200 +22,229 @@
#include <iomanip> #include <iomanip>
#include <cstdlib> #include <cstdlib>
Appl& Appl::Instance() Appl& Appl::Instance(const bool command)
{ {
static Appl instance; static Appl instance(command);
return instance; return instance;
} }
Appl::~Appl() Appl::~Appl()
{ {
m_args.clear(); m_opts.clear();
m_params.clear(); m_optvals.clear();
} }
void Appl::addArgs(const std::string argTxt, const int argNum) void Appl::addText(const char* text)
{ {
m_argTxt = argTxt; opt_t opt;
m_argNum = argNum; opt.name = "__text_only__";
opt.shortname = "";
opt.datatype = dt_none;
opt.optiontype = ot_none;
opt.description = text;
m_opts.push_back(opt);
} }
void Appl::addItem(const char* name, Param param, const char* shortname, void Appl::addOption(const char* name, const char* shortname, OptVal optval,
const char* longname, const char* description, DataType datatype, OptionType optiontype, const char* description)
Datatype datatype, Optiontype optiontype)
{ {
if (strlen(name) != 0) if (strlen(name) != 0) {
m_params[name] = param;
if (strlen(longname) != 0) { m_optvals[name] = optval;
Arg arg;
arg.name = name; opt_t opt;
arg.shortname = shortname; opt.name = name;
arg.longname = longname; opt.shortname = shortname;
arg.description = description; opt.datatype = datatype;
arg.datatype = datatype; opt.optiontype = optiontype;
arg.optiontype = optiontype; opt.description = description;
m_args.push_back(arg); m_opts.push_back(opt);
} }
} }
void Appl::printArgs() void Appl::parseArgs(int argc, char* argv[])
{
std::cerr << std::endl << "Usage:" << std::endl << " "
<< m_argv[0].substr(m_argv[0].find_last_of("/\\") + 1) << " [OPTIONS...]" ;
if (m_argTxt.size() != 0)
std::cerr << " " << m_argTxt;
std::cerr << std::endl << std::endl << "Options:" << std::endl << std::endl;
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " ";
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << a_it->longname
<< "\t" << a_it->description
<< std::endl;
}
std::cerr << std::endl;
}
bool Appl::parseArgs(int argc, char* argv[])
{ {
std::vector<std::string> _argv(argv, argv + argc); std::vector<std::string> _argv(argv, argv + argc);
m_argc = argc;
m_argv = _argv; m_argv = _argv;
for (size_t i = 1; i < m_argc; i++) { // walk through all arguments
for (int i = 1; i < argc; i++) {
// find option with long format '--' // find option with long format '--'
if (m_argv[i].rfind("--") == 0 && m_argv[i].size() > 2) { if (_argv[i].rfind("--") == 0 && _argv[i].size() > 2) {
// is next item an added argument? // is next item an added argument?
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos) { if (i+1 < argc && _argv[i+1].rfind("-", 0) == std::string::npos) {
if (checkArg(m_argv[i].substr(2), m_argv[i+1]) == false) if (checkOption(_argv[i].substr(2), _argv[i+1]) == false)
return false; printHelp();
} else { }
if (checkArg(m_argv[i].substr(2), "") == false) else {
return false; if (checkOption(_argv[i].substr(2), "") == false)
printHelp();
} }
// find option with short format '-' // find option with short format '-'
} else if (m_argv[i].rfind("-") == 0 && m_argv[i].size() > 1) { } else if (_argv[i].rfind("-") == 0 && _argv[i].size() > 1) {
// walk through all characters // walk through all characters
for (size_t j = 1; j < m_argv[i].size(); j++) { for (size_t j = 1; j < _argv[i].size(); j++) {
// only last charater could have an argument // only last charater could have an argument
if (i+1 < m_argc && m_argv[i+1].rfind("-", 0) == std::string::npos if (i+1 < argc && _argv[i+1].rfind("-", 0) == std::string::npos
&& j+1 == m_argv[i].size()) { && j+1 == _argv[i].size()) {
if (checkArg(m_argv[i].substr(j,1), m_argv[i+1]) == false) if (checkOption(_argv[i].substr(j,1), _argv[i+1]) == false)
return false; printHelp();
} else { }
if (checkArg(m_argv[i].substr(j,1), "") == false) else {
return false; if (checkOption(_argv[i].substr(j,1), "") == false)
printHelp();
} }
} }
} }
} }
// check args // check command
if (m_argNum > 0) { if (m_needCommand == true) {
if (m_argc < (m_argNum + 1)) for (int i = 1; i < argc; i++) {
return false;
for (size_t i = 1; i < m_argc; i++) { if (_argv[i].rfind("-", 0) != std::string::npos) {
if (m_argv[i].rfind("-", 0) != std::string::npos) {
i++; i++;
continue; continue;
} }
m_argValues.push_back(m_argv[i]); m_arguments.push_back(_argv[i]);
} }
if (m_argValues.size() < m_argNum) if (m_arguments.size() == 0) {
return false; std::cerr << std::endl << "command needed" << std::endl;
printHelp();
}
} }
return true;
} }
void Appl::printSettings() bool Appl::checkOption(const std::string& option, const std::string& value)
{ {
std::cerr << std::endl << "Settings:" << std::endl; if (strcmp(option.c_str(), "settings") == 0)
printSettings();
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) { if (strcmp(option.c_str(), "v") == 0 || strcmp(option.c_str(), "version") == 0)
const char* c = (strlen(a_it->shortname) == 1) ? a_it->shortname : " "; printVersion();
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << a_it->longname
<< " = ";
if (a_it->datatype == type_bool) {
if (getParam<bool>(a_it->name) == true)
std::cerr << "yes" << std::endl;
else
std::cerr << "no" << std::endl;
}
else if (a_it->datatype == type_int) {
std::cerr << getParam<int>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_long) {
std::cerr << getParam<long>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_float) {
std::cerr << getParam<float>(a_it->name) << std::endl;
}
else if (a_it->datatype == type_string) {
std::cerr << getParam<const char*>(a_it->name) << std::endl;
}
} if (strcmp(option.c_str(), "h") == 0 || strcmp(option.c_str(), "help") == 0)
printHelp();
std::cerr << std::endl; for (o_it = m_opts.begin(); o_it < m_opts.end(); o_it++) {
} if (o_it->shortname == option || o_it->name == option) {
bool Appl::checkArg(const std::string& name, const std::string& arg) // need this option and argument?
{ if (o_it->optiontype == ot_mandatory && value.size() == 0) {
for (a_it = m_args.begin(); a_it < m_args.end(); a_it++) {
if (a_it->shortname == name || a_it->longname == name) {
if (a_it->optiontype == opt_mandatory && arg.size() == 0) {
std::cerr << std::endl << "option requires an argument '" std::cerr << std::endl << "option requires an argument '"
<< name << "'" << std::endl; << option << "'" << std::endl;
return false; return false;
} }
if ((a_it->optiontype == opt_optional && arg.size() != 0) // add given value to option
|| a_it->optiontype != opt_optional) if ((o_it->optiontype == ot_optional && value.size() != 0)
addParam(a_it->name, arg, a_it->datatype); || o_it->optiontype != ot_optional)
setOptVal(o_it->name, value, o_it->datatype);
return true; return true;
} }
} }
std::cerr << m_argv[0].substr(2) << ": Unknown Option -- " << name << std::endl; std::cerr << std::endl << "unknown option '" << option << "'" << std::endl;
return false; return false;
} }
void Appl::addParam(const char* name, const std::string arg, Datatype datatype) void Appl::setOptVal(const char* option, const std::string value, DataType datatype)
{ {
switch (datatype) { switch (datatype) {
case type_bool: case dt_bool:
m_params[name] = true; m_optvals[option] = true;
break; break;
case type_int: case dt_int:
m_params[name] = strtol(arg.c_str(), NULL, 10); m_optvals[option] = strtol(value.c_str(), NULL, 10);
break; break;
case type_long: case dt_long:
m_params[name] = strtol(arg.c_str(), NULL, 10); m_optvals[option] = strtol(value.c_str(), NULL, 10);
break; break;
case type_float: case dt_float:
m_params[name] = static_cast<float>(strtod(arg.c_str(), NULL)); m_optvals[option] = static_cast<float>(strtod(value.c_str(), NULL));
break; break;
case type_string: case dt_string:
m_params[name] = arg.c_str(); m_optvals[option] = value.c_str();
break; break;
default: default:
break; break;
} }
} }
void Appl::printVersion()
{
std::cerr << m_version << std::endl;
exit(EXIT_SUCCESS);
}
void Appl::printHelp()
{
std::cerr << std::endl << "Usage:" << std::endl << " "
<< m_argv[0].substr(m_argv[0].find_last_of("/\\") + 1) << " [OPTIONS...]" ;
if (m_needCommand == true)
std::cerr << " COMMAND {ARGS...}" << std::endl << std::endl;
else
std::cerr << std::endl << std::endl;
for (o_it = m_opts.begin(); o_it < m_opts.end(); o_it++) {
if (strcmp(o_it->name, "__text_only__") == 0)
std::cerr << o_it->description << std::endl;
else {
const char* c = (strlen(o_it->shortname) == 1) ? o_it->shortname : " ";
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << o_it->name
<< "\t" << o_it->description
<< std::endl;
}
}
std::cerr << " | --settings\n-v | --version\n-h | --help" << std::endl << std::endl;
exit(EXIT_SUCCESS);
}
void Appl::printSettings()
{
std::cerr << std::endl << "Settings:" << std::endl << std::endl;
for (o_it = m_opts.begin(); o_it < m_opts.end(); o_it++) {
if (strcmp(o_it->name, "__text_only__") == 0)
continue;
const char* c = (strlen(o_it->shortname) == 1) ? o_it->shortname : " ";
std::cerr << ((strcmp(c, " ") == 0) ? " " : "-") << c
<< " | --" << o_it->name
<< " = ";
if (o_it->datatype == dt_bool) {
if (getOptVal<bool>(o_it->name) == true)
std::cerr << "yes" << std::endl;
else
std::cerr << "no" << std::endl;
}
else if (o_it->datatype == dt_int) {
std::cerr << getOptVal<int>(o_it->name) << std::endl;
}
else if (o_it->datatype == dt_long) {
std::cerr << getOptVal<long>(o_it->name) << std::endl;
}
else if (o_it->datatype == dt_float) {
std::cerr << getOptVal<float>(o_it->name) << std::endl;
}
else if (o_it->datatype == dt_string) {
std::cerr << getOptVal<const char*>(o_it->name) << std::endl;
}
}
std::cerr << std::endl;
exit(EXIT_SUCCESS);
}
+153 -62
View File
@@ -17,96 +17,187 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_APPL_H_ #ifndef LIBUTILS_APPL_H_
#define LIBCORE_APPL_H_ #define LIBUTILS_APPL_H_
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <vector> #include <vector>
/** the available data types. */
enum DataType {
dt_none, // default value
dt_bool, //
dt_int, //
dt_long, //
dt_float, //
dt_string, //
};
/** option types. */
enum OptionType {
ot_none, // default value
ot_optional, // a value is optional
ot_mandatory, // a value is mandatory
};
/** structure for defining application options */
typedef struct opt {
const char* name;
const char* shortname;
const char* description;
DataType datatype;
OptionType optiontype;
} opt_t;
/** union for option values */
union OptVal {
bool b;
int i;
long l;
float f;
const char* c;
OptVal() { memset(this, 0, sizeof(OptVal)); }
OptVal(bool _b) : b(_b) {}
OptVal(int _i) : i(_i) {}
OptVal(long _l) : l(_l) {}
OptVal(float _f) : f(_f) {}
OptVal(const char* _c) : c(_c) {}
};
/**
* @brief class for all kinds of application parameters.
*/
class Appl class Appl
{ {
private:
struct Option;
public: public:
enum Datatype { type_none, type_bool, type_int, type_long, type_float, type_string }; /**
enum Optiontype { opt_none, opt_optional, opt_mandatory }; * @brief create an instance and return the reference.
* @param command is true if an command is needed.
union Param { * @return the reference to instance.
bool b; */
int i; static Appl& Instance(const bool command=false);
long l;
float f;
const char* c;
Param() { memset(this, 0, sizeof(Param)); }
Param(bool _b) : b(_b) {}
Param(int _i) : i(_i) {}
Param(long _l) : l(_l) {}
Param(float _f) : f(_f) {}
Param(const char* _c) : c(_c) {}
};
template <typename T>
T getParam(const char* name)
{
p_it = m_params.find(name);
return (reinterpret_cast<T&>(p_it->second));
}
static Appl& Instance();
/**
* @brief destructor.
*/
~Appl(); ~Appl();
void addArgs(const std::string argTxt, const int argNum); /**
size_t numArg() const { return m_argValues.size(); } * @brief save application version string.
std::string getArg(const int argNum) const { return m_argValues[argNum]; } * @param version string.
*/
void setVersion(const char* version) { m_version = version; }
void addItem(const char* name, Param param, const char* shortname, /**
const char* longname, const char* description, * @brief create new entry of application option only for help page.
Datatype datatype, Optiontype optiontype); * @param text string to print.
*/
void addText(const char* text);
void printArgs(); /**
* @brief create new entry of application option.
* @param name the long name.
* @param shortname optional short name.
* @param optval value of option.
* @param datatype data type of option value.
* @param optiontype type of given option.
* @param description hint text for help page.
*/
void addOption(const char* name, const char* shortname, OptVal optval,
DataType datatype, OptionType optiontype, const char* description);
bool parseArgs(int argc, char* argv[]); /**
void printSettings(); * @brief returns the value of the interested option.
* @param name the interested option.
* @return casted value.
*/
template <typename T>
T getOptVal(const char* name)
{
ov_it = m_optvals.find(name);
return (reinterpret_cast<T&>(ov_it->second));
}
/**
* @brief parse application arguments.
* @param argc the number of options.
* @param argv the given options.
*/
void parseArgs(int argc, char* argv[]);
/**
* @brief returns the number of saved commands and arguments.
* @return number of commands and arguments.
*/
int numArgs() const { return m_arguments.size(); }
/**
* @brief returns the string of an interested argument (0 = command).
* @param num number of interested argument.
* @return string value.
*/
std::string getArg(const int num) const { return m_arguments[num]; }
private: private:
Appl() {} /** private constructor - singleton pattern */
Appl(const bool command) : m_needCommand(command) {}
Appl(const Appl&); Appl(const Appl&);
Appl& operator= (const Appl&); Appl& operator=(const Appl&);
struct Arg { /** application options */
const char* name; std::vector<opt_t> m_opts;
const char* shortname; std::vector<opt_t>::const_iterator o_it;
const char* longname;
const char* description;
Datatype datatype;
Optiontype optiontype;
};
size_t m_argc; /** map option - value */
std::map<const char*, OptVal> m_optvals;
std::map<const char*, OptVal>::iterator ov_it;
/** given arguments */
std::vector<std::string> m_argv; std::vector<std::string> m_argv;
std::vector<Arg> m_args; /** application version string */
std::vector<Arg>::const_iterator a_it; const char* m_version;
std::map<const char*, Param> m_params; /** true if the application need a command */
std::map<const char*, Param>::iterator p_it; bool m_needCommand;
std::string m_argTxt; /** arguments (argument 0 = command) string */
size_t m_argNum; std::vector<std::string> m_arguments;
std::vector<std::string> m_argValues; /**
* @brief checks the passed parameter if this is a valid option.
* @param option to check.
* @param value to save if paramter is a valid option.
*/
bool checkOption(const std::string& option, const std::string& value);
bool checkArg(const std::string& name, const std::string& arg); /**
* @brief save the passed value to option.
* @param option name.
* @param value to save.
* @param datatype of given option.
*/
void setOptVal(const char* option, const std::string value, DataType datatype);
void addParam(const char* name, Param param) { m_params[name] = param; } /**
* @brief print application version.
*/
void printVersion();
void addParam(const char* name, const std::string arg, Datatype datatype); /**
* @brief print help page.
*/
void printHelp();
/**
* @brief print used option settings.
*/
void printSettings();
}; };
#endif // LIBCORE_APPL_H_ #endif // LIBUTILS_APPL_H_
+2 -2
View File
@@ -32,10 +32,10 @@ Daemon& Daemon::Instance()
return instance; return instance;
} }
void Daemon::run(const char* file) void Daemon::run(const char* pidfile)
{ {
m_status = false; m_status = false;
m_pidfile = file; m_pidfile = pidfile;
m_pidfd = 0; m_pidfd = 0;
pid_t pid; pid_t pid;
+44 -10
View File
@@ -17,32 +17,66 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_DAEMON_H_ #ifndef LIBUTILS_DAEMON_H_
#define LIBCORE_DAEMON_H_ #define LIBUTILS_DAEMON_H_
/**
* @brief class to daemonize a process.
*/
class Daemon class Daemon
{ {
public: public:
/**
* @brief create an instance and return the reference.
* @return the reference to instance.
*/
static Daemon& Instance(); static Daemon& Instance();
~Daemon() {}
void run(const char* file); /**
* @brief daemonize act process.
* @param pidfile the name of the pid file.
*/
void run(const char* pidfile);
/**
* @brief stop daemon and delete the pid file.
*/
void stop() { pidfile_close(); } void stop() { pidfile_close(); }
/**
* @brief show actual status if daemonize.
* @return true if process is a daemon.
*/
bool status() { return m_status; } bool status() { return m_status; }
private: private:
bool m_status; /** private constructor - singleton pattern */
const char* m_pidfile;
int m_pidfd;
Daemon() {} Daemon() {}
Daemon(const Daemon&); Daemon(const Daemon&);
Daemon& operator= (const Daemon&); Daemon& operator=(const Daemon&);
/** status of process; true if we are a daemon */
bool m_status;
/** name of the pid file*/
const char* m_pidfile;
/** file descriptor of the pid file */
int m_pidfd;
/**
* @brief creates a pid file for process.
* @return true if success.
*/
bool pidfile_open(); bool pidfile_open();
/**
* @brief close and delete the pid file.
* @return true if success.
*/
bool pidfile_close(); bool pidfile_close();
}; };
#endif // LIBCORE_DAEMON_H_ #endif // LIBUTILS_DAEMON_H_
+26 -25
View File
@@ -28,7 +28,10 @@
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
/** static char array with logging area names */
static const char* AreaNames[Size_of_Areas] = { "bas", "net", "bus" }; static const char* AreaNames[Size_of_Areas] = { "bas", "net", "bus" };
/** static char array with logging level names */
static const char* LevelNames[Size_of_Level] = { "error", "event", "trace", "debug" }; static const char* LevelNames[Size_of_Level] = { "error", "event", "trace", "debug" };
int calcAreas(const std::string areas) int calcAreas(const std::string areas)
@@ -66,8 +69,8 @@ int calcLevel(const std::string level)
} }
LogMessage::LogMessage(const int area, const int level, const std::string text, const Status status) LogMessage::LogMessage(const int area, const int level, const std::string text, const bool running)
: m_area(area), m_level(level), m_text(text), m_status(status) : m_area(area), m_level(level), m_text(text), m_running(running)
{ {
char time[24]; char time[24];
struct timeval tv; struct timeval tv;
@@ -89,17 +92,17 @@ LogMessage::LogMessage(const int area, const int level, const std::string text,
void LogSink::addMessage(const LogMessage& message) void LogSink::addMessage(const LogMessage& message)
{ {
LogMessage* tmp = new LogMessage(LogMessage(message)); LogMessage* tmp = new LogMessage(LogMessage(message));
m_queue.add((tmp)); m_logQueue.add((tmp));
} }
void* LogSink::run() void* LogSink::run()
{ {
while (1) { while (1) {
LogMessage* message = m_queue.remove(); LogMessage* message = m_logQueue.remove();
if (message->getStatus() == LogMessage::End) { if (message->isRunning() == false) {
delete message; delete message;
while (m_queue.size() == true) { while (m_logQueue.size() == true) {
LogMessage* message = m_queue.remove(); LogMessage* message = m_logQueue.remove();
write(*message); write(*message);
delete message; delete message;
} }
@@ -114,8 +117,6 @@ void* LogSink::run()
int LogConsole::m_numInstance = 0;
void LogConsole::write(const LogMessage& message) const void LogConsole::write(const LogMessage& message) const
{ {
std::cout << message.getTime() << " [" std::cout << message.getTime() << " ["
@@ -126,11 +127,9 @@ void LogConsole::write(const LogMessage& message) const
int LogFile::m_numInstance = 0;
void LogFile::write(const LogMessage& message) const void LogFile::write(const LogMessage& message) const
{ {
std::fstream file(m_filename.c_str(), std::ios::out | std::ios::app); std::fstream file(m_file.c_str(), std::ios::out | std::ios::app);
if (file.is_open() == true) { if (file.is_open() == true) {
file << message.getTime() << " [" file << message.getTime() << " ["
@@ -143,19 +142,19 @@ void LogFile::write(const LogMessage& message) const
LogInstance& LogInstance::Instance() Logger& Logger::Instance()
{ {
static LogInstance instance; static Logger instance;
return (instance); return (instance);
} }
LogInstance::~LogInstance() Logger::~Logger()
{ {
while (m_sinks.empty() == false) while (m_sinks.empty() == false)
*this -= *(m_sinks.begin()); *this -= *(m_sinks.begin());
} }
LogInstance& LogInstance::operator+= (LogSink* sink) Logger& Logger::operator+=(LogSink* sink)
{ {
sinkCI_t itEnd = m_sinks.end(); sinkCI_t itEnd = m_sinks.end();
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink); sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
@@ -166,7 +165,7 @@ LogInstance& LogInstance::operator+= (LogSink* sink)
return (*this); return (*this);
} }
LogInstance& LogInstance::operator-= (const LogSink* sink) Logger& Logger::operator-=(const LogSink* sink)
{ {
sinkCI_t itEnd = m_sinks.end(); sinkCI_t itEnd = m_sinks.end();
sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink); sinkCI_t it = std::find(m_sinks.begin(), itEnd, sink);
@@ -181,7 +180,7 @@ LogInstance& LogInstance::operator-= (const LogSink* sink)
return (*this); return (*this);
} }
void LogInstance::log(const int area, const int level, const std::string& data, ...) void Logger::log(const int area, const int level, const std::string& data, ...)
{ {
if (m_running == true) { if (m_running == true) {
char* tmp; char* tmp;
@@ -190,7 +189,7 @@ void LogInstance::log(const int area, const int level, const std::string& data,
if (vasprintf(&tmp, data.c_str(), ap) != -1) { if (vasprintf(&tmp, data.c_str(), ap) != -1) {
std::string buffer(tmp); std::string buffer(tmp);
m_messages.add(new LogMessage(LogMessage(area, level, buffer, LogMessage::Run))); m_logQueue.add(new LogMessage(area, level, buffer));
} }
va_end(ap); va_end(ap);
@@ -199,12 +198,12 @@ void LogInstance::log(const int area, const int level, const std::string& data,
} }
void* LogInstance::run() void* Logger::run()
{ {
m_running = true; m_running = true;
while (m_running == true) { while (m_running == true) {
LogMessage* message = m_messages.remove(); LogMessage* message = m_logQueue.remove();
sinkCI_t iter = m_sinks.begin(); sinkCI_t iter = m_sinks.begin();
@@ -213,13 +212,15 @@ void* LogInstance::run()
if (((*iter)->getAreas() & message->getArea() if (((*iter)->getAreas() & message->getArea()
&& (*iter)->getLevel() >= message->getLevel()) && (*iter)->getLevel() >= message->getLevel())
&& message->getStatus() == LogMessage::Run) { && message->isRunning() == true) {
(*iter)->addMessage(*message); (*iter)->addMessage(*message);
} else if (message->getStatus() == LogMessage::End) { }
else if (message->isRunning() == false) {
(*iter)->addMessage(*message); (*iter)->addMessage(*message);
m_running = false; m_running = false;
} }
} }
} }
@@ -229,8 +230,8 @@ void* LogInstance::run()
return NULL; return NULL;
} }
void LogInstance::stop() void Logger::stop()
{ {
m_messages.add(new LogMessage(LogMessage(bas, error, "", LogMessage::End))); m_logQueue.add(new LogMessage(LogMessage(bas, error, "", false)));
usleep(100000); usleep(100000);
} }
+201 -60
View File
@@ -17,8 +17,8 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_LOGGER_H_ #ifndef LIBUTILS_LOGGER_H_
#define LIBCORE_LOGGER_H_ #define LIBUTILS_LOGGER_H_
#include "wqueue.h" #include "wqueue.h"
#include "thread.h" #include "thread.h"
@@ -28,154 +28,295 @@
#include <vector> #include <vector>
#include <cstdarg> #include <cstdarg>
enum Areas { bas=1, net=2, bus=4, all=7, Size_of_Areas=3 }; /** available types for all subsystems */
enum Level { error=0, event, trace, debug, Size_of_Level }; enum AreasType {
bas=1, // basis
net=2, // network
bus=4, // ebus
all=7, // type for all subsystems
Size_of_Areas=3, // number of possible areas
};
/** available logging levels */
enum LevelType {
error=0, //
event, //
trace, //
debug, //
Size_of_Level, // number of possible levels
};
/** global function to get calculate logging areas */
int calcAreas(const std::string areas); int calcAreas(const std::string areas);
/** global function to get calculate logging level */
int calcLevel(const std::string level); int calcLevel(const std::string level);
/**
* @brief class which describes a logging message itself.
*/
class LogMessage class LogMessage
{ {
public: public:
enum Status { Run, End }; /**
* @brief creates a new logging message.
LogMessage(const int area, const int level, const std::string text, const Status status); * @param area the logging area of the message.
* @param level the logging level of the message.
~LogMessage() {} * @param text the logging message.
* @param running the status of logging subsystem.
LogMessage(const LogMessage& src) */
: m_area(src.m_area), m_level(src.m_level), m_text(src.m_text), LogMessage(const int area, const int level, const std::string text, const bool running=true);
m_status(src.m_status), m_time(src.m_time) {}
void operator= (const LogMessage& src)
{ m_area = src.m_area; m_level = src.m_level; m_text = src.m_text;
m_status = src.m_status; m_time = src.m_time; }
/**
* @brief get the logging area.
* @return the logging area.
*/
int getArea() const { return (m_area); } int getArea() const { return (m_area); }
/**
* @brief get the logging level.
* @return the logging level.
*/
int getLevel() const { return(m_level); } int getLevel() const { return(m_level); }
/**
* @brief get the logging text.
* @return the logging text.
*/
std::string getText() const { return (m_text.c_str()); } std::string getText() const { return (m_text.c_str()); }
Status getStatus() const { return (m_status); }
/**
* @brief status of logging subsystem.
* @return false if logging subsystem is going down.
*/
bool isRunning() const { return m_running; }
/**
* @brief get the logging timestamp.
* @return the logging timestamp.
*/
std::string getTime() const { return (m_time.c_str()); } std::string getTime() const { return (m_time.c_str()); }
private: private:
/** the logging area */
int m_area; int m_area;
/** the logging level */
int m_level; int m_level;
/** the logging message */
std::string m_text; std::string m_text;
Status m_status;
/** true if this instance is running */
bool m_running;
/** the logging timestamp */
std::string m_time; std::string m_time;
}; };
enum Type { Console, Logfile }; /**
* @brief base class for all type of logging sinks.
*/
class LogSink : public Thread class LogSink : public Thread
{ {
public: public:
LogSink(const int areas, const int level, const Type type, const char* name) /**
: m_areas(areas), m_level(level), m_type(type), m_name(name) {} * @brief creates a virtual logging sink.
* @param areas the logging areas.
virtual ~LogSink() {} * @param level the logging level.
*/
LogSink(const int areas, const int level) : m_areas(areas), m_level(level) {}
/**
* @brief adds the logging message to internal message queue.
* @param message a reference to logging message.
*/
void addMessage(const LogMessage& message); void addMessage(const LogMessage& message);
/**
* @brief endless loop for logging sink instance.
* @return void pointer.
*/
void* run(); void* run();
/**
* @brief get the logging areas.
* @return the logging areas.
*/
int getAreas() const { return (m_areas); } int getAreas() const { return (m_areas); }
/**
* @brief set the logging areas.
* @param areas the logging areas.
*/
void setAreas(const int& areas) { m_areas = areas; } void setAreas(const int& areas) { m_areas = areas; }
/**
* @brief get the logging level.
* @return the logging level.
*/
int getLevel() const { return (m_level); } int getLevel() const { return (m_level); }
/**
* @brief set the logging level.
* @param level the logging level.
*/
void setLevel(const int& level) { m_level = level; } void setLevel(const int& level) { m_level = level; }
Type getType() const { return (m_type); }
const char* getName() const { return (m_name.c_str()); }
protected: protected:
WQueue<LogMessage*> m_queue; /** queue for logging messages */
WQueue<LogMessage*> m_logQueue;
private: private:
/** the logging areas */
int m_areas; int m_areas;
int m_level;
Type m_type;
std::string m_name;
/** the logging level */
int m_level;
/**
* @brief virtual function for writing the logging message.
* @param message the logging message.
*/
virtual void write(const LogMessage& message) const = 0; virtual void write(const LogMessage& message) const = 0;
}; };
/**
* @brief class for console logging sink type.
*/
class LogConsole : public LogSink class LogConsole : public LogSink
{ {
public: public:
/**
* @brief creates a console logging sink.
* @param areas the logging areas.
* @param level the logging level.
* @param name the thread name for logging sink.
*/
LogConsole(const int areas, const int level, const char* name) LogConsole(const int areas, const int level, const char* name)
: LogSink(areas, level, Console, name), m_instance(++m_numInstance) : LogSink(areas, level) { this->start(name); }
{ this->start(name); }
~LogConsole() {}
private: private:
const int m_instance; /**
static int m_numInstance; * @brief write the logging message to stdout.
* @param message the logging message.
*/
void write(const LogMessage& message) const; void write(const LogMessage& message) const;
}; };
/**
* @brief class for logfile logging sink type.
*/
class LogFile : public LogSink class LogFile : public LogSink
{ {
public: public:
LogFile(const int areas, const int level, const char* name, const char* filename) /**
: LogSink(areas, level, Logfile, name), m_filename(filename), m_instance(++m_numInstance) * @brief creates a log file logging sink.
{ this->start(name); } * @param areas the logging areas.
* @param level the logging level.
~LogFile() {} * @param name the thread name for logging sink.
* @param file the log file.
*/
LogFile(const int areas, const int level, const char* name, const char* file)
: LogSink(areas, level), m_file(file) { this->start(name); }
private: private:
std::string m_filename; /** the logging file */
const int m_instance; std::string m_file;
static int m_numInstance;
/**
* @brief write the logging message to specific log file.
* @param message the logging message.
*/
void write(const LogMessage& message) const; void write(const LogMessage& message) const;
}; };
class LogInstance : public Thread /**
* @brief logger base class which provide the logging interface.
*/
class Logger : public Thread
{ {
public: public:
static LogInstance& Instance(); /**
* @brief create an instance and return the reference.
* @return the reference to instance.
*/
static Logger& Instance();
~LogInstance(); /**
* @brief destructor.
*/
~Logger();
LogInstance& operator+= (LogSink* sink); /**
LogInstance& operator-= (const LogSink* sink); * @brief adds a logging sink and returns the reference to logger.
* @param pointer of logging sink.
* @return the reference to logger.
*/
Logger& operator+=(LogSink* sink);
/**
* @brief removes a logging sink and returns the reference to logger.
* @param pointer of logging sink.
* @return the reference to logger.
*/
Logger& operator-=(const LogSink* sink);
/**
* @brief creates a logging message and add them to internal message queue.
* @param area the logging area of the message.
* @param level the logging level of the message.
* @param text the logging message.
* @param ... possible 'variable argument lists'.
*/
void log(const int area, const int level, const std::string& text, ...); void log(const int area, const int level, const std::string& text, ...);
int getNumberOfSinks() const { return(m_sinks.size()); } /**
LogSink* getSink(const int Index) const { return(m_sinks[Index]); } * @brief returns the sink at the specified index.
* @param index the index of the sink to return.
* @return the sink at the specified index.
*/
LogSink* getSink(const int index) const { return(m_sinks[index]); }
/**
* @brief endless loop for logger instance.
* @return void pointer.
*/
void* run(); void* run();
/**
* @brief shutdown logger subsystem.
*/
void stop(); void stop();
private: private:
LogInstance() {} /** private constructor - singleton pattern */
LogInstance(const LogInstance&); Logger() {}
LogInstance& operator= (const LogInstance&); Logger(const Logger&);
Logger& operator=(const Logger&);
/** typedefs for a vector of type LogSink* */
typedef std::vector<LogSink*> sink_t; typedef std::vector<LogSink*> sink_t;
typedef std::vector<LogSink*>::iterator sinkCI_t; typedef std::vector<LogSink*>::iterator sinkCI_t;
/** vector of available logging sinks */
sink_t m_sinks; sink_t m_sinks;
WQueue<LogMessage*> m_messages; /** queue for logging messages */
WQueue<LogMessage*> m_logQueue;
/** true if this instance is running */
bool m_running; bool m_running;
}; };
#endif // LIBCORE_LOGGER_H_ #endif // LIBUTILS_LOGGER_H_
@@ -17,27 +17,26 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef MESSAGE_H_ #include "notify.h"
#define MESSAGE_H_
#include <string> Notify::Notify()
class Message
{ {
int pipefd[2];
int ret = pipe(pipefd);
public: if (ret == 0) {
Message(const std::string data, void* source = NULL) : m_data(data), m_source(source) {} m_recvfd = pipefd[0];
Message(const Message& src) : m_data(src.m_data), m_source(src.m_source) {} m_sendfd = pipefd[1];
std::string getData() const { return m_data; } fcntl(m_sendfd, F_SETFL, O_NONBLOCK);
void* getSource() const { return m_source; } }
private: }
std::string m_data;
void* m_source;
}; Notify::~Notify()
{
close(m_sendfd);
close(m_recvfd);
}
#endif // MESSAGE_H_
+28 -18
View File
@@ -17,40 +17,50 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_NOTIFY_H_ #ifndef LIBUTILS_NOTIFY_H_
#define LIBCORE_NOTIFY_H_ #define LIBUTILS_NOTIFY_H_
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
/**
* @brief class to notify other thread per pipe.
*/
class Notify class Notify
{ {
public: public:
Notify() /**
{ * @brief constructs a new instance and do notifying.
int pipefd[2]; */
int ret = pipe(pipefd); Notify();
if (ret == 0) { /**
m_recvfd = pipefd[0]; * @brief destructor.
m_sendfd = pipefd[1]; */
~Notify();
fcntl(m_sendfd, F_SETFL, O_NONBLOCK); /**
} * @brief file descriptor to watch for notify event.
* @return the notification value.
*/
int notifyFD() { return m_recvfd; }
} /**
virtual ~Notify() { close(m_sendfd); close(m_recvfd); } * @brief write notify event to file descriptor.
* @return result of writing notification.
int notifyFD() const { return m_recvfd; } */
int notify() const { return write(m_sendfd,"1",1); } int notify() const { return write(m_sendfd,"1",1); }
private: private:
int m_recvfd; /** file descriptor to watch */
int m_sendfd; int m_recvfd;
/** file descriptor to notify */
int m_sendfd;
}; };
#endif // LIBCORE_NOTIFY_H_ #endif // LIBUTILS_NOTIFY_H_
-4
View File
@@ -19,11 +19,7 @@
#include "tcpsocket.h" #include "tcpsocket.h"
#include <cstdlib> #include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <string.h> #include <string.h>
+91 -8
View File
@@ -17,72 +17,155 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_TCPSOCKET_H_ #ifndef LIBUTILS_TCPSOCKET_H_
#define LIBCORE_TCPSOCKET_H_ #define LIBUTILS_TCPSOCKET_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <string> #include <string>
/**
* @brief class for low level tcp socket operations. (open, close, send, receive).
*/
class TCPSocket class TCPSocket
{ {
public: public:
/** grant access for friend classes */
friend class TCPClient; friend class TCPClient;
friend class TCPServer; friend class TCPServer;
/**
* @brief destructor.
*/
~TCPSocket() { close(m_sfd); } ~TCPSocket() { close(m_sfd); }
ssize_t recv(char* buffer, size_t len) { return read(m_sfd, buffer, len); } /**
* @brief write bytes to opened file descriptor.
* @param buffer data to send.
* @param len number of bytes to send.
* @return number of written bytes or -1 if an error has occured.
*/
ssize_t send(const char* buffer, size_t len) { return write(m_sfd, buffer, len); } ssize_t send(const char* buffer, size_t len) { return write(m_sfd, buffer, len); }
/**
* @brief read bytes from opened file descriptor.
* @param buffer for received bytes.
* @param len size of the receive buffer.
* @return number of read bytes or -1 if an error has occured.
*/
ssize_t recv(char* buffer, size_t len) { return read(m_sfd, buffer, len); }
/**
* @brief returns the tcp port.
* @return the tcp port.
*/
int getPort() const { return m_port; } int getPort() const { return m_port; }
/**
* @brief returns the ip address.
* @return the ip address.
*/
std::string getIP() const { return m_ip; } std::string getIP() const { return m_ip; }
/**
* @brief returns the file descriptor.
* @return the file descriptor.
*/
int getFD() const { return m_sfd; } int getFD() const { return m_sfd; }
/**
* @brief returns status of file descriptor.
* @return true if file descriptor is valid.
*/
bool isValid(); bool isValid();
private: private:
/** file descriptor from tcp socket */
int m_sfd; int m_sfd;
/** port of tcp socket */
int m_port; int m_port;
/** ip address of tcp socket */
std::string m_ip; std::string m_ip;
/**
* @brief private constructor, limited access only for friend classes.
* @param sfd the file desctriptor of tcp socket.
* @param address struct which holds the ip address.
*/
TCPSocket(int sfd, struct sockaddr_in* address); TCPSocket(int sfd, struct sockaddr_in* address);
}; };
/**
* @brief class to initiate a tcp socket connection to a listening server.
*/
class TCPClient class TCPClient
{ {
public: public:
/**
* @brief initiate a tcp socket connection to a listening server.
* @param server the server name or ip address to connect.
* @param port the tcp port.
* @return pointer to an opened tcp socket.
*/
TCPSocket* connect(const std::string& server, const int& port); TCPSocket* connect(const std::string& server, const int& port);
private:
}; };
/**
* @brief class for a tcp based network server.
*/
class TCPServer class TCPServer
{ {
public: public:
/**
* @brief creates a new instance of a listening tcp server.
* @param port the tcp port.
* @param address the ip address.
*/
TCPServer(const int port, const std::string address) TCPServer(const int port, const std::string address)
: m_lfd(0), m_port(port), m_address(address), m_listening(false) {} : m_lfd(0), m_port(port), m_address(address), m_listening(false) {}
/**
* @brief destructor.
*/
~TCPServer() { if (m_lfd > 0) {close(m_lfd);} } ~TCPServer() { if (m_lfd > 0) {close(m_lfd);} }
/**
* @brief start listening of tcp socket.
*/
int start(); int start();
/**
* @brief accept an incomming tcp connection and create a local tcp socket for communication.
* @return pointer to an opened tcp socket.
*/
TCPSocket* newSocket(); TCPSocket* newSocket();
/**
* @brief returns the file descriptor.
* @return the file descriptor.
*/
int getFD() const { return m_lfd; } int getFD() const { return m_lfd; }
private: private:
/** file descriptor from listening tcp socket */
int m_lfd; int m_lfd;
/** listening tcp port */
int m_port; int m_port;
/** listening tcp socket ip address */
std::string m_address; std::string m_address;
/** true if object is already listening */
bool m_listening; bool m_listening;
}; };
#endif // LIBCORE_TCPSOCKET_H_ #endif // LIBUTILS_TCPSOCKET_H_
+13 -1
View File
@@ -17,11 +17,19 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "thread.h" #include "thread.h"
/**
* @brief static function which will be called on thread startup.
* @return void pointer.
*/
static void* runThread(void* arg) static void* runThread(void* arg)
{ {
return ((Thread *)arg)->run(); return ((Thread*)arg)->run();
} }
Thread::~Thread() Thread::~Thread()
@@ -39,7 +47,11 @@ int Thread::start(const char* name)
int result = pthread_create(&m_threadid, NULL, runThread, this); int result = pthread_create(&m_threadid, NULL, runThread, this);
if (result == 0) { if (result == 0) {
#ifdef HAVE_PTHREAD_SETNAME_NP
pthread_setname_np(m_threadid, name); pthread_setname_np(m_threadid, name);
#endif
m_running = true; m_running = true;
} }
+42 -3
View File
@@ -17,30 +17,69 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_THREAD_H_ #ifndef LIBUTILS_THREAD_H_
#define LIBCORE_THREAD_H_ #define LIBUTILS_THREAD_H_
#include <pthread.h> #include <pthread.h>
/**
* @brief wrapper class for pthread.
*/
class Thread class Thread
{ {
public: public:
/**
* @brief constructor.
*/
Thread() : m_threadid(0), m_running(false), m_detached(false) {} Thread() : m_threadid(0), m_running(false), m_detached(false) {}
/**
* @brief virtual destructor.
*/
virtual ~Thread(); virtual ~Thread();
/**
* @brief create the thread and set name for process list.
* @param name the thread name which show in process list.
* @return value of thread creating.
*/
int start(const char* name); int start(const char* name);
/**
* @brief join the thread.
* @return value of thread joining.
*/
int join(); int join();
/**
* @brief detach the thread.
* @return value of thread detaching.
*/
int detach(); int detach();
/**
* @brief return the thread id.
* @return own thread id.
*/
pthread_t self() {return m_threadid; } pthread_t self() {return m_threadid; }
/**
* @brief virtul function which must be implemented in derived class.
* @return void pointer.
*/
virtual void* run() = 0; virtual void* run() = 0;
private: private:
/** own thread id */
pthread_t m_threadid; pthread_t m_threadid;
/** true if thread is running */
bool m_running; bool m_running;
/** true if thread is detached */
bool m_detached; bool m_detached;
}; };
#endif // LIBCORE_THREAD_H_ #endif // LIBUTILS_THREAD_H_
+35 -4
View File
@@ -17,28 +17,42 @@
* along with ebusd. If not, see http://www.gnu.org/licenses/. * along with ebusd. If not, see http://www.gnu.org/licenses/.
*/ */
#ifndef LIBCORE_WQUEUE_H_ #ifndef LIBUTILS_WQUEUE_H_
#define LIBCORE_WQUEUE_H_ #define LIBUTILS_WQUEUE_H_
#include <list> #include <list>
#include <pthread.h> #include <pthread.h>
template <typename T> class WQueue /**
* @brief queue class template for all kinds data types with exclusiv lock.
*/
template <typename T>
class WQueue
{ {
public: public:
/**
* @brief constructs a new instance.
*/
WQueue() WQueue()
{ {
pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL); pthread_cond_init(&m_cond, NULL);
} }
/**
* @brief destructor.
*/
~WQueue() ~WQueue()
{ {
pthread_mutex_destroy(&m_mutex); pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond); pthread_cond_destroy(&m_cond);
} }
/**
* @brief add a new item to the end of queue.
* @param item to add.
*/
void add(T item) void add(T item)
{ {
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
@@ -49,6 +63,10 @@ public:
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
} }
/**
* @brief remove the first item from queue.
* @return the item.
*/
T remove() T remove()
{ {
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
@@ -64,6 +82,10 @@ public:
return item; return item;
} }
/**
* @brief return the first item from queue without remove.
* @return the item.
*/
T next() T next()
{ {
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
@@ -78,6 +100,10 @@ public:
return item; return item;
} }
/**
* @brief the number of entries inside queue.
* @return the size.
*/
int size() int size()
{ {
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
@@ -90,10 +116,15 @@ public:
} }
private: private:
/** the queue itself */
std::list<T> m_queue; std::list<T> m_queue;
/** mutex variable for exclusive lock */
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
/** condition variable for exclusive lock */
pthread_cond_t m_cond; pthread_cond_t m_cond;
}; };
#endif // LIBCORE_WQUEUE_H_ #endif // LIBUTILS_WQUEUE_H_