move raw logging+dump to proto, more abstraction

This commit is contained in:
John
2023-11-04 09:18:41 +01:00
parent 3d9dd9b1c3
commit 607fc00c0e
9 changed files with 305 additions and 232 deletions
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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");
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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