diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index 31a0ebbe..277bc9f9 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -350,8 +350,32 @@ result_t BusHandler::readFromBus(Message* message, const string& inputStr, symbo return ret; } -void BusHandler::notifyProtocolStatus(bool signal) { - // ignored +void BusHandler::notifyProtocolStatus(ProtocolState state) { + if (state == ps_empty && m_pollInterval > 0) { // check for poll/scan + time_t now; + time(&now); + if (m_lastPoll == 0 || difftime(now, m_lastPoll) > m_pollInterval) { + Message* message = m_messages->getNextPoll(); + if (message != nullptr) { + m_lastPoll = now; + if (difftime(now, message->getLastUpdateTime()) > m_pollInterval) { + // only poll this message if it was not updated already by other means within the interval + auto request = new PollRequest(message); + result_t ret = request->prepare(m_protocol->getOwnMasterAddress()); + if (ret != RESULT_OK) { + logError(lf_bus, "prepare poll message: %s", getResultCode(ret)); + delete request; + } else { + ret = m_protocol->addRequest(request, false); + if (ret != RESULT_OK) { + logError(lf_bus, "push poll message: %s", getResultCode(ret)); + delete request; + } + } + } + } + } + } } result_t BusHandler::notifyProtocolAnswer(const MasterSymbolString& command, SlaveSymbolString* response) { @@ -494,7 +518,7 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, const string& levels if (scanMessage == nullptr) { return RESULT_ERR_NOTFOUND; } - if (m_protocol->getDevice()->isReadOnly()) { + if (m_protocol->isReadOnly()) { return RESULT_OK; } deque messages; @@ -564,9 +588,8 @@ result_t BusHandler::startScan(bool full, const string& levels) { } m_scanResults.clear(); m_runningScans++; - m_protocol->addRequest(request, false); // request is deleted by ProtocolHandler after finish - return RESULT_OK; + return m_protocol->addRequest(request, false); } void BusHandler::setScanResult(symbol_t dstAddress, size_t index, const string& str) { @@ -704,7 +727,7 @@ void BusHandler::formatUpdateInfo(ostringstream* output) const { } *output << ",\"c\":" << m_protocol->getMasterCount() << ",\"m\":" << m_messages->size() - << ",\"ro\":" << (m_protocol->getDevice()->isReadOnly() ? 1 : 0) + << ",\"ro\":" << (m_protocol->isReadOnly() ? 1 : 0) << ",\"an\":" << (m_protocol->isAnswering() ? 1 : 0) << ",\"co\":" << (m_protocol->isAddressConflict(SYN) ? 1 : 0); if (m_grabMessages) { @@ -727,8 +750,7 @@ void BusHandler::formatUpdateInfo(ostringstream* output) const { } unsigned char address = 0; for (int index = 0; index < 256; index++, address++) { - bool ownAddress = !m_protocol->getDevice()->isReadOnly() - && (address == m_protocol->getOwnMasterAddress() || address == m_protocol->getOwnSlaveAddress()); + bool ownAddress = !m_protocol->isOwnAddress(address); if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) { continue; } @@ -815,8 +837,11 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool m_scanResults[dstAddress].resize(1); } m_runningScans++; - requestExecuted = m_protocol->addRequest(request, true); - result = requestExecuted ? request->m_result : RESULT_ERR_TIMEOUT; + result = m_protocol->addRequest(request, true); + requestExecuted = result == RESULT_OK; + if (requestExecuted) { + result = request->m_result; + } delete request; request = nullptr; } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index e0f6c684..b7405ca8 100755 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -410,7 +410,7 @@ class BusHandler : public ProtocolListener { void setScanConfigLoaded(symbol_t address, const string& file); // @copydoc - void notifyProtocolStatus(bool signal) override; + void notifyProtocolStatus(ProtocolState state) override; // @copydoc result_t notifyProtocolAnswer(const MasterSymbolString& master, SlaveSymbolString* slave) override; diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 5da175e0..f78270f6 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -363,8 +363,7 @@ int main(int argc, char* argv[], char* envp[]) { } // open the device - Device *device = Device::create(s_opt.device, s_opt.extraLatency, !s_opt.noDeviceCheck, s_opt.readOnly, - s_opt.initialSend); + 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 cleanup(); @@ -385,8 +384,14 @@ int main(int argc, char* argv[], char* envp[]) { signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); + // create the MainLoop + s_requestQueue = new Queue(); + s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue); + BusHandler* busHandler = s_mainLoop->getBusHandler(); + ProtocolHandler* protocol = busHandler->getProtocol(); + ostringstream ostream; - device->formatInfo(&ostream, false, false, true); + 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" @@ -397,12 +402,7 @@ int main(int argc, char* argv[], char* envp[]) { // load configuration files s_scanHelper->loadConfigFiles(!s_opt.scanConfig); - s_requestQueue = new Queue(); - - // create the MainLoop and start it - s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue); - BusHandler* busHandler = s_mainLoop->getBusHandler(); - ProtocolHandler* protocol = busHandler->getProtocol(); + // start the MainLoop if (s_opt.injectMessages) { int scanAdrCount = 0; bool scanAddresses[256] = {}; diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 902a6540..f2b7e107 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -152,6 +152,7 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag } // create BusHandler ebus_protocol_config_t config = { + .readOnly = opt.readOnly, .ownAddress = m_address, .answer = opt.answer, .busLostRetries = opt.acquireRetries, @@ -160,6 +161,7 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag .slaveRecvTimeout = opt.receiveTimeout, .lockCount = opt.masterCount, .generateSyn = opt.generateSyn, + .initialSend = opt.initialSend, }; m_busHandler = new BusHandler(m_device, m_messages, scanHelper, config, opt.pollInterval); @@ -377,7 +379,7 @@ void MainLoop::run() { << ",\"a\":\"other\"" #endif << ",\"u\":" << (now-start); - m_device->formatInfo(&ostr, false, true, true); + m_protocol->formatInfoJson(&ostr); if (m_reconnectCount) { ostr << ",\"rc\":" << m_reconnectCount; } @@ -1935,7 +1937,7 @@ result_t MainLoop::executeInfo(const vector& args, const string& user, o *ostream << "update check: " << m_updateCheck << "\n"; } *ostream << "device: "; - m_device->formatInfo(ostream, verbose); + m_protocol->formatInfo(ostream, verbose, false); *ostream << "\n"; if (!user.empty()) { *ostream << "user: " << user << "\n"; @@ -2226,7 +2228,7 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri << ",\n \"maxsymbollatency\": " << m_protocol->getMaxSymbolLatency(); } } - if (!m_device->isReadOnly()) { + if (!m_protocol->isReadOnly()) { *ostream << ",\n \"qq\": " << static_cast(m_address); } *ostream << ",\n \"reconnects\": " << m_reconnectCount diff --git a/src/lib/ebus/device.cpp b/src/lib/ebus/device.cpp index 07166e67..1132bdaa 100755 --- a/src/lib/ebus/device.cpp +++ b/src/lib/ebus/device.cpp @@ -88,11 +88,11 @@ namespace ebusd { #define DEBUG_RAW_TRAFFIC(format, args...) #endif -Device::Device(const char* name, bool readOnly, bool initialSend) - : m_name(name), m_readOnly(readOnly), m_initialSend(initialSend), m_listener(nullptr) { +Device::Device(const char* name) + : m_name(name), m_listener(nullptr) { } -Device* Device::create(const char* name, unsigned int extraLatency, bool checkDevice, bool readOnly, bool initialSend) { +Device* Device::create(const char* name, unsigned int extraLatency, bool checkDevice) { bool highSpeed = strncmp(name, "ens:", 4) == 0; bool enhanced = highSpeed || strncmp(name, "enh:", 4) == 0; if (enhanced) { @@ -128,23 +128,17 @@ Device* Device::create(const char* name, unsigned int extraLatency, bool checkDe *portpos = 0; char* hostOrIp = strdup(addrpos); free(in); - return new NetworkDevice(name, hostOrIp, port, extraLatency, readOnly, initialSend, udp, enhanced); + return new NetworkDevice(name, hostOrIp, port, extraLatency, udp, enhanced); } // support enh:/dev/, ens:/dev/, and /dev/ - return new SerialDevice(name, checkDevice, extraLatency, readOnly, initialSend, enhanced, highSpeed); -} - -result_t Device::afterOpen() { - if (m_initialSend && !send(ESC)) { - return RESULT_ERR_SEND; - } - return RESULT_OK; + return new SerialDevice(name, checkDevice, extraLatency, enhanced, highSpeed); } -FileDevice::FileDevice(const char* name, bool checkDevice, unsigned int latency, bool readOnly, bool initialSend, + +FileDevice::FileDevice(const char* name, bool checkDevice, unsigned int latency, bool enhancedProto) - : Device(name, readOnly, initialSend), + : Device(name), m_checkDevice(checkDevice), m_latency(HOST_LATENCY_MS+(enhancedProto?ENHANCED_LATENCY_MS:0)+latency), m_enhancedProto(enhancedProto), m_fd(-1), m_resetRequested(false), @@ -164,33 +158,24 @@ FileDevice::~FileDevice() { } } -void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool asJson, bool noWait) { - if (asJson) { - if (m_enhancedProto) { - string ver = getEnhancedVersion(); - if (!ver.empty()) { - *ostream << ",\"dv\":\"" << ver << "\""; - } +void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool prefix) { + if (prefix) { + *ostream << m_name; + string info = getEnhancedProtoInfo(); + if (!info.empty()) { + *ostream << ", " << info; } return; } - *ostream << m_name; - string info = getEnhancedProtoInfo(); - if (!info.empty()) { - *ostream << ", " << info; - } - if (isReadOnly()) { - *ostream << ", readonly"; - } - if (noWait) { - return; - } if (!isValid()) { *ostream << ", invalid"; } + if (!m_enhancedProto) { + return; + } bool infoAdded = false; if (verbose) { - info = getEnhancedInfos(); + string info = getEnhancedInfos(); if (!info.empty()) { *ostream << ", " << info; infoAdded = true; @@ -204,6 +189,15 @@ void FileDevice::formatInfo(ostringstream* ostream, bool verbose, bool asJson, b } } +void FileDevice::formatInfoJson(ostringstream* ostream) { + if (m_enhancedProto) { + string ver = getEnhancedVersion(); + if (!ver.empty()) { + *ostream << ",\"dv\":\"" << ver << "\""; + } + } +} + result_t FileDevice::open() { close(); return m_bufSize == 0 ? RESULT_ERR_DEVICE : RESULT_OK; @@ -220,8 +214,6 @@ result_t FileDevice::afterOpen() { m_listener->notifyStatus(false, "resetting"); } m_resetRequested = true; - } else if (m_initialSend && !write(ESC)) { - return RESULT_ERR_SEND; } return RESULT_OK; } @@ -339,7 +331,7 @@ result_t FileDevice::send(symbol_t value) { if (!isValid()) { return RESULT_ERR_DEVICE; } - if (m_readOnly || !write(value)) { + if (!write(value)) { return RESULT_ERR_SEND; } if (m_listener != nullptr) { @@ -496,9 +488,6 @@ result_t FileDevice::startArbitration(symbol_t masterAddress) { } return RESULT_OK; } - if (m_readOnly) { - return RESULT_ERR_SEND; - } m_arbitrationMaster = masterAddress; if (m_enhancedProto && masterAddress != SYN) { if (!write(masterAddress, true)) { diff --git a/src/lib/ebus/device.h b/src/lib/ebus/device.h index 407f2262..40bc9d62 100755 --- a/src/lib/ebus/device.h +++ b/src/lib/ebus/device.h @@ -99,10 +99,8 @@ class Device { /** * Construct a new instance. * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). - * @param readOnly whether to allow read access to the device only. - * @param initialSend whether to send an initial @a ESC symbol in @a open(). */ - Device(const char* name, bool readOnly, bool initialSend); + explicit Device(const char* name); public: /** @@ -115,13 +113,10 @@ class Device { * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). * @param extraLatency the extra bus transfer latency in milliseconds. * @param checkDevice whether to regularly check the device availability (only for serial devices). - * @param readOnly whether to allow read access to the device only. - * @param initialSend whether to send an initial @a ESC symbol in @a open(). * @return the new @a Device, or nullptr on error. * Note: the caller needs to free the created instance. */ - static Device* create(const char* name, unsigned int extraLatency = 0, bool checkDevice = true, - bool readOnly = false, bool initialSend = false); + static Device* create(const char* name, unsigned int extraLatency = 0, bool checkDevice = true); /** * Get the device name. @@ -129,12 +124,6 @@ class Device { */ const char* getName() const { return m_name; } - /** - * Return whether to allow read access to the device only. - * @return whether to allow read access to the device only. - */ - bool isReadOnly() const { return m_readOnly; } - /** * Set the @a DeviceListener. * @param listener the @a DeviceListener. @@ -142,13 +131,18 @@ class Device { void setListener(DeviceListener* listener) { m_listener = listener; } /** - * Format device infos in plain text or JSON format. + * Format device infos in plain text. * @param output the @a ostringstream to append the infos to. * @param verbose whether to add verbose infos. - * @param asJson whether to format as JSON rather than plain text. - * @param noWait true to not wait for any response asynchronously and return immediately. + * @param prefix true for the synchronously retrievable prefix, false for the potentially asynchronous suffix. */ - virtual void formatInfo(ostringstream* output, bool verbose, bool asJson = false, bool noWait = false) = 0; + virtual void formatInfo(ostringstream* output, bool verbose, bool prefix) = 0; + + /** + * Format device infos in JSON format. + * @param output the @a ostringstream to append the infos to. + */ + virtual void formatInfoJson(ostringstream* output) = 0; /** * Open the file descriptor. @@ -160,7 +154,7 @@ class Device { * Has to be called by subclasses upon successful opening the device as last action in open(). * @return the @a result_t code. */ - virtual result_t afterOpen(); + virtual result_t afterOpen() { return RESULT_OK; } /** * Close the file descriptor if opened. @@ -213,12 +207,6 @@ class Device { /** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */ const char* m_name; - /** whether to allow read access to the device only. */ - const bool m_readOnly; - - /** whether to send an initial @a ESC symbol in @a open(). */ - const bool m_initialSend; - /** the @a DeviceListener, or nullptr. */ DeviceListener* m_listener; }; @@ -234,11 +222,9 @@ class FileDevice : public Device { * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). * @param checkDevice whether to regularly check the device availability. * @param latency the bus transfer latency in milliseconds. - * @param readOnly whether to allow read access to the device only. - * @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param enhancedProto whether to use the ebusd enhanced protocol. */ - FileDevice(const char* name, bool checkDevice, unsigned int latency, bool readOnly, bool initialSend, + FileDevice(const char* name, bool checkDevice, unsigned int latency, bool enhancedProto = false); public: @@ -248,7 +234,10 @@ class FileDevice : public Device { virtual ~FileDevice(); // @copydoc - void formatInfo(ostringstream* output, bool verbose, bool asJson = false, bool noWait = false) override; + void formatInfo(ostringstream* output, bool verbose, bool prefix) override; + + // @copydoc + void formatInfoJson(ostringstream* output) override; // @copydoc result_t open() override; @@ -450,14 +439,12 @@ class SerialDevice : public FileDevice { * @param name the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). * @param checkDevice whether to regularly check the device availability. * @param extraLatency the extra bus transfer latency in milliseconds. - * @param readOnly whether to allow read access to the device only. - * @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param enhancedProto whether to use the ebusd enhanced protocol. * @param enhancedHighSpeed whether to use ebusd enhanced protocol in high speed mode. */ - SerialDevice(const char* name, bool checkDevice, unsigned int extraLatency, bool readOnly, bool initialSend, + SerialDevice(const char* name, bool checkDevice, unsigned int extraLatency, bool enhancedProto = false, bool enhancedHighSpeed = false) - : FileDevice(name, checkDevice, extraLatency, readOnly, initialSend, enhancedProto), + : FileDevice(name, checkDevice, extraLatency, enhancedProto), m_enhancedHighSpeed(enhancedHighSpeed) { } @@ -498,14 +485,12 @@ class NetworkDevice : public FileDevice { * @param hostOrIp the host name or IP address of the device. * @param port the TCP or UDP port of the device. * @param extraLatency the extra bus transfer latency in milliseconds. - * @param readOnly whether to allow read access to the device only. - * @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param udp true for UDP, false to TCP. * @param enhancedProto whether to use the ebusd enhanced protocol. */ - NetworkDevice(const char* name, const char* hostOrIp, uint16_t port, unsigned int extraLatency, bool readOnly, - bool initialSend, bool udp, bool enhancedProto = false) - : FileDevice(name, true, NETWORK_LATENCY_MS+extraLatency, readOnly, initialSend, enhancedProto), + NetworkDevice(const char* name, const char* hostOrIp, uint16_t port, unsigned int extraLatency, + bool udp, bool enhancedProto = false) + : FileDevice(name, true, NETWORK_LATENCY_MS+extraLatency, enhancedProto), m_hostOrIp(hostOrIp), m_port(port), m_udp(udp) {} /** @@ -514,6 +499,7 @@ class NetworkDevice : public FileDevice { ~NetworkDevice() override { if (m_hostOrIp) { free((void*)m_hostOrIp); + m_hostOrIp = nullptr; } } diff --git a/src/lib/ebus/protocol.cpp b/src/lib/ebus/protocol.cpp index 7842120a..9707916a 100644 --- a/src/lib/ebus/protocol.cpp +++ b/src/lib/ebus/protocol.cpp @@ -43,14 +43,35 @@ ProtocolHandler* ProtocolHandler::create(const ebus_protocol_config_t config, return new DirectProtocolHandler(config, device, listener); } +void ProtocolHandler::formatInfo(ostringstream* ostream, bool verbose, bool noWait) { + m_device->formatInfo(ostream, verbose, true); + if (isReadOnly()) { + *ostream << ", readonly"; + } + if (noWait) { + return; + } + m_device->formatInfo(ostream, verbose, false); +} + +void ProtocolHandler::formatInfoJson(ostringstream* ostream) { + m_device->formatInfoJson(ostream); +} + void ProtocolHandler::clear() { memset(m_seenAddresses, 0, sizeof(m_seenAddresses)); m_masterCount = 1; } -bool ProtocolHandler::addRequest(BusRequest* request, bool wait) { +result_t ProtocolHandler::addRequest(BusRequest* request, bool wait) { + if (m_config.readOnly) { + return RESULT_ERR_DEVICE; + } m_nextRequests.push(request); - return !wait || m_finishedRequests.remove(request, true); + if (!wait || m_finishedRequests.remove(request, true)) { + return RESULT_OK; + } + return RESULT_ERR_TIMEOUT; } result_t ProtocolHandler::sendAndWait(const MasterSymbolString& master, SlaveSymbolString* slave) { @@ -63,8 +84,11 @@ result_t ProtocolHandler::sendAndWait(const MasterSymbolString& master, SlaveSym logInfo(lf_bus, "send message: %s", master.getStr().c_str()); for (int sendRetries = m_config.failedSendRetries + 1; sendRetries > 0; sendRetries--) { - bool success = addRequest(&request, true); - result = success ? request.m_result : RESULT_ERR_TIMEOUT; + result = addRequest(&request, true); + bool success = result == RESULT_OK; + if (success) { + result = request.m_result; + } if (result == RESULT_OK) { break; } @@ -103,7 +127,7 @@ bool ProtocolHandler::addSeenAddress(symbol_t address) { return false; } if (!isMaster(address)) { - if (!m_device->isReadOnly() && address == m_ownSlaveAddress) { + if (!m_config.readOnly && address == m_ownSlaveAddress) { if (!m_addressConflict) { m_addressConflict = true; logError(lf_bus, "own slave address %2.2x is used by another participant", address); @@ -122,7 +146,7 @@ bool ProtocolHandler::addSeenAddress(symbol_t address) { return false; } bool ret = false; - if (!m_device->isReadOnly() && address == m_ownMasterAddress) { + if (!m_config.readOnly && address == m_ownMasterAddress) { if (!m_addressConflict) { m_addressConflict = true; logError(lf_bus, "own master address %2.2x is used by another participant", address); diff --git a/src/lib/ebus/protocol.h b/src/lib/ebus/protocol.h index eb743b45..2424ad07 100755 --- a/src/lib/ebus/protocol.h +++ b/src/lib/ebus/protocol.h @@ -52,6 +52,8 @@ namespace ebusd { /** settings for the eBUS protocol handler. */ typedef struct ebus_protocol_config { + /** whether to allow read access to the device only. */ + bool readOnly; /** the own master address. */ symbol_t ownAddress; /** whether to answer queries for the own master/slave address. */ @@ -68,9 +70,19 @@ typedef struct ebus_protocol_config { unsigned int lockCount; /** whether to enable AUTO-SYN symbol generation. */ bool generateSyn; + /** whether to send an initial escape symbol after connecting device. */ + bool initialSend; } ebus_protocol_config_t; +/** the possible protocol states. */ +enum ProtocolState { + ps_noSignal, //!< no signal on the bus + ps_idle, //!< idle (after @a SYN symbol) + ps_empty, //!< idle, no more lock remaining, and no other request queued +}; + + class ProtocolHandler; /** @@ -185,9 +197,9 @@ class ProtocolListener { /** * Called to notify a status update from the protocol. - * @param signal true when signal is acquired, false otherwise. + * @param state the current protocol state. */ - virtual void notifyProtocolStatus(bool signal) = 0; // abstract + virtual void notifyProtocolStatus(ProtocolState state) = 0; // abstract /** * Called to notify a new valid seen address on the bus. @@ -234,7 +246,7 @@ class ProtocolHandler : public WaitThread { m_reconnect(false), m_ownMasterAddress(config.ownAddress), m_ownSlaveAddress(getSlaveAddress(config.ownAddress)), m_addressConflict(false), - m_masterCount(device->isReadOnly()?0:1), + 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) { @@ -266,6 +278,25 @@ class ProtocolHandler : public WaitThread { */ static ProtocolHandler* create(const ebus_protocol_config_t config, Device* device, ProtocolListener* listener); + /** + * Format device/protocol infos in plain text. + * @param output the @a ostringstream to append the infos to. + * @param verbose whether to add verbose infos. + * @param noWait true to not wait for any response asynchronously and return immediately. + */ + virtual void formatInfo(ostringstream* output, bool verbose, bool noWait); + + /** + * Format device/protocol infos in JSON format. + * @param output the @a ostringstream to append the infos to. + */ + virtual void formatInfoJson(ostringstream* output); + + /** + * @return whether to allow read access to the device only. + */ + bool isReadOnly() const { return m_config.readOnly; } + /** * @return the own master address. */ @@ -286,7 +317,7 @@ class ProtocolHandler : public WaitThread { * @return @p true when the address is the own master or slave address (if not readonly). */ bool isOwnAddress(symbol_t address) const { - return !m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress); + return !m_config.readOnly && (address == m_ownMasterAddress || address == m_ownSlaveAddress); } /** @@ -324,9 +355,9 @@ class ProtocolHandler : public WaitThread { * Add a @a BusRequest to the internal queue and optionally wait for it to complete. * @param request the @a BusRequest to add. * @param wait true to wait for it to complete, false to return immediately. - * @return true when it was not waited for or when it was completed. + * @return the result code of adding the request (i.e. RESULT_OK when it was not waited for or when it was completed). */ - virtual bool addRequest(BusRequest* request, bool wait); + virtual result_t addRequest(BusRequest* request, bool wait); /** * Send a message on the bus and wait for the answer. diff --git a/src/lib/ebus/protocol_direct.cpp b/src/lib/ebus/protocol_direct.cpp index 1b170b92..c66bd1cc 100644 --- a/src/lib/ebus/protocol_direct.cpp +++ b/src/lib/ebus/protocol_direct.cpp @@ -91,6 +91,9 @@ void DirectProtocolHandler::run() { result_t result = m_device->open(); if (result == RESULT_OK) { logNotice(lf_bus, "re-opened %s", m_device->getName()); + if (m_config.initialSend && !m_config.readOnly) { + m_device->send(ESC); + } } else { logError(lf_bus, "unable to open %s: %s", m_device->getName(), getResultCode(result)); setState(bs_noSignal, result); @@ -131,6 +134,10 @@ result_t DirectProtocolHandler::handleSymbol() { } if (!m_device->isArbitrating() && m_currentRequest == nullptr && m_remainLockCount == 0) { BusRequest* startRequest = m_nextRequests.peek(); + if (startRequest == nullptr) { + m_listener->notifyProtocolStatus(ps_empty); + startRequest = m_nextRequests.peek(); + } if (startRequest != nullptr) { // initiate arbitration symbol_t master = startRequest->getMaster()[0]; logDebug(lf_bus, "start request %2.2x", master); @@ -220,7 +227,7 @@ result_t DirectProtocolHandler::handleSymbol() { // send symbol if necessary result_t result; struct timespec sentTime, recvTime; - if (sending) { + if (sending && !m_config.readOnly) { if (m_state != bs_sendSyn && (sendSymbol == ESC || sendSymbol == SYN)) { if (m_escape) { sendSymbol = (symbol_t)(sendSymbol == ESC ? 0x00 : 0x01); @@ -254,7 +261,7 @@ result_t DirectProtocolHandler::handleSymbol() { clockGettime(&recvTime); } bool sentAutoSyn = false; - if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0 + if (!sending && !m_config.readOnly && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0 && timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) { // check if acting as AUTO-SYN generator is required result = m_device->send(SYN); @@ -671,7 +678,7 @@ result_t DirectProtocolHandler::setState(BusState state, result_t result, bool f if (state == bs_noSignal) { // notify all requests if (m_state != bs_noSignal) { - m_listener->notifyProtocolStatus(false); + m_listener->notifyProtocolStatus(ps_idle); } m_response.clear(); // notify with empty response while ((m_currentRequest = m_nextRequests.pop()) != nullptr) { @@ -686,7 +693,7 @@ result_t DirectProtocolHandler::setState(BusState state, result_t result, bool f } } } else if (m_state == bs_noSignal) { - m_listener->notifyProtocolStatus(true); + m_listener->notifyProtocolStatus(ps_noSignal); } m_escape = 0;