diff --git a/src/lib/ebus/CMakeLists.txt b/src/lib/ebus/CMakeLists.txt index e3f3b097..dc617ed9 100644 --- a/src/lib/ebus/CMakeLists.txt +++ b/src/lib/ebus/CMakeLists.txt @@ -6,7 +6,8 @@ set(libebus_a_SOURCES filereader.h filereader.cpp datatype.h datatype.cpp data.h data.cpp - device.h device.cpp + device.h device_enhanced.h + device_trans.h device_trans.cpp transport.h transport.cpp protocol.h protocol.cpp protocol_direct.h protocol_direct.cpp diff --git a/src/lib/ebus/Makefile.am b/src/lib/ebus/Makefile.am index 40882f0a..cc4f386a 100644 --- a/src/lib/ebus/Makefile.am +++ b/src/lib/ebus/Makefile.am @@ -10,7 +10,8 @@ libebus_a_SOURCES = \ filereader.h filereader.cpp \ datatype.h datatype.cpp \ data.h data.cpp \ - device.h device.cpp \ + device.h device_enhanced.h \ + device_trans.h device_trans.cpp \ transport.h transport.cpp \ protocol.h protocol.cpp \ protocol_direct.h protocol_direct.cpp \ diff --git a/src/lib/ebus/device.h b/src/lib/ebus/device.h index 8da116a7..a3cbe585 100755 --- a/src/lib/ebus/device.h +++ b/src/lib/ebus/device.h @@ -22,7 +22,6 @@ #include #include #include "lib/ebus/result.h" -#include "lib/ebus/transport.h" #include "lib/ebus/symbol.h" namespace ebusd { @@ -33,10 +32,9 @@ namespace ebusd { * A @a Device allows to send and receive data to/from a local or remote eBUS * device while optionally dumping the data to a file and/or forwarding it to * a logging function. - * The data transport itself is handled by a @a Transport instance. */ -/** the arbitration state handled by @a CharDevice. */ +/** the arbitration state handled by @a Device. */ enum ArbitrationState { as_none, //!< no arbitration in process as_start, //!< arbitration start requested @@ -77,14 +75,13 @@ class DeviceListener { /** * The base class for accessing an eBUS. */ -class Device : public TransportListener { +class Device { protected: /** * Construct a new instance. - * @param transport the @a Transport to use. */ - explicit Device(Transport* transport) - : m_transport(transport), m_listener(nullptr) { + Device() + : m_listener(nullptr) { } public: @@ -92,17 +89,13 @@ class Device : public TransportListener { * Destructor. */ virtual ~Device() { - if (m_transport) { - delete m_transport; - m_transport = nullptr; - } } /** * Get the device name. * @return the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */ - const char* getName() const { return m_transport->getName(); } + virtual const char* getName() const = 0; // abstract /** * Set the @a DeviceListener. @@ -116,13 +109,7 @@ class Device : public TransportListener { * @param verbose whether to add verbose infos. * @param prefix true for the synchronously retrievable prefix, false for the potentially asynchronous suffix. */ - virtual void formatInfo(ostringstream* output, bool verbose, bool prefix) { - if (prefix) { - *output << m_transport->getName() << ", " << m_transport->getTransportInfo(); - } else if (!m_transport->isValid()) { - *output << ", invalid"; - } - } + virtual void formatInfo(ostringstream* output, bool verbose, bool prefix) = 0; // abstract /** * Format device infos in JSON format. @@ -135,50 +122,18 @@ class Device : public TransportListener { */ virtual bool supportsUpdateCheck() const { return false; } - // @copydoc - virtual result_t notifyTransportStatus(bool opened) { - m_listener->notifyDeviceStatus(!opened, opened ? "transport opened" : "transport closed"); - return RESULT_OK; - } - - // @copydoc - virtual void notifyTransportMessage(bool error, const char* message) { - m_listener->notifyDeviceStatus(error, message); - } - /** * Open the file descriptor. * @return the @a result_t code. */ - virtual result_t open() { return m_transport->open(); } + virtual result_t open() = 0; // abstract /** * Return whether the device is opened and available. * @return whether the device is opened and available. */ - virtual bool isValid() { return m_transport->isValid(); } - - protected: - /** the @a Transport to use. */ - Transport* m_transport; - - /** the @a DeviceListener, or nullptr. */ - DeviceListener* m_listener; -}; - - -class CharDevice : public Device { - protected: - /** - * Construct a new instance. - * @param transport the @a Transport to use. - */ - explicit CharDevice(Transport* transport) - : Device(transport), m_arbitrationMaster(SYN), m_arbitrationCheck(0) { - transport->setListener(this); - } + virtual bool isValid() = 0; // abstract - public: /** * Write a single byte to the device. * @param value the byte value to write. @@ -202,156 +157,24 @@ class CharDevice : public Device { * @param masterAddress the master address, or @a SYN to cancel a previous arbitration request. * @return the result_t code. */ - virtual result_t startArbitration(symbol_t masterAddress); + virtual result_t startArbitration(symbol_t masterAddress) = 0; // abstract /** * Return whether the device is currently in arbitration. * @return true when the device is currently in arbitration. */ - virtual bool isArbitrating() const { return m_arbitrationMaster != SYN; } + virtual bool isArbitrating() const = 0; // abstract /** * Cancel a running arbitration. * @param arbitrationState the reference in which @a as_error is stored when cancelled. * @return true if it was cancelled, false if not. */ - virtual bool cancelRunningArbitration(ArbitrationState* arbitrationState); + virtual bool cancelRunningArbitration(ArbitrationState* arbitrationState) = 0; // abstract protected: - /** the arbitration master address to send when in arbitration, or @a SYN. */ - symbol_t m_arbitrationMaster; - - /** >0 when in arbitration and the next received symbol needs to be checked against the sent master address, - * incremented with each received SYN when arbitration was not performed as expected and needs to be stopped. */ - size_t m_arbitrationCheck; -}; - - -class PlainCharDevice : public CharDevice { - public: - /** - * Construct a new instance. - * @param transport the @a Transport to use. - */ - explicit PlainCharDevice(Transport* transport) - : CharDevice(transport) { - } - - // @copydoc - result_t send(symbol_t value) override; - - // @copydoc - result_t recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) override; -}; - - -class EnhancedCharDevice : public CharDevice { - public: - /** - * Construct a new instance. - * @param transport the @a Transport to use. - */ - explicit EnhancedCharDevice(Transport* transport) - : CharDevice(transport), m_resetRequested(false), - m_extraFatures(0), m_infoReqTime(0), m_infoLen(0), m_infoPos(0), m_enhInfoIsWifi(false) { - } - - // @copydoc - void formatInfo(ostringstream* output, bool verbose, bool prefix) override; - - // @copydoc - void formatInfoJson(ostringstream* output) const override; - - // @copydoc - result_t send(symbol_t value) override; - - // @copydoc - result_t recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) override; - - // @copydoc - result_t startArbitration(symbol_t masterAddress) override; - - // @copydoc - virtual result_t notifyTransportStatus(bool opened); - - // @copydoc - bool supportsUpdateCheck() const override { return m_extraFatures & 0x01; } - - /** - * Check for a running extra infos request, wait for it to complete, - * and then send a new request for extra infos to enhanced device. - * @param infoId the ID of the info to request. - * @param wait true to wait for a running request to complete, false to send right away. - * @return @a RESULT_OK on success, or an error code otherwise. - */ - result_t requestEnhancedInfo(symbol_t infoId, bool wait = true); - - /** - * Get the enhanced device version. - * @return @a a string with the version infos, or empty. - */ - string getEnhancedVersion() const { return m_enhInfoVersion; } - - /** - * Retrieve/update all extra infos from an enhanced device. - * @return @a a string with the extra infos, or empty. - */ - string getEnhancedInfos(); - - private: - /** - * Cancel a running arbitration. - * @param arbitrationState the reference in which @a as_error is stored when cancelled. - * @return true if it was cancelled, false if not. - */ - bool cancelRunningArbitration(ArbitrationState* arbitrationState); - - /** - * Handle the already buffered enhanced data. - * @param value the reference in which the read byte value is stored. - * @param arbitrationState the variable in which to store the current/received arbitration state. - * @return the @a result_t code, especially RESULT_CONTINE if the value was set and more data is available immediately. - */ - result_t handleEnhancedBufferedData(const uint8_t* data, size_t len, symbol_t* value, - ArbitrationState* arbitrationState); - - /** - * Called when reception of an info ID was completed. - */ - void notifyInfoRetrieved(); - - /** whether the reset of the device was already requested. */ - bool m_resetRequested; - - /** the extra features supported by the device. */ - symbol_t m_extraFatures; - - /** the time of the last info request. */ - time_t m_infoReqTime; - - /** the info buffer expected length. */ - size_t m_infoLen; - - /** the info buffer write position. */ - size_t m_infoPos; - - /** the info buffer. */ - symbol_t m_infoBuf[16+1]; - - /** a string describing the enhanced device version. */ - string m_enhInfoVersion; - - /** whether the device is known to be connected via WIFI. */ - bool m_enhInfoIsWifi; - - /** a string describing the enhanced device temperature. */ - string m_enhInfoTemperature; - - /** a string describing the enhanced device supply voltage. */ - string m_enhInfoSupplyVoltage; - - /** a string describing the enhanced device bus voltage. */ - string m_enhInfoBusVoltage; + /** the @a DeviceListener, or nullptr. */ + DeviceListener* m_listener; }; } // namespace ebusd diff --git a/src/lib/ebus/device_enhanced.h b/src/lib/ebus/device_enhanced.h new file mode 100755 index 00000000..fe59b6b0 --- /dev/null +++ b/src/lib/ebus/device_enhanced.h @@ -0,0 +1,93 @@ +/* + * ebusd - daemon for communication with eBUS heating systems. + * Copyright (C) 2015-2023 John Baier + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef LIB_EBUS_DEVICE_ENHANCED_H_ +#define LIB_EBUS_DEVICE_ENHANCED_H_ + +#include +#include +#include "lib/ebus/result.h" +#include "lib/ebus/symbol.h" + +namespace ebusd { + +/** @file lib/ebus/device_enhanced.h + * Enhanced protocol definitions for @a Device instances. + */ + +// ebusd enhanced protocol IDs: +#define ENH_REQ_INIT ((uint8_t)0x0) +#define ENH_RES_RESETTED ((uint8_t)0x0) +#define ENH_REQ_SEND ((uint8_t)0x1) +#define ENH_RES_RECEIVED ((uint8_t)0x1) +#define ENH_REQ_START ((uint8_t)0x2) +#define ENH_RES_STARTED ((uint8_t)0x2) +#define ENH_REQ_INFO ((uint8_t)0x3) +#define ENH_RES_INFO ((uint8_t)0x3) +#define ENH_RES_FAILED ((uint8_t)0xa) +#define ENH_RES_ERROR_EBUS ((uint8_t)0xb) +#define ENH_RES_ERROR_HOST ((uint8_t)0xc) + +// ebusd enhanced error codes for the ENH_RES_ERROR_* responses +#define ENH_ERR_FRAMING ((uint8_t)0x00) +#define ENH_ERR_OVERRUN ((uint8_t)0x01) + +#define ENH_BYTE_FLAG ((uint8_t)0x80) +#define ENH_BYTE_MASK ((uint8_t)0xc0) +#define ENH_BYTE1 ((uint8_t)0xc0) +#define ENH_BYTE2 ((uint8_t)0x80) +#define makeEnhancedByte1(cmd, data) (uint8_t)(ENH_BYTE1 | ((cmd) << 2) | (((data)&0xc0) >> 6)) +#define makeEnhancedByte2(cmd, data) (uint8_t)(ENH_BYTE2 | ((data)&0x3f)) +#define makeEnhancedSequence(cmd, data) {makeEnhancedByte1(cmd, data), makeEnhancedByte2(cmd, data)} + + +/** + * Interface for an enhanced @a Device. + */ +class EnhancedDeviceInterface { + public: + /** + * Destructor. + */ + virtual ~EnhancedDeviceInterface() {} + + /** + * Check for a running extra infos request, wait for it to complete, + * and then send a new request for extra infos to enhanced device. + * @param infoId the ID of the info to request. + * @param wait true to wait for a running request to complete, false to send right away. + * @return @a RESULT_OK on success, or an error code otherwise. + */ + virtual result_t requestEnhancedInfo(symbol_t infoId, bool wait = true) = 0; // abstract + + /** + * Get the enhanced device version. + * @return @a a string with the version infos, or empty. + */ + virtual string getEnhancedVersion() const = 0; // abstract + + /** + * Retrieve/update all extra infos from an enhanced device. + * @return @a a string with the extra infos, or empty. + */ + virtual string getEnhancedInfos() = 0; // abstract +}; + +} // namespace ebusd + +#endif // LIB_EBUS_DEVICE_ENHANCED_H_ diff --git a/src/lib/ebus/device.cpp b/src/lib/ebus/device_trans.cpp similarity index 88% rename from src/lib/ebus/device.cpp rename to src/lib/ebus/device_trans.cpp index 55494bd1..97e6fa2b 100755 --- a/src/lib/ebus/device.cpp +++ b/src/lib/ebus/device_trans.cpp @@ -20,7 +20,7 @@ # include #endif -#include "lib/ebus/device.h" +#include "lib/ebus/device_trans.h" #include #include #include @@ -35,33 +35,33 @@ using std::setw; using std::setprecision; using std::fixed; -// ebusd enhanced protocol IDs: -#define ENH_REQ_INIT ((uint8_t)0x0) -#define ENH_RES_RESETTED ((uint8_t)0x0) -#define ENH_REQ_SEND ((uint8_t)0x1) -#define ENH_RES_RECEIVED ((uint8_t)0x1) -#define ENH_REQ_START ((uint8_t)0x2) -#define ENH_RES_STARTED ((uint8_t)0x2) -#define ENH_REQ_INFO ((uint8_t)0x3) -#define ENH_RES_INFO ((uint8_t)0x3) -#define ENH_RES_FAILED ((uint8_t)0xa) -#define ENH_RES_ERROR_EBUS ((uint8_t)0xb) -#define ENH_RES_ERROR_HOST ((uint8_t)0xc) -// ebusd enhanced error codes for the ENH_RES_ERROR_* responses -#define ENH_ERR_FRAMING ((uint8_t)0x00) -#define ENH_ERR_OVERRUN ((uint8_t)0x01) -#define ENH_BYTE_FLAG ((uint8_t)0x80) -#define ENH_BYTE_MASK ((uint8_t)0xc0) -#define ENH_BYTE1 ((uint8_t)0xc0) -#define ENH_BYTE2 ((uint8_t)0x80) -#define makeEnhancedByte1(cmd, data) (uint8_t)(ENH_BYTE1 | ((cmd) << 2) | (((data)&0xc0) >> 6)) -#define makeEnhancedByte2(cmd, data) (uint8_t)(ENH_BYTE2 | ((data)&0x3f)) -#define makeEnhancedSequence(cmd, data) {makeEnhancedByte1(cmd, data), makeEnhancedByte2(cmd, data)} +result_t BaseDevice::startArbitration(symbol_t masterAddress) { + if (m_arbitrationCheck) { + if (masterAddress != SYN) { + return RESULT_ERR_ARB_RUNNING; // should not occur + } + return RESULT_OK; + } + m_arbitrationMaster = masterAddress; + return RESULT_OK; +} +bool BaseDevice::cancelRunningArbitration(ArbitrationState* arbitrationState) { + if (m_arbitrationMaster == SYN) { + return false; + } + if (arbitrationState) { + *arbitrationState = as_error; + } + m_arbitrationMaster = SYN; + m_arbitrationCheck = 0; + return true; +} -result_t PlainCharDevice::send(symbol_t value) { + +result_t PlainDevice::send(symbol_t value) { result_t result = m_transport->write(&value, 1); if (result == RESULT_OK && m_listener != nullptr) { m_listener->notifyDeviceData(&value, 1, false); @@ -69,7 +69,7 @@ result_t PlainCharDevice::send(symbol_t value) { return result; } -result_t PlainCharDevice::recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) { +result_t PlainDevice::recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) { if (m_arbitrationMaster != SYN && arbitrationState) { *arbitrationState = as_running; } @@ -133,32 +133,9 @@ result_t PlainCharDevice::recv(unsigned int timeout, symbol_t* value, Arbitratio return result; } -result_t CharDevice::startArbitration(symbol_t masterAddress) { - if (m_arbitrationCheck) { - if (masterAddress != SYN) { - return RESULT_ERR_ARB_RUNNING; // should not occur - } - return RESULT_OK; - } - m_arbitrationMaster = masterAddress; - return RESULT_OK; -} - -bool CharDevice::cancelRunningArbitration(ArbitrationState* arbitrationState) { - if (m_arbitrationMaster == SYN) { - return false; - } - if (arbitrationState) { - *arbitrationState = as_error; - } - m_arbitrationMaster = SYN; - m_arbitrationCheck = 0; - return true; -} - -void EnhancedCharDevice::formatInfo(ostringstream* ostream, bool verbose, bool prefix) { - CharDevice::formatInfo(ostream, verbose, prefix); +void EnhancedDevice::formatInfo(ostringstream* ostream, bool verbose, bool prefix) { + BaseDevice::formatInfo(ostream, verbose, prefix); if (prefix) { *ostream << ", enhanced"; return; @@ -179,14 +156,14 @@ void EnhancedCharDevice::formatInfo(ostringstream* ostream, bool verbose, bool p } } -void EnhancedCharDevice::formatInfoJson(ostringstream* ostream) const { +void EnhancedDevice::formatInfoJson(ostringstream* ostream) const { string ver = getEnhancedVersion(); if (!ver.empty()) { *ostream << ",\"dv\":\"" << ver << "\""; } } -result_t EnhancedCharDevice::requestEnhancedInfo(symbol_t infoId, bool wait) { +result_t EnhancedDevice::requestEnhancedInfo(symbol_t infoId, bool wait) { if (m_extraFatures == 0) { return RESULT_ERR_INVALID_ARG; } @@ -228,7 +205,7 @@ result_t EnhancedCharDevice::requestEnhancedInfo(symbol_t infoId, bool wait) { return result; } -string EnhancedCharDevice::getEnhancedInfos() { +string EnhancedDevice::getEnhancedInfos() { if (m_extraFatures == 0) { return ""; } @@ -281,7 +258,7 @@ string EnhancedCharDevice::getEnhancedInfos() { + m_enhInfoBusVoltage; } -result_t EnhancedCharDevice::send(symbol_t value) { +result_t EnhancedDevice::send(symbol_t value) { uint8_t buf[] = makeEnhancedSequence(ENH_REQ_SEND, value); result_t result = m_transport->write(buf, 2); if (result == RESULT_OK && m_listener != nullptr) { @@ -290,7 +267,7 @@ result_t EnhancedCharDevice::send(symbol_t value) { return result; } -result_t EnhancedCharDevice::recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) { +result_t EnhancedDevice::recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) { if (arbitrationState && m_arbitrationMaster != SYN) { *arbitrationState = as_running; } @@ -322,7 +299,7 @@ result_t EnhancedCharDevice::recv(unsigned int timeout, symbol_t* value, Arbitra return result; } -result_t EnhancedCharDevice::startArbitration(symbol_t masterAddress) { +result_t EnhancedDevice::startArbitration(symbol_t masterAddress) { if (m_arbitrationCheck) { if (masterAddress != SYN) { return RESULT_ERR_ARB_RUNNING; // should not occur @@ -345,16 +322,16 @@ result_t EnhancedCharDevice::startArbitration(symbol_t masterAddress) { return RESULT_OK; } -bool EnhancedCharDevice::cancelRunningArbitration(ArbitrationState* arbitrationState) { - if (!CharDevice::cancelRunningArbitration(arbitrationState)) { +bool EnhancedDevice::cancelRunningArbitration(ArbitrationState* arbitrationState) { + if (!BaseDevice::cancelRunningArbitration(arbitrationState)) { return false; } symbol_t buf[2] = makeEnhancedSequence(ENH_REQ_START, SYN); return m_transport->write(buf, 2) == RESULT_OK; } -result_t EnhancedCharDevice::notifyTransportStatus(bool opened) { - result_t result = CharDevice::notifyTransportStatus(opened); // always OK +result_t EnhancedDevice::notifyTransportStatus(bool opened) { + result_t result = BaseDevice::notifyTransportStatus(opened); // always OK if (opened) { symbol_t buf[2] = makeEnhancedSequence(ENH_REQ_INIT, 0x01); // extra feature: info result = m_transport->write(buf, 2); @@ -377,7 +354,7 @@ result_t EnhancedCharDevice::notifyTransportStatus(bool opened) { return result; } -result_t EnhancedCharDevice::handleEnhancedBufferedData(const uint8_t* data, size_t len, +result_t EnhancedDevice::handleEnhancedBufferedData(const uint8_t* data, size_t len, symbol_t* value, ArbitrationState* arbitrationState) { bool valueSet = false; bool sent = false; @@ -533,7 +510,7 @@ symbol_t* value, ArbitrationState* arbitrationState) { return more ? RESULT_CONTINUE : valueSet ? RESULT_OK : RESULT_ERR_TIMEOUT; } -void EnhancedCharDevice::notifyInfoRetrieved() { +void EnhancedDevice::notifyInfoRetrieved() { symbol_t id = m_infoBuf[0]; symbol_t* data = m_infoBuf+1; size_t len = m_infoLen-1; @@ -559,7 +536,7 @@ void EnhancedCharDevice::notifyInfoRetrieved() { stream << "firmware " << m_enhInfoVersion; if (len >= 5) { stream << ", jumpers 0x" << setw(2) << static_cast(data[4]); - m_enhInfoIsWifi = (data[4]&0x08)!=0; + m_enhInfoIsWifi = (data[4]&0x08) != 0; } stream << setfill(' '); // reset break; diff --git a/src/lib/ebus/device_trans.h b/src/lib/ebus/device_trans.h new file mode 100755 index 00000000..5868d4fe --- /dev/null +++ b/src/lib/ebus/device_trans.h @@ -0,0 +1,228 @@ +/* + * ebusd - daemon for communication with eBUS heating systems. + * Copyright (C) 2015-2023 John Baier + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef LIB_EBUS_DEVICE_TRANS_H_ +#define LIB_EBUS_DEVICE_TRANS_H_ + +#include +#include +#include "lib/ebus/device.h" +#include "lib/ebus/device_enhanced.h" +#include "lib/ebus/transport.h" +#include "lib/ebus/result.h" +#include "lib/ebus/symbol.h" + +namespace ebusd { + +/** @file lib/ebus/device_trans.h + * Classes providing access to the eBUS via a @a Transport instance. + */ + +/** + * The base class for accessing an eBUS via a @a Transport instance. + */ +class BaseDevice : public Device, public TransportListener { + protected: + /** + * Construct a new instance. + * @param transport the @a Transport to use. + */ + explicit BaseDevice(Transport* transport) + : Device(), m_transport(transport), + m_arbitrationMaster(SYN), m_arbitrationCheck(0) { + } + + public: + /** + * Destructor. + */ + virtual ~BaseDevice() { + if (m_transport) { + delete m_transport; + m_transport = nullptr; + } + } + + // @copydoc + virtual const char* getName() const { return m_transport->getName(); } + + // @copydoc + virtual void formatInfo(ostringstream* output, bool verbose, bool prefix) { + if (prefix) { + *output << m_transport->getName() << ", " << m_transport->getTransportInfo(); + } else if (!m_transport->isValid()) { + *output << ", invalid"; + } + } + + // @copydoc + virtual void formatInfoJson(ostringstream* output) const {} + + // @copydoc + virtual result_t notifyTransportStatus(bool opened) { + m_listener->notifyDeviceStatus(!opened, opened ? "transport opened" : "transport closed"); + return RESULT_OK; + } + + // @copydoc + virtual void notifyTransportMessage(bool error, const char* message) { + m_listener->notifyDeviceStatus(error, message); + } + + // @copydoc + virtual result_t open() { return m_transport->open(); } + + // @copydoc + virtual bool isValid() { return m_transport->isValid(); } + + // @copydoc + virtual result_t startArbitration(symbol_t masterAddress); + + // @copydoc + virtual bool isArbitrating() const { return m_arbitrationMaster != SYN; } + + // @copydoc + virtual bool cancelRunningArbitration(ArbitrationState* arbitrationState); + + protected: + /** the @a Transport to use. */ + Transport* m_transport; + + /** the arbitration master address to send when in arbitration, or @a SYN. */ + symbol_t m_arbitrationMaster; + + /** >0 when in arbitration and the next received symbol needs to be checked against the sent master address, + * incremented with each received SYN when arbitration was not performed as expected and needs to be stopped. */ + size_t m_arbitrationCheck; +}; + + +class PlainDevice : public BaseDevice { + public: + /** + * Construct a new instance. + * @param transport the @a Transport to use. + */ + explicit PlainDevice(Transport* transport) + : BaseDevice(transport) { + } + + // @copydoc + result_t send(symbol_t value) override; + + // @copydoc + result_t recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) override; +}; + + +class EnhancedDevice : public BaseDevice, public EnhancedDeviceInterface { + public: + /** + * Construct a new instance. + * @param transport the @a Transport to use. + */ + explicit EnhancedDevice(Transport* transport) + : BaseDevice(transport), EnhancedDeviceInterface(), m_resetRequested(false), + m_extraFatures(0), m_infoReqTime(0), m_infoLen(0), m_infoPos(0), m_enhInfoIsWifi(false) { + } + + // @copydoc + void formatInfo(ostringstream* output, bool verbose, bool prefix) override; + + // @copydoc + void formatInfoJson(ostringstream* output) const override; + + // @copydoc + result_t send(symbol_t value) override; + + // @copydoc + result_t recv(unsigned int timeout, symbol_t* value, ArbitrationState* arbitrationState) override; + + // @copydoc + result_t startArbitration(symbol_t masterAddress) override; + + // @copydoc + virtual result_t notifyTransportStatus(bool opened); + + // @copydoc + bool supportsUpdateCheck() const override { return m_extraFatures & 0x01; } + + // @copydoc + virtual result_t requestEnhancedInfo(symbol_t infoId, bool wait = true); + + // @copydoc + virtual string getEnhancedVersion() const { return m_enhInfoVersion; } + + // @copydoc + virtual string getEnhancedInfos(); + + // @copydoc + virtual bool cancelRunningArbitration(ArbitrationState* arbitrationState); + + private: + /** + * Handle the already buffered enhanced data. + * @param value the reference in which the read byte value is stored. + * @param arbitrationState the variable in which to store the current/received arbitration state. + * @return the @a result_t code, especially RESULT_CONTINE if the value was set and more data is available immediately. + */ + result_t handleEnhancedBufferedData(const uint8_t* data, size_t len, symbol_t* value, + ArbitrationState* arbitrationState); + + /** + * Called when reception of an info ID was completed. + */ + void notifyInfoRetrieved(); + + /** whether the reset of the device was already requested. */ + bool m_resetRequested; + + /** the extra features supported by the device. */ + symbol_t m_extraFatures; + + /** the time of the last info request. */ + time_t m_infoReqTime; + + /** the info buffer expected length. */ + size_t m_infoLen; + + /** the info buffer write position. */ + size_t m_infoPos; + + /** the info buffer. */ + symbol_t m_infoBuf[16+1]; + + /** a string describing the enhanced device version. */ + string m_enhInfoVersion; + + /** whether the device is known to be connected via WIFI. */ + bool m_enhInfoIsWifi; + + /** a string describing the enhanced device temperature. */ + string m_enhInfoTemperature; + + /** a string describing the enhanced device supply voltage. */ + string m_enhInfoSupplyVoltage; + + /** a string describing the enhanced device bus voltage. */ + string m_enhInfoBusVoltage; +}; + +} // namespace ebusd + +#endif // LIB_EBUS_DEVICE_TRANS_H_ diff --git a/src/lib/ebus/protocol.cpp b/src/lib/ebus/protocol.cpp index 3d605f67..51932c59 100644 --- a/src/lib/ebus/protocol.cpp +++ b/src/lib/ebus/protocol.cpp @@ -22,6 +22,7 @@ #include #include +#include "lib/ebus/device_trans.h" #include "lib/ebus/protocol.h" #include "lib/ebus/protocol_direct.h" #include "lib/utils/log.h" @@ -97,11 +98,11 @@ ProtocolHandler* ProtocolHandler::create(const ebus_protocol_config_t config, // support ens:/dev/, enh:/dev/, and /dev/ transport = new SerialTransport(name, config.extraLatency, !config.noDeviceCheck, speed); } - CharDevice* device; + Device* device; if (enhanced) { - device = new EnhancedCharDevice(transport); + device = new EnhancedDevice(transport); } else { - device = new PlainCharDevice(transport); + device = new PlainDevice(transport); } return new DirectProtocolHandler(config, device, listener); } diff --git a/src/lib/ebus/protocol_direct.h b/src/lib/ebus/protocol_direct.h index 984b5513..8db3f5ce 100755 --- a/src/lib/ebus/protocol_direct.h +++ b/src/lib/ebus/protocol_direct.h @@ -65,8 +65,8 @@ class DirectProtocolHandler : public ProtocolHandler { * @param listener the @a ProtocolListener. */ DirectProtocolHandler(const ebus_protocol_config_t config, - CharDevice* device, ProtocolListener* listener) - : ProtocolHandler(config, device, listener), m_device(device), + Device* device, ProtocolListener* listener) + : ProtocolHandler(config, device, listener), m_lockCount(config.lockCount <= 3 ? 3 : config.lockCount), m_remainLockCount(config.lockCount == 0 ? 1 : 0), m_generateSynInterval(config.generateSyn ? 10*getMasterNumber(config.ownAddress)+SYN_TIMEOUT : 0), @@ -146,9 +146,6 @@ class DirectProtocolHandler : public ProtocolHandler { */ void messageCompleted(); - /** the @a CharDevice instance for accessing the bus. */ - CharDevice* m_device; - /** the number of AUTO-SYN symbols before sending is allowed after lost arbitration. */ unsigned int m_lockCount;