|
- /*!
- * \file /utl/com/_1wire.h
- * \brief An 1-wire interface implementation
- *
- * Copyright (C) 2018 Christos Choutouridis
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #ifndef __utl_com_1wire_h__
- #define __utl_com_1wire_h__
-
- #include <utl/impl/impl.h>
- #include <utl/helper/crtp.h>
- #include <utl/meta/sfinae.h>
- #include <utl/com/_1wire_id.h>
-
- #include <gsl/span>
- using gsl::span;
-
- namespace utl {
-
-
-
- /*!
- * \ingroup Communication
- * \brief Abstract base class interface for 1-wire bus
- */
- //!@{
-
- /*!
- * \brief
- * Template base class for 1-wire communication interface using CRTP
- * \param impl_t The CRTP type (the derived/implementation class typename).
- */
- template <typename impl_t>
- class _1wire_i {
- _CRTP_IMPL(impl_t);
-
- public:
- using type = _1wire_i; //!< Export type as identity meta-function
-
- //! 1-wire bus speed
- enum class Speed { STD =0, OVDR };
-
- /*!
- * \name Object lifetime
- */
- //!@{
- protected:
- _1wire_i () = default; //!< Allow constructor from derived only
- ~_1wire_i () = default; //!< Allow destructor from derived only
- _1wire_i (const _1wire_i&) = delete; //!< No copies
- _1wire_i& operator= (const _1wire_i&) = delete;
- //!@}
-
- /*!
- * \name Implementation requirements
- * \note
- * In order for the implementation to have the following as private members too
- * it need to declare this class as friend
- */
- //!@{
- private:
- Speed speed () { return impl().speed(); } //!< Get the 1-wire bus speed
- void speed (Speed s) { return impl().speed(s); } //!< Set the 1-wire bus speed
- bool bit () { return impl().bit(); } //!< Read a bit from the 1-Wire bus, return it and provide the recovery time.
- bool bit (bool b) { return impl().bit(b); } //!< Write a bit to the 1-Wire bus, return write status and provide the recovery time.
- bool _reset () { return impl()._reset(); } //!< Generate a 1-wire reset and return the operation status
- //!@}
-
- /*!
- * \name Friends api to provide functionality to all class specializations
- */
- //!@{
- private:
- enum Command {
- CMD_READ_ROM = 0x33,
- CMD_OVDR_SKIP = 0x3C,
- CMD_MATCH = 0x55,
- CMD_OVDR_MATCH = 0x69,
- CMD_SKIP = 0xCC,
- CMD_ALARM_SEARCH = 0xEC,
- CMD_SEARCH_ROM = 0xF0
- };
- template <typename _T> friend bool _1wire_i_reset (_T&, typename _T::Speed);
- template <typename _T> friend byte_t _1wire_i_rw (_T&, byte_t, typename _T::Speed);
- template <typename _T> friend byte_t _1wire_i_rx (_T&, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_rx (_T&, span<byte_t>, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_tx (_T&, byte_t, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_tx (_T&, const span<byte_t>, typename _T::Speed);
- template <typename _T> friend void _1wire_i_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
- template <typename _T> friend void _1wire_i_match_n_ovdr (_T& obj, _1wire_id_t& id);
- template <typename _T> friend void _1wire_i_skip (_T& obj, typename _T::Speed s);
- template <typename _T> friend void _1wire_i_skip_n_ovdr (_T& obj);
- template <typename _T> friend _1wire_id_t _1wire_i_first (_T&, typename _T::Speed, bool);
- template <typename _T> friend _1wire_id_t _1wire_i_next (_T&, typename _T::Speed, bool);
- //!@}
-
- /*!
- * \name User functionality provided by the interface
- */
- //!@{
- public:
- /*!
- * \brief
- * Generate a 1-wire reset
- * \param s Bus speed
- * \return The status of the operation
- * \arg 0 Fail
- * \arg 1 Success
- */
- bool reset (Speed s) { return _1wire_i_reset (*this, s); };
- //! Read a byte from 1-Wire bus
- //! @param s The bus speed
- //! @return The received byte
- byte_t read (Speed s) { return _1wire_i_rx (*this, s); }
- //! Read a span of bytes from 1-wire bus
- //! \param data Ref to data span
- //! \param s The speed to use
- //! \return The number of received bytes
- size_t read (span<byte_t> data, Speed s) { return _1wire_i_rx (*this, data, s); }
- //! \brief Write a byte to 1-Wire bus
- //! \param b The byte to write
- //! \param s Bus speed to use
- //! \return The number of transmitted bytes
- size_t write (byte_t byte, Speed s) { return _1wire_i_tx (*this, byte, s); }
- //! \brief Write a span of bytes to 1-wire bus
- //! \param data Ref to data span
- //! \param s Bus speed to use
- //! \return The number of transmitted bytes
- size_t write (const span<byte_t> data, Speed s) { return _1wire_i_tx (*this, data, s); }
- /*!
- * \brief
- * Write a byte to 1-Wire bus and read the response
- * \param b The byte to write
- * \param s Bus speed to use
- * \return The byte received.
- */
- byte_t rw (byte_t b, Speed s) { return _1wire_i_rw (*this, b, s); }
-
- void match (_1wire_id_t& id, Speed s) { _1wire_i_match (*this, id, s); }
- void match_n_ovdr (_1wire_id_t& id) { _1wire_i_match_n_ovdr (*this, id); }
- void skip (Speed s) { _1wire_i_skip (*this, s); }
- void skip_n_ovdr () { _1wire_i_skip_n_ovdr (*this); }
-
- /*!
- * \brief
- * 'first' operation, to search on the 1-Wire for the first device.
- * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
- * \param s The bus speed
- * \param alarm If set, search for alarm devices
- * \return ID The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- _1wire_id_t first (Speed s, bool alarm =false) { return _1wire_i_first (*this, s, alarm); }
- /*!
- * \brief
- * 'next' operation, to search on the 1-Wire for the next device.
- * This search is usually performed after a 'first' operation or another 'next' operation.
- * Based on maxim-ic application note 187.
- * \param s The bus speed
- * \param alarm If set, search for alarm devices
- * \return ID The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- _1wire_id_t next (Speed s, bool alarm =false) { return _1wire_i_next (*this, s, alarm); }
- //!@}
-
-
- private:
- _1wire_id_t dec_ {_1wire_id_t::nullDev()}; /*!<
- * Hold the algorithm's select bit when a discrepancy
- * is detected. We use this variable to navigate to the
- * ROM tree as we store the path we take each time (0-1).
- * Each bit represent a bit position in the ROM ID.
- */
- _1wire_id_t pos_ {_1wire_id_t::nullDev()}; /*!<
- * Hold the discrepancy position. We use this variable to
- * navigate to the ROM tree as we store the crossroads(1) we encounter.
- * Each bit represent a bit position in the ROM ID.
- */
- _1wire_id_t cur_ {_1wire_id_t::nullDev()}; //! Current rom discrepancy state
- };
-
-
-
- /*!
- * \brief
- * A virtual base class implementation
- * \param impl_t = virtual_tag
- */
- template <>
- class _1wire_i <virtual_tag> {
- public:
- using type = _1wire_i<virtual_tag>; //!< Export type as identity meta-function
-
- //! 1-wire bus speed
- enum class Speed { STD =0, OVDR };
-
- /*!
- * \name Object lifetime
- */
- //!@{
- protected:
- _1wire_i () = default; //!< Allow constructor from derived only
- _1wire_i (const type&) = delete; //!< No copies
- type& operator= (const type&) = delete;
- public:
- virtual ~_1wire_i () = default; //!< Virtual default destructor
- //!@}
-
- /*!
- * \name Implementation requirements
- */
- //!@{
- private:
- virtual Speed speed () =0; //!< Get the 1-wire bus speed
- virtual void speed (Speed) =0; //!< Set the 1-wire bus speed
- virtual bool bit () =0; //!< Read a bit from the 1-Wire bus, return it and provide the recovery time.
- virtual bool bit (bool) =0; //!< Write a bit to the 1-Wire bus, return write status and provide the recovery time.
- virtual bool _reset () =0; //!< Generate a 1-wire reset and return the operation status
- //!@}
-
- /*!
- * \name Friends api to provide functionality to all class specializations
- */
- //!@{
- private:
- enum Command {
- CMD_READ_ROM = 0x33,
- CMD_OVDR_SKIP = 0x3C,
- CMD_MATCH = 0x55,
- CMD_OVDR_MATCH = 0x69,
- CMD_SKIP = 0xCC,
- CMD_ALARM_SEARCH = 0xEC,
- CMD_SEARCH_ROM = 0xF0
- };
- template <typename _T> friend bool _1wire_i_reset (_T&, typename _T::Speed);
- template <typename _T> friend byte_t _1wire_i_rw (_T&, byte_t, typename _T::Speed);
- template <typename _T> friend byte_t _1wire_i_rx (_T&, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_rx (_T&, span<byte_t>, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_tx (_T&, byte_t, typename _T::Speed);
- template <typename _T> friend size_t _1wire_i_tx (_T&, const span<byte_t>, typename _T::Speed);
- template <typename _T> friend void _1wire_i_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
- template <typename _T> friend void _1wire_i_match_n_ovdr (_T& obj, _1wire_id_t& id);
- template <typename _T> friend void _1wire_i_skip (_T& obj, typename _T::Speed s);
- template <typename _T> friend void _1wire_i_skip_n_ovdr (_T& obj);
- template <typename _T> friend _1wire_id_t _1wire_i_first (_T&, typename _T::Speed, bool);
- template <typename _T> friend _1wire_id_t _1wire_i_next (_T&, typename _T::Speed, bool);
- //!@}
-
- /*!
- * \name User functionality provided by the interface
- */
- //!@{
- public:
- /*!
- * \brief
- * Generate a 1-wire reset
- * \param s Bus speed
- * \return The status of the operation
- * \arg 0 Fail
- * \arg 1 Success
- */
- bool reset (Speed s) { return _1wire_i_reset (*this, s); };
- //! Read a byte from 1-Wire bus
- //! @param s The bus speed
- //! @return The received byte
- byte_t read (Speed s) { return _1wire_i_rx (*this, s); }
- //! Read a span of bytes from 1-wire bus
- //! \param data Ref to data span
- //! \param s The speed to use
- //! \return The number of received bytes
- size_t read (span<byte_t> data, Speed s) { return _1wire_i_rx (*this, data, s); }
- //! \brief Write a byte to 1-Wire bus
- //! \param b The byte to write
- //! \param s Bus speed to use
- //! \return The number of transmitted bytes
- size_t write (byte_t byte, Speed s) { return _1wire_i_tx (*this, byte, s); }
- //! \brief Write a span of bytes to 1-wire bus
- //! \param data Ref to data span
- //! \param s Bus speed to use
- //! \return The number of transmitted bytes
- size_t write (const span<byte_t> data, Speed s) { return _1wire_i_tx (*this, data, s); }
- /*!
- * \brief
- * Write a byte to 1-Wire bus and read the response
- * \param b The byte to write
- * \param s Bus speed to use
- * \return The byte received.
- */
- byte_t rw (byte_t b, Speed s) { return _1wire_i_rw (*this, b, s); }
-
- void match (_1wire_id_t& id, Speed s) { _1wire_i_match (*this, id, s); }
- void match_n_ovdr (_1wire_id_t& id) { _1wire_i_match_n_ovdr (*this, id); }
- void skip (Speed s) { _1wire_i_skip (*this, s); }
- void skip_n_ovdr () { _1wire_i_skip_n_ovdr (*this); }
-
- /*!
- * \brief
- * 'first' operation, to search on the 1-Wire for the first device.
- * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
- * \param s The bus speed
- * \param alarm If set, search for alarm devices
- * \return ID The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- _1wire_id_t first (Speed s, bool alarm =false) { return _1wire_i_first (*this, s, alarm); }
- /*!
- * \brief
- * 'next' operation, to search on the 1-Wire for the next device.
- * This search is usually performed after a 'first' operation or another 'next' operation.
- * Based on maxim-ic application note 187.
- * \param s The bus speed
- * \param alarm If set, search for alarm devices
- * \return ID The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- _1wire_id_t next (Speed s, bool alarm =false) { return _1wire_i_next (*this, s, alarm); }
- //!@}
-
-
- private:
- _1wire_id_t dec_ {_1wire_id_t::nullDev()}; /*!<
- * Hold the algorithm's select bit when a discrepancy
- * is detected. We use this variable to navigate to the
- * ROM tree as we store the path we take each time (0-1).
- * Each bit represent a bit position in the ROM ID.
- */
- _1wire_id_t pos_ {_1wire_id_t::nullDev()}; /*!<
- * Hold the discrepancy position. We use this variable to
- * navigate to the ROM tree as we store the crossroads(1) we encounter.
- * Each bit represent a bit position in the ROM ID.
- */
- _1wire_id_t cur_ {_1wire_id_t::nullDev()}; //! Current rom discrepancy state
- };
-
-
- /*!
- * \name Friend API to provide common functionality to all specializations
- */
- //!@{
-
- /*!
- * \brief
- * Generate a 1-wire reset
- * \param obj The object from which we call private members
- * \param s Bus speed
- * \return The status of the operation
- * \arg 0 Fail
- * \arg 1 Success
- */
- template <typename _T>
- bool _1wire_i_reset (_T& obj, typename _T::Speed s) {
- if (obj.speed () != s)
- obj.speed (s);
- return obj._reset ();
- }
-
- /*!
- * \brief
- * Write a byte to 1-Wire bus and read the response
- * \param obj The object from which we call private members
- * \param b The byte to write
- * \param s Bus speed to use
- * \return The byte received.
- */
- template <typename _T>
- byte_t _1wire_i_rw (_T& obj, byte_t b, typename _T::Speed s) {
- byte_t ret {0};
-
- // Select speed once
- if (obj.speed () != s)
- obj.speed (s);
- for (uint8_t i =8; i>0 ; --i) {
- ret >>= 1;
- if ((b & 0x01) != 0) ret |= (obj.bit ()) ? 0x80 : 0x00;
- else obj.bit (0);
- b >>= 1;
- /*^
- * If the bit is 1 we use the read sequence, as it has the same
- * waveform with write-1 and we get the slave response
- * If the bit is 0, we can not read the slave response so we just write-0
- */
- }
- return ret;
- }
- /*!
- * \brief Read a byte from 1-Wire bus
- * \param obj The object from which we call private members
- * \param s Bus speed to use
- * \return The byte received.
- */
- template <typename _T>
- byte_t _1wire_i_rx (_T& obj, typename _T::Speed s) {
- byte_t byte {0};
- // Select speed once
- if (obj.speed () != s)
- obj.speed (s);
- for (uint8_t i =8; i>0 ; --i) {
- // shift bits to right as LSB comes first and mask it to MSB
- byte >>= 1;
- byte |= (obj.bit ()) ? 0x80 : 0x00;
- }
- return byte;
- }
-
- /*!
- * \brief Read a span of bytes from 1-Wire bus
- * \param obj The object from which we call private members
- * \param data Reference to byte span
- * \param s Bus speed to use
- * \return The number of received bytes. Actual return data.size()
- */
- template <typename _T>
- size_t _1wire_i_rx (_T& obj, span<byte_t> data, typename _T::Speed s) {
- // Select speed once
- if (obj.speed () != s)
- obj.speed (s);
- for (byte_t& byte : data) {
- byte = 0;
- for (uint8_t i =8; i>0 ; --i) {
- // shift bits to right as LSB comes first and mask it to MSB
- byte >>= 1;
- byte |= (obj.bit ()) ? 0x80 : 0x00;
- }
- }
- return data.size();
- }
- /*!
- * \brief Write a byte to 1-Wire bus
- * \param obj The object from which we call private members
- * \param byte The byte to write
- * \param s Bus speed to use
- * \return The number of transmitted bytes. So "1" of "0"
- */
- template <typename _T>
- size_t _1wire_i_tx (_T& obj, byte_t byte, typename _T::Speed s) {
- return (_1wire_i_rw (obj, byte, s) == byte) ? 1 : 0;
- }
- /*!
- * \brief Write a byte to 1-Wire bus
- * \param obj The object from which we call private members
- * \param data Reference to byte span
- * \param s Bus speed to use
- * \return The number of transmitted bytes.
- * \note
- * The procedure breaks on first transmission error
- */
- template <typename _T>
- size_t _1wire_i_tx (_T& obj, const span<byte_t> data, typename _T::Speed s) {
- size_t ret {0};
- for (byte_t byte : data) {
- if (_1wire_i_rw (obj, byte, s) == byte)
- ++ret;
- else
- break;
- }
- return ret;
- }
-
- /*!
- * Send match rom command
- * \param obj The object from which we call private members
- * \param id The ID to select on the bus
- * \param s The speed to use for the command
- */
- template <typename _T>
- void _1wire_i_match (_T& obj, _1wire_id_t& id, typename _T::Speed s) {
- _1wire_i_tx (obj, (s == _T::Speed::STD) ? _T::CMD_MATCH : _T::CMD_OVDR_MATCH, s);
- for (uint8_t& b : id)
- _1wire_i_tx (obj, b, s);
- }
-
- /*!
- * Match and overdrive sequence
- * \param obj The object from which we call private members
- * \param id The ID to select on the bus
- */
- template <typename _T>
- void _1wire_i_match_n_ovdr (_T& obj, _1wire_id_t& id) {
- _1wire_i_tx (obj, _T::CMD_MATCH, _T::Speed::STD);
- for (uint8_t& b : id)
- _1wire_i_tx (obj, b, _T::Speed::OVDR);
- }
-
- /*!
- * Send skip command to the bus
- * \param obj The object from which we call private members
- * \param id The ID to select on the bus
- */
- template <typename _T>
- void _1wire_i_skip (_T& obj, typename _T::Speed s) {
- _1wire_i_tx (obj, (s == _T::Speed::STD) ? _T::CMD_SKIP : _T::CMD_SKIP, s);
- }
-
- /*!
- * Send the Skip and Overdrive sequence
- * \param obj The object from which we call private members
- */
- template <typename _T>
- void _1wire_i_skip_n_ovdr (_T& obj) {
- _1wire_i_tx (obj, _T::CMD_OVDR_SKIP, _T::Speed::STD);
- }
-
- /*!
- * \brief
- * 'first' operation, to search on the 1-Wire for the first device.
- * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
- * \param obj The object from which we call private members
- * \param s The bus speed
- * \return ID The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- template <typename _T>
- _1wire_id_t _1wire_i_first (_T& obj, typename _T::Speed s, bool alarm) {
- obj.dec_ = obj.pos_ = obj.cur_ = _1wire_id_t::nullDev();
- return _1wire_i_next (obj, s, alarm);
- }
-
- /*!
- * \brief
- * 'next' operation, to search on the 1-Wire for the next device.
- * This search is usually performed after a 'first' operation or another 'next' operation.
- * Based on maxim-ic application note 187.
- * \param obj The object from which we call private members
- * \param s The bus speed
- * \return The romID
- * \arg nullDev Indicate no [more] device[s]
- */
- template <typename _T>
- _1wire_id_t _1wire_i_next (_T& obj, typename _T::Speed s, bool alarm) {
- uint8_t b, bxx; // bit helper vars
- uint8_t i;
- _1wire_id_t ID;
-
- do {
- if ((obj.pos_ != _1wire_id_t::nullDev()) && (obj.dec_ >= obj.pos_)) {
- // dec_ == pos_: We have found all the leafs, already
- // dec_ > pos_ : Error
- ID = _1wire_id_t::nullDev();
- break;
- }
- if (!obj.reset (s)) {
- ID = _1wire_id_t::nullDev();
- break;
- }
- // Issue search command
- if (alarm) obj.write (_T::CMD_ALARM_SEARCH, s);
- else obj.write (_T::CMD_SEARCH_ROM, s);
-
- // traverse entire RomID from LSB to MSB
- for (i =0 ; i<64 ; ++i) {
- // Get response pair bits
- bxx = obj.bit (); // bit
- bxx <<= 1;
- bxx |= obj.bit (); // complementary bit
-
- if (bxx == 0x00) {
- // 00 - We have discrepancy
- obj.cur_.bit (i, 1);
- switch (_1wire_id_t::compare (obj.pos_, obj.cur_)) {
- default:
- case -1:
- // pos_ < cur_: This discrepancy is the most far for now. Mark position and select 0.
- b = 0;
- //dec_.bit (i, (b = 0)); //<-- Its already 0
- obj.pos_.bit (i, 1);
- break;
- case 0:
- // pos_ == cur_: This was the last discrepancy in the last pass.
- // Select the other branch this time (1)
- obj.dec_.bit (i, (b = 1));
- break;
- case 1:
- // pos_ > cur_: We had a discrepancy in a MSB than that, in a previous pass.
- // Continue with the last pass decision.
- b = obj.dec_.bit (i);
- break;
- }
- // Send selection and update romid
- obj.bit (b);
- ID.bit (i, b);
- }
- else if (bxx == 0x01) {
- // 01 - All bits of all ROMs are 0s
- obj.bit (0);
- ID.bit (i, 0);
-
- }
- else if (bxx == 0x02) {
- // 10 - All bits of all ROMs are 1s
- obj.bit (1);
- ID.bit (i, 1);
- }
- else {
- // 11 - No device on the bus
- ID = _1wire_id_t::nullDev();
- break;
- }
- } // for
-
- if (i == 64 && obj.pos_ == _1wire_id_t::nullDev()) {
- // Mark done with only one device
- obj.pos_.bit (0, 1);
- obj.dec_.bit (0, 1);
- }
- } while (0);
-
- return ID;
- }
- //!@}
-
-
- #if defined _utl_have_concepts
- /*!
- * \name 1-wire type interface concept
- */
- template <typename T>
- concept bool _1wire_c = requires (T t, typename T::Speed s, _1wire_id_t id) {
- // Object type
- requires not_<std::is_copy_constructible<T>::value>::value;
- requires not_<std::is_copy_assignable<T>::value>::value;
- // Members
- // typename T::Speed;
- // typename T::Command;
- // Methods
- {t.reset(s)} -> bool;
- {t.read(s)} -> byte_t;
- {t.write(0, s)} -> size_t;
- {t.rw(0, s)} -> byte_t;
- t.match(id, s);
- t.match_n_ovdr(id);
- t.skip(s);
- t.skip_n_ovdr();
- {t.first(s)} -> _1wire_id_t;
- {t.next(s)} -> _1wire_id_t;
- };
- #else
- namespace _1wire_i_cnpt {
- using std::declval;
-
- template <class _Tp> using try_reset_t = decltype (declval<_Tp>().reset (declval<typename _Tp::Speed>()));
- template <class _Tp> using try_rw_t = decltype (declval<_Tp>().rw (declval<byte_t>(), declval<typename _Tp::Speed>()));
- template <class _Tp> using try_rx1_t = decltype (declval<_Tp>().read (declval<typename _Tp::Speed>()));
- template <class _Tp> using try_rx2_t = decltype (declval<_Tp>().read (declval<span<byte_t>>(), declval<typename _Tp::Speed>()));
- template <class _Tp> using try_tx1_t = decltype (declval<_Tp>().write (declval<byte_t>(), declval<typename _Tp::Speed>()));
- template <class _Tp> using try_tx2_t = decltype (declval<_Tp>().write (declval<const span<byte_t>>(), declval<typename _Tp::Speed>()));
-
-
- template <class _Tp> using try_match_t = decltype (declval<_Tp>().match (declval<_1wire_id_t&>(), declval<typename _Tp::Speed>()));
- template <class _Tp> using try_match_n_ovdr_t = decltype (declval<_Tp>().match_n_ovdr (declval<_1wire_id_t&>()));
- template <class _Tp> using try_skip_t = decltype (declval<_Tp>().skip (declval<typename _Tp::Speed>()));
- template <class _Tp> using try_skip_n_ovdr_t = decltype (declval<_Tp>().skip_n_ovdr ());
- template <class _Tp> using try_first_t = decltype (declval<_Tp>().first (declval<typename _Tp::Speed>()));
- template <class _Tp> using try_next_t = decltype (declval<_Tp>().next (declval<typename _Tp::Speed>()));
-
- //! Primary template to catch any non 1-wire interface types
- template <typename _Tp, typename =void>
- struct is_1wire_ : false_ {};
-
- //! template to catch a proper 1-wire interface type
- template <typename _Tp>
- struct is_1wire_ <_Tp,
- void_t <
- // typename _Tp::Speed,
- // typename _Tp::Command,
- use_if_same_t <try_reset_t <_Tp>, bool>,
- use_if_same_t <try_rw_t <_Tp>, byte_t>,
- use_if_same_t <try_rx1_t <_Tp>, byte_t>,
- use_if_same_t <try_rx2_t <_Tp>, size_t>,
- use_if_same_t <try_tx1_t <_Tp>, size_t>,
- use_if_same_t <try_tx2_t <_Tp>, size_t>,
- use_if_same_t <try_match_t<_Tp>, void>,
- use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
- use_if_same_t <try_skip_t<_Tp>, void>,
- use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
- use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
- use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
- > //!^ SFINAE may apply
- > : true_ {};
- }
-
- /*!
- * Value meta-programming function for 1-wire interface checking
- * \param _Tp Type to check
- * \return True if _Tp is a 1-wire interface
- */
- template <typename _Tp>
- constexpr bool _1wire_c = _1wire_i_cnpt::is_1wire_<_Tp>::value;
- #endif
-
- //!@}
- } //namespace utl
-
- #endif /* __utl_com_1wire_h__ */
|