From 8571574085160bc71177f68795f09b17b3c2ad7f Mon Sep 17 00:00:00 2001 From: Lionel Ains Date: Thu, 14 May 2020 09:41:34 +0200 Subject: [PATCH] Add version getter to api (#57) * Moving XNCP version storage into a dedicated class NSEZSP::EzspAdapterVersion * Creating a getter API in libezsp to retrieve XNCP info (fw+hw versions) * Adding EZSP version details to EzspAdapterVersion class * Implementing EzspAdapterVersion::toString() and using it as example in mainEzspTest --- example/mainEzspStateMachine.h | 1 + include/ezsp/ezsp-adapter-version.h | 103 ++++++++++++++ include/ezsp/ezsp-protocol/ezsp-enum.h | 1 + .../ember-gp-sink-table-options-field.h | 6 +- include/ezsp/ezsp.h | 10 +- src/ezsp/CMakeLists.txt | 7 +- src/ezsp/ezsp-adapter-version.cpp | 98 +++++++++++++ src/ezsp/ezsp-dongle.cpp | 20 +++ src/ezsp/ezsp-dongle.h | 49 ++++++- .../get-network-parameters-response.cpp | 2 +- .../struct/ember-gp-address-struct.cpp | 3 +- .../struct/ember-gp-address-struct.h | 4 +- .../ember-gp-sink-table-options-field.cpp | 3 +- .../struct/ember-network-parameters.cpp | 3 +- .../struct/ember-network-parameters.h | 4 +- src/ezsp/ezsp.cpp | 4 + src/ezsp/lib-ezsp-main.cpp | 133 ++++++++---------- src/ezsp/lib-ezsp-main.h | 7 + 18 files changed, 361 insertions(+), 97 deletions(-) create mode 100644 include/ezsp/ezsp-adapter-version.h create mode 100644 src/ezsp/ezsp-adapter-version.cpp diff --git a/example/mainEzspStateMachine.h b/example/mainEzspStateMachine.h index 62ec8ee6..0aaaf74e 100644 --- a/example/mainEzspStateMachine.h +++ b/example/mainEzspStateMachine.h @@ -102,6 +102,7 @@ class MainStateMachine { * @brief Set internal state machine to run mode (waiting for asynchronous sensor reports) */ void ezspRun() { + clogI << "Adapter version: " << this->libEzsp.getAdapterVersion() << "\n"; clogI << "Preparation steps finished... switching to run state\n"; this->currentState = MainState::RUN; } diff --git a/include/ezsp/ezsp-adapter-version.h b/include/ezsp/ezsp-adapter-version.h new file mode 100644 index 00000000..e53f7115 --- /dev/null +++ b/include/ezsp/ezsp-adapter-version.h @@ -0,0 +1,103 @@ +/** + * @file ezsp-adapter-version.h + * + * @brief Handling EZSP adapter versions (firmware and hardware) + */ + +#ifndef __EZSP_ADAPTER_VERSION_H__ +#define __EZSP_ADAPTER_VERSION_H__ + +#include +#include + +#include + +namespace NSEZSP { + +/** + * @brief Class storing information about the EZSP adapter + */ +class LIBEXPORT EzspAdapterVersion { +public: + enum class Manufacturer { + UNKNOWN = 0, + LEGRAND = 0x1021 + }; + + EzspAdapterVersion(); + ~EzspAdapterVersion() = default; + + /** + * @brief Store the EZSP stack version present inside an EZSP version info packet + * + * @param ezspStackVersion The EZSP stack version + */ + void setEzspVersionInfo(uint16_t ezspStackVersion); + + /** + * @brief Store EZSP version data present inside an EZSP version info packet + * + * @param ezspStackVersion The EZSP stack version + * @param ezspProtocolVersion The EZSP protocol version (EZSPv7, EZSPv8) + * @param ezspStackType The EZSP stack type + */ + void setEzspVersionInfo(uint16_t ezspStackVersion, uint8_t ezspProtocolVersion, uint8_t ezspStackType); + + /** + * @brief Store EZSP XNCP data present inside an EZSP XNCP info packet + * + * @param xncpManufacturerId The manufacturer ID (16-bit ID) + * @param xncpVersionNumber The Legrand XNCP 16-bit encoded hardware+firmware version (encoding is proprietary from Legrand) + */ + void setXncpData(uint16_t xncpManufacturerId, uint16_t xncpVersionNumber); + + /** + * @brief Get a string representation of the XNCP firmware version data + * + * @return The firmware version as a string + */ + std::string getFirmwareVersionAsString() const; + + /** + * @brief Get a string representation of the embedded stack version data + * + * @return The stack version as a string + */ + std::string getStackVersionAsString() const; + + /** + * @brief Represent the information stored by this instance as a string + * + * @result The resulting string + */ + std::string toString() const; + + /** + * @brief Serialize to an iostream + * + * @param out The original output stream + * @param data The object to serialize + * + * @return The new output stream with serialized data appended + */ + friend std::ostream& operator<< (std::ostream& out, const EzspAdapterVersion& data){ + out << data.toString(); + return out; + } + + unsigned int ezspProtocolVersion; /* #include #include +#include #include #include @@ -48,7 +49,7 @@ typedef CLibEzspPublic::State CLibEzspState; /* Shortcut for access to public class CLibEzspMain; -typedef std::function FLibStateCallback; /*!< Callback type for method registerLibraryStateCallback() */ +typedef std::function FLibStateCallback; /*!< Callback type for method registerLibraryStateCallback() */ typedef std::function FGpSourceIdCallback; /*!< Callback type for method registerGPSourceIdCallback() */ typedef std::function FGpFrameRecvCallback; /*!< Callback type for method registerGPFrameRecvCallback() */ typedef std::function)> FEnergyScanCallback; /*!< Callback type for method startEnergyScan() */ @@ -71,6 +72,13 @@ class LIBEXPORT CEzsp { */ void start(); + /** + * @brief Get the EZSP adapter's version + * + * @return The EZSP adapter version (hardware and firmware) if already known + */ + NSEZSP::EzspAdapterVersion getAdapterVersion() const; + /** * @brief Instruct the library to directly switch to firmware upgrade mode at init if we get an EZSP timeout * diff --git a/src/ezsp/CMakeLists.txt b/src/ezsp/CMakeLists.txt index 8f0708ed..a9c647a6 100644 --- a/src/ezsp/CMakeLists.txt +++ b/src/ezsp/CMakeLists.txt @@ -5,6 +5,7 @@ list(APPEND ezsp_SOURCES ash.cpp bootloader-prompt.cpp ezsp-dongle.cpp + ezsp-adapter-version.cpp ezsp-protocol/ezsp-enum.cpp ezsp-protocol/get-network-parameters-response.cpp ezsp-protocol/struct/ember-child-data-struct.cpp @@ -36,7 +37,8 @@ option(USE_BUILTIN_MIC_PROCESSING "Compute and check MIC on the host rather than configure_file(${PROJECT_SOURCE_DIR}/src/ezsp/config.h.in ${PROJECT_SOURCE_DIR}/include/ezsp/config.h) -set(ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/gpd.h) +set(ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/ezsp.h) +list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/export.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/enum-generator.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/gpd.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/zbmessage/zcl.h) @@ -44,8 +46,7 @@ list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/zbmessage/gpd list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/zbmessage/green-power-frame.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/zbmessage/green-power-device.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/byte-manip.h) -list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/ezsp.h) -list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/export.h) +list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/ezsp-adapter-version.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/ezsp-protocol/struct/ember-gp-sink-table-options-field.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/ezsp/ezsp-protocol/ezsp-enum.h) list(APPEND ezsp_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/config.h) diff --git a/src/ezsp/ezsp-adapter-version.cpp b/src/ezsp/ezsp-adapter-version.cpp new file mode 100644 index 00000000..c32151e6 --- /dev/null +++ b/src/ezsp/ezsp-adapter-version.cpp @@ -0,0 +1,98 @@ +/** + * @file ezsp-adapter-version.cpp + * + * @brief Handling EZSP adapter versions (firmware and hardware) + */ + +#include +#include + +#include + +#include "ezsp/byte-manip.h" + +using NSEZSP::EzspAdapterVersion; + +EzspAdapterVersion::EzspAdapterVersion() : + ezspProtocolVersion(0), + ezspStackType(0), + ezspStackMajorVersion(0), + ezspStackMinorVersion(0), + ezspStackRevisionVersion(0), + ezspStackBugfixVersion(0), + xncpManufacturerId(static_cast(Manufacturer::UNKNOWN)), + xncpAdapterHardwareVersion(0), + xncpAdapterMajorVersion(0), + xncpAdapterMinorVersion(0), + xncpAdapterRevisionVersion(0) { +} + +void EzspAdapterVersion::setEzspVersionInfo(uint16_t ezspStackVersion) { + this->ezspStackMajorVersion = u8_get_hi_nibble(u16_get_hi_u8(ezspStackVersion)); + this->ezspStackMinorVersion = u8_get_lo_nibble(u16_get_hi_u8(ezspStackVersion)); + this->ezspStackRevisionVersion = u8_get_hi_nibble(u16_get_lo_u8(ezspStackVersion)); + this->ezspStackBugfixVersion = u8_get_lo_nibble(u16_get_lo_u8(ezspStackVersion)); +} + +void EzspAdapterVersion::setEzspVersionInfo(uint16_t ezspStackVersion, uint8_t ezspProtocolVersion, uint8_t ezspStackType) { + this->setEzspVersionInfo(ezspStackVersion); + this->ezspProtocolVersion = ezspProtocolVersion; + this->ezspStackType = ezspStackType; +} + +void EzspAdapterVersion::setXncpData(uint16_t xncpManufacturerId, uint16_t xncpVersionNumber) { + this->xncpManufacturerId = xncpManufacturerId; + this->xncpAdapterHardwareVersion = u8_get_hi_nibble(u16_get_hi_u8(xncpVersionNumber)); /* High nibble of MSB */ + this->xncpAdapterMajorVersion = u8_get_lo_nibble(u16_get_hi_u8(xncpVersionNumber)); /* Low nibble of MSB */ + this->xncpAdapterMinorVersion = u8_get_hi_nibble(u16_get_lo_u8(xncpVersionNumber)); /* High nibble of LSB */ + this->xncpAdapterRevisionVersion = u8_get_lo_nibble(u16_get_lo_u8(xncpVersionNumber)); /* Low nibble of LSB */ +} + +std::string EzspAdapterVersion::getFirmwareVersionAsString() const { + std::stringstream result; + result << this->xncpAdapterMajorVersion << "." << this->xncpAdapterMinorVersion << "." << this->xncpAdapterRevisionVersion; + return result.str(); +} + +std::string EzspAdapterVersion::getStackVersionAsString() const { + std::stringstream result; + result << static_cast(this->ezspStackMajorVersion) << "."; + result << static_cast(this->ezspStackMinorVersion) << "."; + result << static_cast(this->ezspStackRevisionVersion) << "."; + result << static_cast(this->ezspStackBugfixVersion); + return result.str(); +} + +std::string EzspAdapterVersion::toString() const { + std::stringstream buf; + + buf << "EzspAdapterVersion : { "; + if (this->xncpManufacturerId != static_cast(Manufacturer::UNKNOWN)) { + buf << "[Manufacturer: 0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast(this->xncpManufacturerId); + if (this->xncpManufacturerId == static_cast(Manufacturer::LEGRAND)) { + buf << " (LEGRAND)"; + } + buf << "]"; + } + if (this->ezspProtocolVersion) { + buf << "[EZSPv" << std::dec << std::setw(0) << static_cast(this->ezspProtocolVersion); + buf << " running stack type " << static_cast(this->ezspStackType); + if (this->ezspStackType == 2) { + buf << " (mesh)"; + } + buf << "]"; + } + if (this->ezspStackMajorVersion || this->ezspStackMinorVersion || this->ezspStackRevisionVersion || this->ezspStackBugfixVersion) { + buf << "[stack v" << this->getStackVersionAsString() << "]"; + } + /* XNCP can only be properly decoded if manufacturer is Legrand */ + if (this->xncpManufacturerId == static_cast(Manufacturer::LEGRAND)) { + if (this->xncpAdapterHardwareVersion || this->xncpAdapterMajorVersion || this->xncpAdapterMinorVersion || this->xncpAdapterRevisionVersion) { + buf << "[hw v" << this->xncpAdapterHardwareVersion; + buf << ", fw v" << this->getFirmwareVersionAsString() << "]"; + } + } + buf << " }"; + + return buf.str(); +} diff --git a/src/ezsp/ezsp-dongle.cpp b/src/ezsp/ezsp-dongle.cpp index 2f420bdb..6d2e3ec8 100644 --- a/src/ezsp/ezsp-dongle.cpp +++ b/src/ezsp/ezsp-dongle.cpp @@ -13,6 +13,7 @@ using NSEZSP::CEzspDongle; CEzspDongle::CEzspDongle(const NSSPI::TimerBuilder& i_timer_builder, CEzspDongleObserver* ip_observer) : firstStartup(true), + version(), lastKnownMode(CEzspDongle::Mode::UNKNOWN), switchToFirmwareUpgradeOnInitTimeout(false), timerBuilder(i_timer_builder), @@ -64,6 +65,25 @@ bool CEzspDongle::reset() { return true; } +void CEzspDongle::setFetchedXncpData(uint16_t xncpManufacturerId, uint16_t xncpVersionNumber) { + this->version.setXncpData(xncpManufacturerId, xncpVersionNumber); + this->notifyObserversOfDongleState(DONGLE_VERSION_RETRIEVED); /* Notify observers that we now know the EZSP adapter's version */ +} + +void CEzspDongle::setFetchedEzspVersionData(uint16_t ezspStackVersion) { + this->version.setEzspVersionInfo(ezspStackVersion); + this->notifyObserversOfDongleState(DONGLE_VERSION_RETRIEVED); /* Notify observers that we now know the EZSP adapter's version */ +} + +void CEzspDongle::setFetchedEzspVersionData(uint16_t ezspStackVersion, uint8_t ezspProtocolVersion, uint8_t ezspStackType) { + this->version.setEzspVersionInfo(ezspStackVersion, ezspProtocolVersion, ezspStackType); + this->notifyObserversOfDongleState(DONGLE_VERSION_RETRIEVED); /* Notify observers that we now know the EZSP adapter's version */ +} + +NSEZSP::EzspAdapterVersion CEzspDongle::getVersion() const { + return this->version; +} + void CEzspDongle::ashCbInfo(CAsh::EAshInfo info) { clogD << "ashCbInfo : " << CAsh::getEAshInfoAsString(info) << "\n"; diff --git a/src/ezsp/ezsp-dongle.h b/src/ezsp/ezsp-dongle.h index 1dafb63f..0c775727 100644 --- a/src/ezsp/ezsp-dongle.h +++ b/src/ezsp/ezsp-dongle.h @@ -6,15 +6,17 @@ #include #include -#include "spi/IUartDriver.h" +#include +#include +#include +#include +#include +#include +#include "ezsp/enum-generator.h" + #include "ash.h" #include "bootloader-prompt.h" #include "ezsp-dongle-observer.h" -#include -#include "spi/TimerBuilder.h" -#include "spi/IAsyncDataInputObserver.h" -#include "spi/ByteBuffer.h" -#include "ezsp/enum-generator.h" extern "C" { /* Avoid compiler warning on member initialization for structs (in -Weffc++ mode) */ typedef struct { @@ -65,6 +67,40 @@ class CEzspDongle : public NSSPI::IAsyncDataInputObserver, public CAshCallback */ bool reset(); + /** + * @brief Set the current hardware & firmware XNCP version running on the EZSP adapter + * + * @param xncpManufacturerId The XNCP 16-bit manufacturer ID of the firmware running on the EZSP adapter + * @param xncpVersionNumber The XNCP 16-bit version number of the firmware running on the EZSP adapter + * + * @note Because our instance does not parse EZSP message, this method is invoked by external code, when an XNCP + * INFO EZSP message is received, so that we can our own version details + */ + void setFetchedXncpData(uint16_t xncpManufacturerId, uint16_t xncpVersionNumber); + + /** + * @brief Set the current EZSP stack version running on the EZSP adapter + * + * @param ezspStackVersion The EZSP stack version + */ + void setFetchedEzspVersionData(uint16_t ezspStackVersion); + + /** + * @brief Set the current EZSP version data running on the EZSP adapter + * + * @param ezspStackVersion The EZSP stack version + * @param ezspProtocolVersion The EZSP protocol version (EZSPv7, EZSPv8) + * @param ezspStackType The EZSP stack type + */ + void setFetchedEzspVersionData(uint16_t ezspStackVersion, uint8_t ezspProtocolVersion, uint8_t ezspStackType); + + /** + * @brief Get the current hardware & firmware, stack and protocol version running on the EZSP adapter + * + * @return The current version running on the EZSP adapter + */ + NSEZSP::EzspAdapterVersion getVersion() const; + /** * @brief Send Ezsp Command */ @@ -105,6 +141,7 @@ class CEzspDongle : public NSSPI::IAsyncDataInputObserver, public CAshCallback private: bool firstStartup; /*!< Is this the first attempt to exchange with the dongle? If so, we will probe to check if the adapter is in EZSP or bootloader prompt mode */ + NSEZSP::EzspAdapterVersion version; /*!< The version details of this EZSP adapter (firmware and hardware) */ CEzspDongle::Mode lastKnownMode; /*!< What is the current adapter mode (bootloader, EZSP/ASH mode etc.) */ bool switchToFirmwareUpgradeOnInitTimeout; /*!< Shall we directly move to firmware upgrade if we get an ASH timeout, if not, we will run the application (default behaviour) */ const NSSPI::TimerBuilder& timerBuilder; /*!< A timer builder used to generate timers */ diff --git a/src/ezsp/ezsp-protocol/get-network-parameters-response.cpp b/src/ezsp/ezsp-protocol/get-network-parameters-response.cpp index 191ad0b6..76963ff8 100644 --- a/src/ezsp/ezsp-protocol/get-network-parameters-response.cpp +++ b/src/ezsp/ezsp-protocol/get-network-parameters-response.cpp @@ -25,7 +25,7 @@ std::string CGetNetworkParametersResponse::String() const buf << "GetNetworkParametersResponse : { "; buf << "[status : "<< CEzspEnum::EEmberStatusToString(status) << "]"; buf << "[modeType : "<< CEzspEnum::EmberNodeTypeToString(node_type) << "]"; - buf << "["<< parameters.String() << "]"; + buf << "["<< parameters.toString() << "]"; buf << " }"; return buf.str(); diff --git a/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.cpp b/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.cpp index f2df15ef..32a3836d 100644 --- a/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.cpp +++ b/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.cpp @@ -64,8 +64,7 @@ NSSPI::ByteBuffer CEmberGpAddressStruct::getRaw() const return lo_raw; } -std::string CEmberGpAddressStruct::String() const -{ +std::string CEmberGpAddressStruct::toString() const { std::stringstream buf; buf << "CEmberGpAddressStruct: { "; diff --git a/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.h b/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.h index 783b294a..016855e4 100644 --- a/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.h +++ b/src/ezsp/ezsp-protocol/struct/ember-gp-address-struct.h @@ -65,7 +65,7 @@ class CEmberGpAddressStruct * * @return The resulting string */ - std::string String() const; + std::string toString() const; /** * @brief Serialize to an iostream @@ -76,7 +76,7 @@ class CEmberGpAddressStruct * @return The new output stream with serialized data appended */ friend std::ostream& operator<< (std::ostream& out, const CEmberGpAddressStruct& data){ - out << data.String(); + out << data.toString(); return out; } diff --git a/src/ezsp/ezsp-protocol/struct/ember-gp-sink-table-options-field.cpp b/src/ezsp/ezsp-protocol/struct/ember-gp-sink-table-options-field.cpp index f72d4728..36ab1abb 100644 --- a/src/ezsp/ezsp-protocol/struct/ember-gp-sink-table-options-field.cpp +++ b/src/ezsp/ezsp-protocol/struct/ember-gp-sink-table-options-field.cpp @@ -90,8 +90,7 @@ uint16_t CEmberGpSinkTableOption::get() const return o_options; } -std::string CEmberGpSinkTableOption::String() const -{ +std::string CEmberGpSinkTableOption::toString() const { std::stringstream buf; buf << "CEmberGpSinkTableOption : { "; diff --git a/src/ezsp/ezsp-protocol/struct/ember-network-parameters.cpp b/src/ezsp/ezsp-protocol/struct/ember-network-parameters.cpp index 8c7ce3c3..713d88ce 100644 --- a/src/ezsp/ezsp-protocol/struct/ember-network-parameters.cpp +++ b/src/ezsp/ezsp-protocol/struct/ember-network-parameters.cpp @@ -88,8 +88,7 @@ NSSPI::ByteBuffer CEmberNetworkParameters::getRaw() const return raw_message; } -std::string CEmberNetworkParameters::String() const -{ +std::string CEmberNetworkParameters::toString() const { std::stringstream buf; buf << "EmberNetworkParameters : { "; diff --git a/src/ezsp/ezsp-protocol/struct/ember-network-parameters.h b/src/ezsp/ezsp-protocol/struct/ember-network-parameters.h index d3436eaf..e963ffcf 100644 --- a/src/ezsp/ezsp-protocol/struct/ember-network-parameters.h +++ b/src/ezsp/ezsp-protocol/struct/ember-network-parameters.h @@ -108,7 +108,7 @@ class CEmberNetworkParameters * * @return The resulting string */ - std::string String() const; + std::string toString() const; /** * @brief Serialize to an iostream @@ -119,7 +119,7 @@ class CEmberNetworkParameters * @return The new output stream with serialized data appended */ friend std::ostream& operator<< (std::ostream& out, const CEmberNetworkParameters& data){ - out << data.String(); + out << data.toString(); return out; } diff --git a/src/ezsp/ezsp.cpp b/src/ezsp/ezsp.cpp index eeb68523..98243927 100644 --- a/src/ezsp/ezsp.cpp +++ b/src/ezsp/ezsp.cpp @@ -28,6 +28,10 @@ void CEzsp::start() main->start(); } +NSEZSP::EzspAdapterVersion CEzsp::getAdapterVersion() const { + return main->getAdapterVersion(); +} + void CEzsp::forceFirmwareUpgradeOnInitTimeout() { main->forceFirmwareUpgradeOnInitTimeout(); diff --git a/src/ezsp/lib-ezsp-main.cpp b/src/ezsp/lib-ezsp-main.cpp index 361f7efd..67aa67d9 100644 --- a/src/ezsp/lib-ezsp-main.cpp +++ b/src/ezsp/lib-ezsp-main.cpp @@ -4,14 +4,16 @@ * @brief Main API methods for libezsp */ +#include +#include + +#include + #include "ezsp/lib-ezsp-main.h" #include "spi/ILogger.h" #include "ezsp/ezsp-protocol/get-network-parameters-response.h" // For CGetNetworkParametersResponse #include "ezsp/ezsp-protocol/struct/ember-key-struct.h" // For CEmberKeyStruct -#include -#include - DEFINE_ENUM(State, CLIBEZSP_INTERNAL_STATE_LIST, NSEZSP::CLibEzspInternal); using NSEZSP::CLibEzspMain; @@ -62,6 +64,10 @@ void CLibEzspMain::start() } } +NSEZSP::EzspAdapterVersion CLibEzspMain::getAdapterVersion() const { + return this->dongle.getVersion(); +} + void CLibEzspMain::forceFirmwareUpgradeOnInitTimeout() { this->dongle.forceFirmwareUpgradeOnInitTimeout(); @@ -266,10 +272,24 @@ void CLibEzspMain::handleDongleState( EDongleState i_state ) // TODO: manage this ! clogW << __func__ << "() dongle removed\n"; } - else - { - clogD << __func__ << "() dongle state "<< i_state << std::endl; - } + else if (i_state == DONGLE_VERSION_RETRIEVED) { + NSEZSP::EzspAdapterVersion ezspAdapterVersion = this->dongle.getVersion(); + if (ezspAdapterVersion.xncpManufacturerId != static_cast(NSEZSP::EzspAdapterVersion::Manufacturer::UNKNOWN)) { + /* Note: here we only care about DONGLE_VERSION_RETRIEVED notifications if the manufacturer ID is known, meaning we have received both + * EZSP VERSION and XNCP INFO data + */ + if (ezspAdapterVersion.xncpManufacturerId != static_cast(NSEZSP::EzspAdapterVersion::Manufacturer::LEGRAND)) { + clogW << "EZSP adapter is not from Legrand (manufacturer " << std::hex << static_cast(NSEZSP::EzspAdapterVersion::Manufacturer::LEGRAND) << " expected)\n"; + } + else { + clogI << "Legrand EZSP adapter found with hardware version " << std::dec << ezspAdapterVersion.xncpAdapterHardwareVersion + << " and firmware v" << ezspAdapterVersion.getFirmwareVersionAsString() << ", running EZSPv" << ezspAdapterVersion.ezspProtocolVersion << " with stack v" << ezspAdapterVersion.getStackVersionAsString() << "\n"; + } + } + } + else { + clogD << __func__ << "() dongle state "<< i_state << std::endl; + } } bool CLibEzspMain::clearAllGPDevices() @@ -378,33 +398,28 @@ void CLibEzspMain::handleFirmwareXModemXfr() clogW << "EZSP adapter is now ready to receive a firmware image (.gbl) via X-modem\n"; } -void CLibEzspMain::handleEzspRxMessage_VERSION(const NSSPI::ByteBuffer& i_msg_receive) -{ - uint8_t ezspProtocolVersion; - uint8_t ezspStackType; - uint16_t ezspStackVersion; +void CLibEzspMain::handleEzspRxMessage_VERSION(const NSSPI::ByteBuffer& i_msg_receive) { std::stringstream bufDump; bool truncatedVersion = false; /* Flag set to true when receiving a truncated EZSP_VERSION payload */ bool acceptableVersion = false; /* Flag set to true when the version received from the EZSP adapter is acceptable for us */ - for (unsigned int loop=0; loop(i_msg_receive[loop]); } - clogD << "Got EZSP_VERSION payload:" << bufDump.str() << "\n"; + clogD << "Got EZSP_VERSION payload:" << NSSPI::Logger::byteSequenceToString(i_msg_receive) << "\n"; // Check if the wanted protocol version, and display stack version if (i_msg_receive.size() == 2) { clogW << "Got a truncated EZSP version frame from a buggy NCP, using only the 2 last bytes\n"; - ezspStackVersion = dble_u8_to_u16(i_msg_receive[1], i_msg_receive[0]); + uint16_t ezspStackVersion = dble_u8_to_u16(i_msg_receive[1], i_msg_receive[0]); + this->dongle.setFetchedEzspVersionData(ezspStackVersion); truncatedVersion = true; /* We assume the version is acceptable when receiving a truncated version, because truncated payloads only occur at the second attempt * and this means we have already re-run dongleInit() below with the new expected version directly coming from the response of the adapter */ acceptableVersion = true; - /* The two values below are not sent on a truncated version, we thus used the cached values from a previous run */ - ezspProtocolVersion = this->exp_ezsp_min_version; - ezspStackType = this->exp_stack_type; + /* The two values below are not sent on a truncated version, but we use the values cached inside this->dongle from a previous run */ } if (i_msg_receive.size() == 4) { - ezspProtocolVersion = i_msg_receive.at(0); - ezspStackType = i_msg_receive.at(1); - ezspStackVersion = dble_u8_to_u16(i_msg_receive[3], i_msg_receive[2]); + uint8_t ezspProtocolVersion = i_msg_receive.at(0); + uint8_t ezspStackType = i_msg_receive.at(1); + uint16_t ezspStackVersion = dble_u8_to_u16(i_msg_receive[3], i_msg_receive[2]); + this->dongle.setFetchedEzspVersionData(ezspStackVersion, ezspProtocolVersion, ezspStackType); if (ezspStackType != this->exp_stack_type) { clogE << "Wrong stack type: " << static_cast(ezspStackType) << ", expected: " << static_cast(this->exp_stack_type) << "\n"; clogE << "Stopping init here. Library will not work with this EZSP adapter\n"; @@ -423,24 +438,16 @@ void CLibEzspMain::handleEzspRxMessage_VERSION(const NSSPI::ByteBuffer& i_msg_re } if (acceptableVersion) { std::stringstream bufDump; /* Log message container */ - // EZSP protocol version - bufDump << "EZSP adapter is using EZSPv" << std::dec << static_cast(ezspProtocolVersion); - - // Stack type - bufDump << " with stack type " << static_cast(ezspStackType); - if (ezspStackType == 2) { - bufDump << " (mesh)"; + NSEZSP::EzspAdapterVersion ezspVersionDetails = this->dongle.getVersion(); + std::string humanReadableStackType(""); + if (ezspVersionDetails.ezspStackType == 2) { + humanReadableStackType = " (mesh)"; } - // Stack version (encoded in nibbles) - bufDump << ". Stack version: "; - bufDump << static_cast(u8_get_hi_nibble(u16_get_hi_u8(ezspStackVersion))) << "."; - bufDump << static_cast(u8_get_lo_nibble(u16_get_hi_u8(ezspStackVersion))) << "."; - bufDump << static_cast(u8_get_hi_nibble(u16_get_lo_u8(ezspStackVersion))) << "."; - bufDump << static_cast(u8_get_lo_nibble(u16_get_lo_u8(ezspStackVersion))) << "\n"; - /* Output the log message */ - clogI << bufDump.str(); + clogI << "EZSP adapter version is supported: EZSPv" << std::dec << static_cast(ezspVersionDetails.ezspProtocolVersion) + << " with stack type " << static_cast(ezspVersionDetails.ezspStackType) << humanReadableStackType + << ". Stack version: " << ezspVersionDetails.getStackVersionAsString() << "\n"; // Now request the XNCP version this->getXncpInfo(); @@ -450,44 +457,24 @@ void CLibEzspMain::handleEzspRxMessage_VERSION(const NSSPI::ByteBuffer& i_msg_re } } -void CLibEzspMain::handleEzspRxMessage_EZSP_GET_XNCP_INFO(const NSSPI::ByteBuffer& i_msg_receive) -{ - std::stringstream bufDump; - for (unsigned int loop=0; loop(i_msg_receive[loop]); } - //clogD << "Got EZSP_GET_XNCP_INFO payload:" << bufDump.str() << "\n"; +void CLibEzspMain::handleEzspRxMessage_EZSP_GET_XNCP_INFO(const NSSPI::ByteBuffer& i_msg_receive) { + //clogD << "Got EZSP_GET_XNCP_INFO payload:" << NSSPI::Logger::byteSequenceToString(i_msg_receive) << "\n"; - if (i_msg_receive.size() < 5) - { - clogE << "Wrong size for EZSP_GET_XNCP_INFO message: " << static_cast(i_msg_receive.size()) << " bytes\n"; - } - else - { - if (i_msg_receive[0] != EMBER_SUCCESS) - { - clogW << "EZSP_GET_XNCP_INFO failed\n"; - } - else - { - this->xncpManufacturerId = dble_u8_to_u16(i_msg_receive[2], i_msg_receive[1]); - this->xncpVersionNumber = dble_u8_to_u16(i_msg_receive[4], i_msg_receive[3]); - //clogD << "XNCP manufacturer: 0x" << std::hex << std::setw(4) << std::setfill('0') << static_cast(this->xncpManufacturerId) - // << ", version: 0x" << std::hex << std::setw(4) << std::setfill('0') << static_cast(this->xncpVersionNumber) << "\n"; - if (this->xncpManufacturerId != 0x1021) { - clogW << "EZSP adapter is not from Legrand (manufacturer 0x1021 expected)\n"; - } - else { - unsigned int xncpAdapterHardwareVersion = u16_get_hi_u8(this->xncpVersionNumber) >> 4; /* High nibble of MSB */ - unsigned int xncpAdapterMajorVersion = u16_get_hi_u8(this->xncpVersionNumber) & 0x0f; /* Low nibble of MSB */ - unsigned int xncpAdapterMinorVersion = u16_get_lo_u8(this->xncpVersionNumber) >> 4; /* High nibble of LSB */ - unsigned int xncpAdapterRevisionVersion = u16_get_lo_u8(this->xncpVersionNumber) & 0x0f; /* Low nibble of LSB */ - clogI << "Legrand EZSP adapter found with hardware version " << std::dec << xncpAdapterHardwareVersion - << " and firmware v" << xncpAdapterMajorVersion << "." << xncpAdapterMinorVersion << "." << xncpAdapterRevisionVersion << "\n"; - } - } - } - // Now, configure and startup the adapter's embedded stack - setState(CLibEzspInternal::State::STACK_INIT); - stackInit(); + if (i_msg_receive.size() < 5) { + clogE << "Wrong size for EZSP_GET_XNCP_INFO message: " << static_cast(i_msg_receive.size()) << " bytes\n"; + } + else { + if (i_msg_receive[0] != EMBER_SUCCESS) { + clogW << "EZSP_GET_XNCP_INFO failed\n"; + } + else { + this->dongle.setFetchedXncpData(dble_u8_to_u16(i_msg_receive[2], i_msg_receive[1]), + dble_u8_to_u16(i_msg_receive[4], i_msg_receive[3])); + } + } + // Now, configure and startup the adapter's embedded stack + setState(CLibEzspInternal::State::STACK_INIT); + stackInit(); } void CLibEzspMain::handleEzspRxMessage_NETWORK_STATE(const NSSPI::ByteBuffer& i_msg_receive) diff --git a/src/ezsp/lib-ezsp-main.h b/src/ezsp/lib-ezsp-main.h index 65a0cef7..e624db11 100644 --- a/src/ezsp/lib-ezsp-main.h +++ b/src/ezsp/lib-ezsp-main.h @@ -86,6 +86,13 @@ class CLibEzspMain : public CEzspDongleObserver, CGpObserver { */ void start(); + /** + * @brief Get the EZSP adapter's version + * + * @return The EZSP adapter version (hardware and firmware) if already known + */ + NSEZSP::EzspAdapterVersion getAdapterVersion() const; + /** * @brief Register callback on current library state *