move raw logging+dump to proto, more abstraction
This commit is contained in:
@@ -14,8 +14,8 @@ ebusd_SOURCES = \
|
||||
main.h main.cpp main_args.cpp
|
||||
|
||||
|
||||
ebusd_LDADD = ../lib/utils/libutils.a \
|
||||
../lib/ebus/libebus.a \
|
||||
ebusd_LDADD = ../lib/ebus/libebus.a \
|
||||
../lib/utils/libutils.a \
|
||||
-lpthread \
|
||||
@EXTRA_LIBS@
|
||||
|
||||
|
||||
+10
-24
@@ -29,7 +29,6 @@
|
||||
#include "lib/ebus/data.h"
|
||||
#include "lib/ebus/symbol.h"
|
||||
#include "lib/ebus/result.h"
|
||||
#include "lib/ebus/device.h"
|
||||
#include "lib/ebus/protocol.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -248,25 +247,15 @@ class BusHandler : public ProtocolListener {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param device the @a Device instance for accessing the bus.
|
||||
* @param messages the @a MessageMap instance with all known @a Message instances.
|
||||
* @param scanHelper the @a ScanHelper instance.
|
||||
* @param ownAddress the own master address.
|
||||
* @param answer whether to answer queries for the own master/slave address.
|
||||
* @param busLostRetries the number of times a send is repeated due to lost arbitration.
|
||||
* @param failedSendRetries the number of times a failed send is repeated (other than lost arbitration).
|
||||
* @param busAcquireTimeout the maximum time in milliseconds for bus acquisition.
|
||||
* @param slaveRecvTimeout the maximum time in milliseconds an addressed slave is expected to acknowledge.
|
||||
* @param lockCount the number of AUTO-SYN symbols before sending is allowed after lost arbitration, or 0 for auto detection.
|
||||
* @param generateSyn whether to enable AUTO-SYN symbol generation.
|
||||
* @param pollInterval the interval in seconds in which poll messages are cycled, or 0 if disabled.
|
||||
*/
|
||||
BusHandler(Device* device, MessageMap* messages, ScanHelper* scanHelper,
|
||||
const ebus_protocol_config_t config, unsigned int pollInterval)
|
||||
: m_messages(messages), m_scanHelper(scanHelper),
|
||||
BusHandler(MessageMap* messages, ScanHelper* scanHelper,
|
||||
unsigned int pollInterval)
|
||||
: m_protocol(nullptr), m_messages(messages), m_scanHelper(scanHelper),
|
||||
m_pollInterval(pollInterval), m_lastPoll(0), m_runningScans(0),
|
||||
m_grabMessages(true) {
|
||||
m_protocol = ProtocolHandler::create(config, device, this);
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
}
|
||||
|
||||
@@ -274,22 +263,19 @@ class BusHandler : public ProtocolListener {
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BusHandler() {
|
||||
if (m_protocol) {
|
||||
delete m_protocol;
|
||||
m_protocol = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the @a ProtocolHandler instance for accessing the bus.
|
||||
* @param protocol the @a ProtocolHandler instance for accessing the bus.
|
||||
*/
|
||||
void setProtocol(ProtocolHandler* protocol) { m_protocol = protocol; }
|
||||
|
||||
/**
|
||||
* @return the @a ProtocolHandler instance for accessing the bus.
|
||||
*/
|
||||
ProtocolHandler* getProtocol() const { return m_protocol; }
|
||||
|
||||
/**
|
||||
* @return the @a Device instance for accessing the bus.
|
||||
*/
|
||||
const Device* getDevice() const { return m_protocol->getDevice(); }
|
||||
|
||||
/**
|
||||
* Clear stored values (e.g. scan results).
|
||||
*/
|
||||
@@ -433,7 +419,7 @@ class BusHandler : public ProtocolListener {
|
||||
*/
|
||||
result_t prepareScan(symbol_t slave, bool full, const string& levels, bool* reload, ScanRequest** request);
|
||||
|
||||
/** the @a ProtocolHandler instance for accessing the bus. */
|
||||
/** the @a ProtocolHandler instance for accessing the bus (loosely coupled but set quickly after construction). */
|
||||
ProtocolHandler* m_protocol;
|
||||
|
||||
/** the @a MessageMap instance with all known @a Message instances. */
|
||||
|
||||
+62
-17
@@ -29,6 +29,7 @@
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "ebusd/bushandler.h"
|
||||
#include "ebusd/mainloop.h"
|
||||
#include "ebusd/network.h"
|
||||
#include "lib/utils/log.h"
|
||||
@@ -37,16 +38,14 @@
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
using std::dec;
|
||||
using std::hex;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
using std::nouppercase;
|
||||
using std::cout;
|
||||
|
||||
/** the previous config path part to rewrite to the current one. */
|
||||
#define PREVIOUS_CONFIG_PATH_SUFFIX "://ebusd.eu/config/"
|
||||
|
||||
/** the second previous config path part to rewrite to the current one. */
|
||||
#define PREVIOUS_CONFIG_PATH_SUFFIX2 "://cfg.ebusd.eu/"
|
||||
|
||||
/** the opened PID file, or nullptr. */
|
||||
static FILE* s_pidFile = nullptr;
|
||||
|
||||
@@ -59,6 +58,12 @@ static MessageMap* s_messageMap = nullptr;
|
||||
/** the @a ScanHelper instance, or nullptr. */
|
||||
static ScanHelper* s_scanHelper = nullptr;
|
||||
|
||||
/** the @a ProtocolHandler instance, or nullptr. */
|
||||
static ProtocolHandler* s_protocol = nullptr;
|
||||
|
||||
/** the @a BusHandler instance, or nullptr. */
|
||||
static BusHandler* s_busHandler = nullptr;
|
||||
|
||||
/** the @a Request @a Queue instance, or nullptr. */
|
||||
static Queue<Request*>* s_requestQueue = nullptr;
|
||||
|
||||
@@ -143,6 +148,14 @@ void cleanup() {
|
||||
delete s_requestQueue;
|
||||
s_requestQueue = nullptr;
|
||||
}
|
||||
if (s_protocol != nullptr) {
|
||||
delete s_protocol;
|
||||
s_protocol = nullptr;
|
||||
}
|
||||
if (s_busHandler != nullptr) {
|
||||
delete s_busHandler;
|
||||
s_busHandler = nullptr;
|
||||
}
|
||||
if (s_messageMap != nullptr) {
|
||||
delete s_messageMap;
|
||||
s_messageMap = nullptr;
|
||||
@@ -369,13 +382,31 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
return overallResult == RESULT_OK ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// open the device
|
||||
Device *device = Device::create(s_opt.device, s_opt.extraLatency, !s_opt.noDeviceCheck);
|
||||
if (device == nullptr) {
|
||||
logWrite(lf_main, ll_error, "unable to create device %s", s_opt.device); // force logging on exit
|
||||
s_busHandler = new BusHandler(s_messageMap, s_scanHelper, s_opt.pollInterval);
|
||||
|
||||
// create the protocol and open the device
|
||||
ebus_protocol_config_t config = {
|
||||
.device = s_opt.device,
|
||||
.noDeviceCheck = s_opt.noDeviceCheck,
|
||||
.readOnly = s_opt.readOnly,
|
||||
.extraLatency = s_opt.extraLatency,
|
||||
.ownAddress = s_opt.address,
|
||||
.answer = s_opt.answer,
|
||||
.busLostRetries = s_opt.acquireRetries,
|
||||
.failedSendRetries = s_opt.sendRetries,
|
||||
.busAcquireTimeout = s_opt.acquireTimeout,
|
||||
.slaveRecvTimeout = s_opt.receiveTimeout,
|
||||
.lockCount = s_opt.masterCount,
|
||||
.generateSyn = s_opt.generateSyn,
|
||||
.initialSend = s_opt.initialSend,
|
||||
};
|
||||
s_protocol = ProtocolHandler::create(config, s_busHandler);
|
||||
if (s_protocol == nullptr) {
|
||||
logWrite(lf_main, ll_error, "unable to create protocol/device %s", s_opt.device); // force logging on exit
|
||||
cleanup();
|
||||
return EINVAL;
|
||||
}
|
||||
s_busHandler->setProtocol(s_protocol);
|
||||
|
||||
if (!s_opt.foreground) {
|
||||
if (!setLogFile(s_opt.logFile)) {
|
||||
@@ -391,14 +422,28 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
|
||||
if (s_opt.dumpFile[0]) {
|
||||
s_protocol->setDumpFile(s_opt.dumpFile, s_opt.dumpSize, s_opt.dumpFlush);
|
||||
if (s_opt.dump) {
|
||||
s_protocol->toggleDump();
|
||||
}
|
||||
}
|
||||
if (s_opt.logRawFile[0] && strcmp(s_opt.logRawFile, s_opt.logFile) != 0) {
|
||||
s_protocol->setLogRawFile(s_opt.logRawFile, s_opt.logRawSize);
|
||||
}
|
||||
if (s_opt.logRaw != 0) {
|
||||
s_protocol->toggleLogRaw(s_opt.logRaw == 2);
|
||||
}
|
||||
|
||||
// open Device
|
||||
s_protocol->open();
|
||||
|
||||
// create the MainLoop
|
||||
s_requestQueue = new Queue<Request*>();
|
||||
s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue);
|
||||
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||
ProtocolHandler* protocol = busHandler->getProtocol();
|
||||
s_mainLoop = new MainLoop(s_opt, s_busHandler, s_messageMap, s_scanHelper, s_requestQueue);
|
||||
|
||||
ostringstream ostream;
|
||||
protocol->formatInfo(&ostream, false, true);
|
||||
s_protocol->formatInfo(&ostream, false, true);
|
||||
string deviceInfoStr = ostream.str();
|
||||
logNotice(lf_main, PACKAGE_STRING "." REVISION " started%s on device: %s",
|
||||
s_opt.scanConfig ? s_opt.initialScan == ESC ? " with auto scan"
|
||||
@@ -420,7 +465,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
if (!s_scanHelper->parseMessage(argv[arg_index], false, &master, &slave)) {
|
||||
continue;
|
||||
}
|
||||
protocol->injectMessage(master, slave);
|
||||
s_protocol->injectMessage(master, slave);
|
||||
if (s_opt.scanConfig && master.size() >= 5 && master[4] == 0 && master[2] == 0x07 && master[3] == 0x04
|
||||
&& isValidAddress(master[1], false) && !isMaster(master[1]) && !scanAddresses[master[1]]) {
|
||||
// scan message, simulate scanning
|
||||
@@ -428,11 +473,11 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
scanAdrCount++;
|
||||
}
|
||||
}
|
||||
protocol->start("bushandler");
|
||||
s_protocol->start("bushandler");
|
||||
for (symbol_t address = 0; scanAdrCount > 0; address++) {
|
||||
if (scanAddresses[address]) {
|
||||
scanAdrCount--;
|
||||
busHandler->scanAndWait(address, true);
|
||||
s_busHandler->scanAndWait(address, true);
|
||||
}
|
||||
}
|
||||
if (s_opt.stopAfterInject) {
|
||||
@@ -440,7 +485,7 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
protocol->start("bushandler");
|
||||
s_protocol->start("bushandler");
|
||||
}
|
||||
s_mainLoop->start("mainloop");
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@ namespace ebusd {
|
||||
*/
|
||||
|
||||
/** the config path part behind the scheme (scheme without "://"). */
|
||||
//#define CONFIG_PATH_SUFFIX "://ebus.github.io/cfg/de/"
|
||||
|
||||
#define CONFIG_PATH_SUFFIX "://cfg.ebusd.eu/"
|
||||
|
||||
/** A structure holding all program options. */
|
||||
|
||||
+8
-131
@@ -32,8 +32,6 @@
|
||||
namespace ebusd {
|
||||
|
||||
using std::dec;
|
||||
using std::hex;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
using std::endl;
|
||||
using std::ifstream;
|
||||
@@ -105,41 +103,19 @@ result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map<
|
||||
#define VERBOSITY_4 (VERBOSITY_3 | OF_ALL_ATTRS)
|
||||
|
||||
|
||||
MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper,
|
||||
Queue<Request*>* requestQueue)
|
||||
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
|
||||
MainLoop::MainLoop(const struct options& opt, BusHandler* busHandler,
|
||||
MessageMap* messages, ScanHelper* scanHelper, Queue<Request*>* requestQueue)
|
||||
: Thread(), m_busHandler(busHandler), m_protocol(busHandler->getProtocol()), m_reconnectCount(0),
|
||||
m_userList(opt.accessLevel), m_messages(messages),
|
||||
m_scanHelper(scanHelper), m_address(opt.address), m_scanConfig(opt.scanConfig),
|
||||
m_initialScan(opt.readOnly ? ESC : opt.initialScan), m_scanRetries(opt.scanRetries),
|
||||
m_scanStatus(SCAN_STATUS_NONE), m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex),
|
||||
m_shutdown(false), m_runUpdateCheck(opt.updateCheck), m_httpClient(), m_requestQueue(requestQueue) {
|
||||
m_device->setListener(this);
|
||||
// open Device
|
||||
result_t result = m_device->open();
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result));
|
||||
} else if (!m_device->isValid()) {
|
||||
logError(lf_bus, "device %s not available", m_device->getName());
|
||||
}
|
||||
if (opt.dumpFile[0]) {
|
||||
m_dumpFile = new RotateFile(opt.dumpFile, opt.dumpSize, false, opt.dumpFlush ? 1 : 16);
|
||||
m_dumpFile->setEnabled(opt.dump);
|
||||
} else {
|
||||
m_dumpFile = nullptr;
|
||||
}
|
||||
m_logRawEnabled = opt.logRaw != 0;
|
||||
if (opt.logRawFile[0] && strcmp(opt.logRawFile, opt.logFile) != 0) {
|
||||
m_logRawFile = new RotateFile(opt.logRawFile, opt.logRawSize, true);
|
||||
m_logRawFile->setEnabled(m_logRawEnabled);
|
||||
} else {
|
||||
m_logRawFile = nullptr;
|
||||
}
|
||||
m_logRawBytes = opt.logRaw == 2;
|
||||
m_logRawLastReceived = true;
|
||||
m_logRawLastSymbol = SYN;
|
||||
if (opt.aclFile[0]) {
|
||||
string errorDescription;
|
||||
time_t mtime = 0;
|
||||
istream* stream = FileReader::openFile(opt.aclFile, &errorDescription, &mtime);
|
||||
result_t result;
|
||||
if (stream) {
|
||||
result = m_userList.readFromStream(stream, opt.aclFile, mtime, false, nullptr, &errorDescription);
|
||||
delete(stream);
|
||||
@@ -150,24 +126,7 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag
|
||||
logError(lf_main, "error reading ACL file \"%s\": %s", opt.aclFile, getResultCode(result));
|
||||
}
|
||||
}
|
||||
// create BusHandler
|
||||
ebus_protocol_config_t config = {
|
||||
.readOnly = opt.readOnly,
|
||||
.ownAddress = m_address,
|
||||
.answer = opt.answer,
|
||||
.busLostRetries = opt.acquireRetries,
|
||||
.failedSendRetries = opt.sendRetries,
|
||||
.busAcquireTimeout = opt.acquireTimeout,
|
||||
.slaveRecvTimeout = opt.receiveTimeout,
|
||||
.lockCount = opt.masterCount,
|
||||
.generateSyn = opt.generateSyn,
|
||||
.initialSend = opt.initialSend,
|
||||
};
|
||||
m_busHandler = new BusHandler(m_device, m_messages, scanHelper,
|
||||
config, opt.pollInterval);
|
||||
m_protocol = m_busHandler->getProtocol();
|
||||
|
||||
// create network
|
||||
m_htmlPath = opt.htmlPath;
|
||||
logInfo(lf_main, "registering data handlers");
|
||||
if (datahandler_register(&m_userList, m_busHandler, messages, &m_dataHandlers)) {
|
||||
@@ -191,23 +150,6 @@ MainLoop::~MainLoop() {
|
||||
delete dataHandler;
|
||||
}
|
||||
m_dataHandlers.clear();
|
||||
if (m_dumpFile) {
|
||||
delete m_dumpFile;
|
||||
m_dumpFile = nullptr;
|
||||
}
|
||||
if (m_logRawFile) {
|
||||
delete m_logRawFile;
|
||||
m_logRawFile = nullptr;
|
||||
}
|
||||
if (m_busHandler != nullptr) {
|
||||
delete m_busHandler;
|
||||
m_busHandler = nullptr;
|
||||
m_protocol = nullptr; // ProtocolHandler is freed by BusHandler
|
||||
}
|
||||
if (m_device != nullptr) {
|
||||
delete m_device;
|
||||
m_device = nullptr;
|
||||
}
|
||||
if (m_newlyDefinedMessages) {
|
||||
delete m_newlyDefinedMessages;
|
||||
m_newlyDefinedMessages = nullptr;
|
||||
@@ -480,62 +422,6 @@ void MainLoop::run() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainLoop::notifyDeviceData(symbol_t symbol, bool received) {
|
||||
if (received && m_dumpFile) {
|
||||
m_dumpFile->write(&symbol, 1);
|
||||
}
|
||||
if (!m_logRawFile && !m_logRawEnabled) {
|
||||
return;
|
||||
}
|
||||
if (m_logRawBytes) {
|
||||
if (m_logRawFile) {
|
||||
m_logRawFile->write(&symbol, 1, received);
|
||||
} else if (m_logRawEnabled) {
|
||||
if (received) {
|
||||
logNotice(lf_bus, "<%02x", symbol);
|
||||
} else {
|
||||
logNotice(lf_bus, ">%02x", symbol);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (symbol != SYN) {
|
||||
if (received && !m_logRawLastReceived && symbol == m_logRawLastSymbol) {
|
||||
return; // skip received echo of previously sent symbol
|
||||
}
|
||||
if (m_logRawBuffer.tellp() == 0 || received != m_logRawLastReceived) {
|
||||
m_logRawLastReceived = received;
|
||||
if (m_logRawBuffer.tellp() == 0 && m_logRawLastSymbol != SYN) {
|
||||
m_logRawBuffer << "...";
|
||||
}
|
||||
m_logRawBuffer << (received ? "<" : ">");
|
||||
}
|
||||
m_logRawBuffer << setw(2) << setfill('0') << hex << static_cast<unsigned>(symbol);
|
||||
}
|
||||
m_logRawLastSymbol = symbol;
|
||||
if (m_logRawBuffer.tellp() > (symbol == SYN ? 0 : 64)) { // flush: direction+5 hdr+24 max data+crc+direction+ack+1
|
||||
if (symbol != SYN) {
|
||||
m_logRawBuffer << "...";
|
||||
}
|
||||
const string bufStr = m_logRawBuffer.str();
|
||||
const char* str = bufStr.c_str();
|
||||
if (m_logRawFile) {
|
||||
m_logRawFile->write((const unsigned char*)str, strlen(str), received, false);
|
||||
} else {
|
||||
logNotice(lf_bus, str);
|
||||
}
|
||||
m_logRawBuffer.str("");
|
||||
}
|
||||
}
|
||||
|
||||
void MainLoop::notifyStatus(bool error, const char* message) {
|
||||
if (error) {
|
||||
logError(lf_bus, "device status: %s", message);
|
||||
} else {
|
||||
logNotice(lf_bus, "device status: %s", message);
|
||||
}
|
||||
}
|
||||
|
||||
result_t MainLoop::decodeRequest(Request* req, bool* connected, RequestMode* reqMode,
|
||||
string* user, bool* reload, ostringstream* ostream) {
|
||||
vector<string> args;
|
||||
@@ -1886,15 +1772,7 @@ result_t MainLoop::executeRaw(const vector<string>& args, ostringstream* ostream
|
||||
" Toggle logging of messages or each byte.";
|
||||
return RESULT_OK;
|
||||
}
|
||||
bool enabled;
|
||||
m_logRawBytes = bytes;
|
||||
if (m_logRawFile) {
|
||||
enabled = !m_logRawFile->isEnabled();
|
||||
m_logRawFile->setEnabled(enabled);
|
||||
} else {
|
||||
enabled = !m_logRawEnabled;
|
||||
m_logRawEnabled = enabled;
|
||||
}
|
||||
bool enabled = m_protocol->toggleLogRaw(bytes);
|
||||
*ostream << (enabled ? "raw logging enabled" : "raw logging disabled");
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -1905,12 +1783,11 @@ result_t MainLoop::executeDump(const vector<string>& args, ostringstream* ostrea
|
||||
" Toggle binary dump of received bytes.";
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (!m_dumpFile) {
|
||||
if (!m_protocol->hasDumpFile()) {
|
||||
*ostream << "dump not configured";
|
||||
return RESULT_OK;
|
||||
}
|
||||
bool enabled = !m_dumpFile->isEnabled();
|
||||
m_dumpFile->setEnabled(enabled);
|
||||
bool enabled = m_protocol->toggleDump();
|
||||
*ostream << (enabled ? "dump enabled" : "dump disabled");
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
+10
-46
@@ -30,7 +30,7 @@
|
||||
#include "ebusd/scan.h"
|
||||
#include "lib/ebus/filereader.h"
|
||||
#include "lib/ebus/message.h"
|
||||
#include "lib/utils/rotatefile.h"
|
||||
#include "lib/ebus/protocol.h"
|
||||
#include "lib/utils/httpclient.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -99,18 +99,18 @@ class UserList : public UserInfo, public MappedFileReader {
|
||||
/**
|
||||
* The main loop handling requests from connected clients.
|
||||
*/
|
||||
class MainLoop : public Thread, DeviceListener {
|
||||
class MainLoop : public Thread {
|
||||
public:
|
||||
/**
|
||||
* Construct the main loop and create bus handling components.
|
||||
* @param opt the program options.
|
||||
* @param device the @a Device instance.
|
||||
* @param busHandler @a BusHandler instance.
|
||||
* @param messages the @a MessageMap instance.
|
||||
* @param scanHelper the @a ScanHelper instance.
|
||||
* @param requestQueue the reference to the @a Request @a Queue.
|
||||
*/
|
||||
MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper,
|
||||
Queue<Request*>* requestQueue);
|
||||
MainLoop(const struct options& opt, BusHandler* busHandler,
|
||||
MessageMap* messages, ScanHelper* scanHelper, Queue<Request*>* requestQueue);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -122,18 +122,6 @@ class MainLoop : public Thread, DeviceListener {
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Get the @a BusHandler instance.
|
||||
* @return the created @a BusHandler instance.
|
||||
*/
|
||||
BusHandler* getBusHandler() { return m_busHandler; }
|
||||
|
||||
// @copydoc
|
||||
void notifyDeviceData(symbol_t symbol, bool received) override;
|
||||
|
||||
// @copydoc
|
||||
void notifyStatus(bool error, const char* message) override;
|
||||
|
||||
|
||||
protected:
|
||||
// @copydoc
|
||||
@@ -370,33 +358,15 @@ class MainLoop : public Thread, DeviceListener {
|
||||
*/
|
||||
result_t formatHttpResult(result_t ret, int type, ostringstream* ostream);
|
||||
|
||||
/** the @a Device instance. */
|
||||
Device* m_device;
|
||||
/** the @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
/** the @a ProtocolHandler instance. */
|
||||
ProtocolHandler* m_protocol;
|
||||
|
||||
/** the number of reconnects requested from the @a Device. */
|
||||
unsigned int m_reconnectCount;
|
||||
|
||||
/** the @a RotateFile for writing sent/received bytes in log format, or nullptr. */
|
||||
RotateFile* m_logRawFile;
|
||||
|
||||
/** whether raw logging to @p logNotice is enabled (only relevant if m_logRawFile is nullptr). */
|
||||
bool m_logRawEnabled;
|
||||
|
||||
/** whether to log raw bytes instead of messages with @a m_logRawEnabled. */
|
||||
bool m_logRawBytes;
|
||||
|
||||
/** the buffer for building log raw message. */
|
||||
ostringstream m_logRawBuffer;
|
||||
|
||||
/** true when the last byte in @a m_logRawBuffer was receive, false if it was sent. */
|
||||
bool m_logRawLastReceived;
|
||||
|
||||
/** the last sent/received symbol.*/
|
||||
symbol_t m_logRawLastSymbol;
|
||||
|
||||
/** the @a RotateFile for dumping received data, or nullptr. */
|
||||
RotateFile* m_dumpFile;
|
||||
|
||||
/** the @a UserList instance. */
|
||||
UserList m_userList;
|
||||
|
||||
@@ -440,12 +410,6 @@ class MainLoop : public Thread, DeviceListener {
|
||||
/** the @a HttpClient for performing the update check. */
|
||||
HttpClient m_httpClient;
|
||||
|
||||
/** the created @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
/** the created @a ProtocolHandler instance. */
|
||||
ProtocolHandler* m_protocol;
|
||||
|
||||
/** the reference to the @a Request @a Queue. */
|
||||
Queue<Request*>* m_requestQueue;
|
||||
|
||||
|
||||
@@ -775,7 +775,7 @@ void MqttHandler::run() {
|
||||
publishDefinition(m_replacers, "def_global_uptime-", uptimeTopic, "global", "uptime", "def_global-");
|
||||
publishDefinition(m_replacers, "def_global_updatecheck-", m_globalTopic.get("", "updatecheck"), "global",
|
||||
"updatecheck", "def_global-");
|
||||
if (m_busHandler->getDevice()->supportsUpdateCheck()) {
|
||||
if (m_busHandler->getProtocol()->supportsUpdateCheck()) {
|
||||
publishDefinition(m_replacers, "def_global_updatecheck_device-", m_globalTopic.get("", "updatecheck"),
|
||||
"global", "updatecheck_device", "");
|
||||
}
|
||||
|
||||
+119
-3
@@ -20,13 +20,18 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include "lib/ebus/protocol.h"
|
||||
#include "lib/ebus/protocol_direct.h"
|
||||
#include <string>
|
||||
#include "lib/utils/log.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
using std::hex;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
|
||||
bool ActiveBusRequest::notify(result_t result, const SlaveSymbolString& slave) {
|
||||
if (result == RESULT_OK) {
|
||||
string str = slave.getStr();
|
||||
@@ -37,12 +42,25 @@ bool ActiveBusRequest::notify(result_t result, const SlaveSymbolString& slave) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ProtocolHandler* ProtocolHandler::create(const ebus_protocol_config_t config,
|
||||
Device* device, ProtocolListener* listener) {
|
||||
ProtocolListener* listener) {
|
||||
Device *device = Device::create(config.device, config.extraLatency, !config.noDeviceCheck);
|
||||
if (device == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return new DirectProtocolHandler(config, device, listener);
|
||||
}
|
||||
|
||||
result_t ProtocolHandler::open() {
|
||||
result_t result = m_device->open();
|
||||
if (result != RESULT_OK) {
|
||||
logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result));
|
||||
} else if (!m_device->isValid()) {
|
||||
logError(lf_bus, "device %s not available", m_device->getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProtocolHandler::formatInfo(ostringstream* ostream, bool verbose, bool noWait) {
|
||||
m_device->formatInfo(ostream, verbose, true);
|
||||
if (isReadOnly()) {
|
||||
@@ -58,6 +76,63 @@ void ProtocolHandler::formatInfoJson(ostringstream* ostream) {
|
||||
m_device->formatInfoJson(ostream);
|
||||
}
|
||||
|
||||
void ProtocolHandler::notifyDeviceData(symbol_t symbol, bool received) {
|
||||
if (received && m_dumpFile) {
|
||||
m_dumpFile->write(&symbol, 1);
|
||||
}
|
||||
if (!m_logRawFile && !m_logRawEnabled) {
|
||||
return;
|
||||
}
|
||||
if (m_logRawBytes) {
|
||||
if (m_logRawFile) {
|
||||
m_logRawFile->write(&symbol, 1, received);
|
||||
} else if (m_logRawEnabled) {
|
||||
if (received) {
|
||||
logNotice(lf_bus, "<%02x", symbol);
|
||||
} else {
|
||||
logNotice(lf_bus, ">%02x", symbol);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (symbol != SYN) {
|
||||
if (received && !m_logRawLastReceived && symbol == m_logRawLastSymbol) {
|
||||
return; // skip received echo of previously sent symbol
|
||||
}
|
||||
if (m_logRawBuffer.tellp() == 0 || received != m_logRawLastReceived) {
|
||||
m_logRawLastReceived = received;
|
||||
if (m_logRawBuffer.tellp() == 0 && m_logRawLastSymbol != SYN) {
|
||||
m_logRawBuffer << "...";
|
||||
}
|
||||
m_logRawBuffer << (received ? "<" : ">");
|
||||
}
|
||||
m_logRawBuffer << setw(2) << setfill('0') << hex << static_cast<unsigned>(symbol);
|
||||
}
|
||||
m_logRawLastSymbol = symbol;
|
||||
if (m_logRawBuffer.tellp() > (symbol == SYN ? 0 : 64)) { // flush: direction+5 hdr+24 max data+crc+direction+ack+1
|
||||
if (symbol != SYN) {
|
||||
m_logRawBuffer << "...";
|
||||
}
|
||||
const string bufStr = m_logRawBuffer.str();
|
||||
const char* str = bufStr.c_str();
|
||||
if (m_logRawFile) {
|
||||
m_logRawFile->write((const unsigned char*)str, strlen(str), received, false);
|
||||
} else {
|
||||
logNotice(lf_bus, str);
|
||||
}
|
||||
m_logRawBuffer.str("");
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolHandler::notifyStatus(bool error, const char* message) {
|
||||
if (error) {
|
||||
logError(lf_bus, "device status: %s", message);
|
||||
} else {
|
||||
logNotice(lf_bus, "device status: %s", message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProtocolHandler::clear() {
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
m_masterCount = 1;
|
||||
@@ -161,4 +236,45 @@ bool ProtocolHandler::addSeenAddress(symbol_t address) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ProtocolHandler::setDumpFile(const char* dumpFile, unsigned int dumpSize, bool dumpFlush) {
|
||||
if (m_dumpFile) {
|
||||
delete m_dumpFile;
|
||||
m_dumpFile = nullptr;
|
||||
}
|
||||
if (dumpFile && dumpFile[0]) {
|
||||
m_dumpFile = new RotateFile(dumpFile, dumpSize, false, dumpFlush ? 1 : 16);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProtocolHandler::toggleDump() {
|
||||
if (!m_dumpFile) {
|
||||
return false;
|
||||
}
|
||||
bool enabled = !m_dumpFile->isEnabled();
|
||||
m_dumpFile->setEnabled(enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void ProtocolHandler::setLogRawFile(const char* logRawFile, unsigned int logRawSize) {
|
||||
if (logRawFile[0]) {
|
||||
m_logRawFile = new RotateFile(logRawFile, logRawSize, true);
|
||||
m_logRawFile->setEnabled(m_logRawEnabled);
|
||||
} else {
|
||||
m_logRawFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProtocolHandler::toggleLogRaw(bool bytes) {
|
||||
bool enabled;
|
||||
m_logRawBytes = bytes;
|
||||
if (m_logRawFile) {
|
||||
enabled = !m_logRawFile->isEnabled();
|
||||
m_logRawFile->setEnabled(enabled);
|
||||
} else {
|
||||
enabled = !m_logRawEnabled;
|
||||
m_logRawEnabled = enabled;
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
+93
-6
@@ -23,6 +23,7 @@
|
||||
#include "lib/ebus/result.h"
|
||||
#include "lib/ebus/device.h"
|
||||
#include "lib/utils/queue.h"
|
||||
#include "lib/utils/rotatefile.h"
|
||||
#include "lib/utils/thread.h"
|
||||
|
||||
namespace ebusd {
|
||||
@@ -52,8 +53,14 @@ namespace ebusd {
|
||||
|
||||
/** settings for the eBUS protocol handler. */
|
||||
typedef struct ebus_protocol_config {
|
||||
/** eBUS device string (serial device or [udp:]ip:port) with optional protocol prefix (enh: or ens:). */
|
||||
const char* device;
|
||||
/** whether to skip serial eBUS device test. */
|
||||
bool noDeviceCheck;
|
||||
/** whether to allow read access to the device only. */
|
||||
bool readOnly;
|
||||
/** extra transfer latency in ms. */
|
||||
unsigned int extraLatency;
|
||||
/** the own master address. */
|
||||
symbol_t ownAddress;
|
||||
/** whether to answer queries for the own master/slave address. */
|
||||
@@ -232,7 +239,7 @@ class ProtocolListener {
|
||||
/**
|
||||
* Handles input from and output to eBUS with respect to the eBUS protocol.
|
||||
*/
|
||||
class ProtocolHandler : public WaitThread {
|
||||
class ProtocolHandler : public WaitThread, DeviceListener {
|
||||
public:
|
||||
/**
|
||||
* Construct a new instance.
|
||||
@@ -249,8 +256,13 @@ class ProtocolHandler : public WaitThread {
|
||||
m_masterCount(config.readOnly ? 0 : 1),
|
||||
m_symbolLatencyMin(-1), m_symbolLatencyMax(-1), m_arbitrationDelayMin(-1),
|
||||
m_arbitrationDelayMax(-1), m_lastReceive(0),
|
||||
m_symPerSec(0), m_maxSymPerSec(0) {
|
||||
m_symPerSec(0), m_maxSymPerSec(0),
|
||||
m_logRawFile(nullptr), m_logRawEnabled(false), m_logRawBytes(false),
|
||||
m_logRawLastSymbol(SYN), m_dumpFile(nullptr) {
|
||||
memset(m_seenAddresses, 0, sizeof(m_seenAddresses));
|
||||
m_device->setListener(this);
|
||||
m_logRawLastReceived = true;
|
||||
m_logRawLastSymbol = SYN;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,16 +279,33 @@ class ProtocolHandler : public WaitThread {
|
||||
delete req;
|
||||
}
|
||||
}
|
||||
if (m_dumpFile) {
|
||||
delete m_dumpFile;
|
||||
m_dumpFile = nullptr;
|
||||
}
|
||||
if (m_logRawFile) {
|
||||
delete m_logRawFile;
|
||||
m_logRawFile = nullptr;
|
||||
}
|
||||
if (m_device != nullptr) {
|
||||
delete m_device;
|
||||
m_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
* @param config the configuration to use.
|
||||
* @param device the @a Device instance for accessing the bus.
|
||||
* @param listener the @a ProtocolListener.
|
||||
* @return the new ProtocolHandler, or @a nullptr on error.
|
||||
*/
|
||||
static ProtocolHandler* create(const ebus_protocol_config_t config, Device* device, ProtocolListener* listener);
|
||||
static ProtocolHandler* create(const ebus_protocol_config_t config, ProtocolListener* listener);
|
||||
|
||||
/**
|
||||
* Open the device.
|
||||
* @return the @a result_t code.
|
||||
*/
|
||||
virtual result_t open();
|
||||
|
||||
/**
|
||||
* Format device/protocol infos in plain text.
|
||||
@@ -334,9 +363,15 @@ class ProtocolHandler : public WaitThread {
|
||||
unsigned int getMaxSymPerSec() const { return m_maxSymPerSec; }
|
||||
|
||||
/**
|
||||
* @return the @a Device instance for accessing the bus.
|
||||
* @return whether the device supports checking for version updates.
|
||||
*/
|
||||
const Device* getDevice() const { return m_device; }
|
||||
virtual bool supportsUpdateCheck() const { return m_device->supportsUpdateCheck(); }
|
||||
|
||||
// @copydoc
|
||||
void notifyDeviceData(symbol_t symbol, bool received) override;
|
||||
|
||||
// @copydoc
|
||||
void notifyStatus(bool error, const char* message) override;
|
||||
|
||||
/**
|
||||
* Clear stored values (e.g. scan results).
|
||||
@@ -425,6 +460,37 @@ class ProtocolHandler : public WaitThread {
|
||||
*/
|
||||
unsigned int getMasterCount() const { return m_masterCount; }
|
||||
|
||||
/**
|
||||
* Set the dump file to use.
|
||||
* @param dumpFile the dump file to use, or nullptr.
|
||||
* @param dumpSize the maximum file size.
|
||||
* @param dumpFlush true to early flush the file.
|
||||
*/
|
||||
void setDumpFile(const char* dumpFile, unsigned int dumpSize, bool dumpFlush);
|
||||
|
||||
/**
|
||||
* @return whether a dump file is set.
|
||||
*/
|
||||
bool hasDumpFile() const { return m_dumpFile; }
|
||||
|
||||
/**
|
||||
* Toggle dumping to file.
|
||||
* @return true if dumping is now enabled.
|
||||
*/
|
||||
bool toggleDump();
|
||||
|
||||
/**
|
||||
* Set the log raw data file to use.
|
||||
* @param logRawFile the log raw file to use, or nullptr.
|
||||
* @param logRawSize the maximum file size.
|
||||
*/
|
||||
void setLogRawFile(const char* logRawFile, unsigned int logRawSize);
|
||||
|
||||
/**
|
||||
* Toggle logging raw data.
|
||||
* @return true if logging raw data is now enabled.
|
||||
*/
|
||||
bool toggleLogRaw(bool bytes);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -500,6 +566,27 @@ class ProtocolHandler : public WaitThread {
|
||||
|
||||
/** the participating bus addresses seen so far. */
|
||||
bool m_seenAddresses[256];
|
||||
|
||||
/** the @a RotateFile for writing sent/received bytes in log format, or nullptr. */
|
||||
RotateFile* m_logRawFile;
|
||||
|
||||
/** whether raw logging to @p logNotice is enabled (only relevant if m_logRawFile is nullptr). */
|
||||
bool m_logRawEnabled;
|
||||
|
||||
/** whether to log raw bytes instead of messages with @a m_logRawEnabled. */
|
||||
bool m_logRawBytes;
|
||||
|
||||
/** the buffer for building log raw message. */
|
||||
ostringstream m_logRawBuffer;
|
||||
|
||||
/** true when the last byte in @a m_logRawBuffer was receive, false if it was sent. */
|
||||
bool m_logRawLastReceived;
|
||||
|
||||
/** the last sent/received symbol.*/
|
||||
symbol_t m_logRawLastSymbol;
|
||||
|
||||
/** the @a RotateFile for dumping received data, or nullptr. */
|
||||
RotateFile* m_dumpFile;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
Reference in New Issue
Block a user