/*!
 * \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/core/impl.h>
#include <utl/core/crtp.h>
#include <utl/com/_1wire_id.h>
#include <utl/meta/meta.h>


namespace utl {

/*!
 * \ingroup Communication
 * \brief   Abstract base class interface for 1-wire bus
 */
//!@{

   /*!
    * \name Friend API to provide common functionality to all specializations
    */
   namespace _1wire_i_det {
      template <typename _T> byte_t _touch (_T& obj, byte_t out, typename _T::Speed s);
      template <typename _T> void _match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
      template <typename _T> void _match_n_ovdr (_T& obj, _1wire_id_t& id);
      template <typename _T> void _skip (_T& obj, typename _T::Speed s);
      template <typename _T> void _skip_n_ovdr (_T& obj);
      template <typename _T> _1wire_id_t _first (_T& obj, typename _T::Speed s, bool alarm);
      template <typename _T> _1wire_id_t _next (_T& obj, typename _T::Speed s, bool alarm);
   }

   /*!
    * \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 () const { return impl().speed(); }    //!< Get the 1-wire bus speed
      void speed (Speed s) { return impl().speed(s); }   //!< Set the 1-wire bus speed
      //! Write a bit to the 1-Wire bus, return response/write status and provide the recovery time.
      bool bit (bool b)    { return impl().bit(b); }
      bool _reset (Speed s){ return impl()._reset(s); }  //!< 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 byte_t _1wire_i_det::_touch (_T&, byte_t, typename _T::Speed);
      template <typename _T> friend void _1wire_i_det::_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
      template <typename _T> friend void _1wire_i_det::_match_n_ovdr (_T& obj, _1wire_id_t& id);
      template <typename _T> friend void _1wire_i_det::_skip (_T& obj, typename _T::Speed s);
      template <typename _T> friend void _1wire_i_det::_skip_n_ovdr (_T& obj);
      template <typename _T> friend _1wire_id_t _1wire_i_det::_first (_T&, typename _T::Speed, bool);
      template <typename _T> friend _1wire_id_t _1wire_i_det::_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 = Speed::STD) {
         return _reset (s);
      }

      /*!
       * Transmit a byte to 1-Wire bus and read the response
       * \param   out   The byte to write
       * \param   s     Bus speed to use
       * \return  The byte received.
       */
      byte_t tx_data (byte_t out, Speed s = Speed::STD) {
         return _1wire_i_det::_touch (*this, out, s);
      }

      /*!
       * Transmit a number of bytes to 1-wire bus and read the response
       * \param out  Pointer to data to transmit
       * \param in   Pointer to data to store
       * \param n    Number of bytes
       * \param s    Speed to use
       * \return     The number of transmitted bytes
       */
      size_t tx_data (const byte_t *out, byte_t *in, size_t n, Speed s = Speed::STD);
      /*!
       * Receive a byte from 1-Wire bus while transmitting 0xFF
       * \param   s     Bus speed to use
       * \return  The byte received.
       */
      byte_t rx_data (Speed s = Speed::STD) {
         return _1wire_i_det::_touch (*this, 0xFF, s);
      }
      /*!
       * Receive a number of bytes from 1-wire bus while transmitting 0xFFs
       * \param in   Pointer to data to store
       * \param n    Number of bytes
       * \param s    Speed to use
       * \return     The number of transmitted bytes
       */
      size_t rx_data (byte_t *in, size_t n, Speed s = Speed::STD);

      /*!
       * Send match rom command
       * \param   id    The ID to select on the bus
       * \param   s     The speed to use for the command
       */
      void match (_1wire_id_t& id, Speed s = Speed::STD) {
         _1wire_i_det::_match (*this, id, s);
      }
      /*!
       * Match and overdrive sequence
       * \param   obj   The object from which we call private members
       * \param   id    The ID to select on the bus
       */
      void match_n_ovdr (_1wire_id_t& id) {
         _1wire_i_det::_match_n_ovdr (*this, id);
      }
      /*!
       * Send skip command to the bus
       * \param   id    The ID to select on the bus
       */
      void skip (Speed s = Speed::STD) {
         _1wire_i_det::_skip (*this, s);
      }
      /*!
       * Send the Skip and Overdrive sequence
       */
      void skip_n_ovdr () {
         _1wire_i_det::_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 = Speed::STD, bool alarm =false) {
         return _1wire_i_det::_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 = Speed::STD, bool alarm =false) {
         return _1wire_i_det::_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
   };

   template <typename _I>
   size_t _1wire_i<_I>::tx_data (const byte_t *out, byte_t *in, size_t n, Speed s){
      for (size_t nn {n} ; nn ; --nn)
         *in++ = tx_data (*out++, s);
      return n;
   }

   template <typename _I>
   size_t _1wire_i<_I>::rx_data(byte_t *in, size_t n, Speed s) {
      for (size_t nn {n} ; nn ; --nn)
         *in++ = tx_data (0xFF, s);
      return n;
   }

   /*!
    * \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 () const =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 (Speed) =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 byte_t _1wire_i_det::_touch (_T&, byte_t, typename _T::Speed);
      template <typename _T> friend void _1wire_i_det::_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
      template <typename _T> friend void _1wire_i_det::_match_n_ovdr (_T& obj, _1wire_id_t& id);
      template <typename _T> friend void _1wire_i_det::_skip (_T& obj, typename _T::Speed s);
      template <typename _T> friend void _1wire_i_det::_skip_n_ovdr (_T& obj);
      template <typename _T> friend _1wire_id_t _1wire_i_det::_first (_T&, typename _T::Speed, bool);
      template <typename _T> friend _1wire_id_t _1wire_i_det::_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 = Speed::STD) {
         return _reset (s);
      }

      /*!
       * Transmit a byte to 1-Wire bus and read the response
       * \param   out   The byte to write
       * \param   s     Bus speed to use
       * \return  The byte received.
       */
      byte_t tx_data (byte_t out, Speed s = Speed::STD) {
         return _1wire_i_det::_touch (*this, out, s);
      }

      /*!
       * Transmit a number of bytes to 1-wire bus and read the response
       * \param out  Pointer to data to transmit
       * \param in   Pointer to data to store
       * \param n    Number of bytes
       * \param s    Speed to use
       * \return     The number of transmitted bytes
       */
      size_t tx_data (const byte_t *out, byte_t *in, size_t n, Speed s = Speed::STD);
      /*!
       * Receive a byte from 1-Wire bus while transmitting 0xFF
       * \param   s     Bus speed to use
       * \return  The byte received.
       */
      byte_t rx_data (Speed s = Speed::STD) {
         return _1wire_i_det::_touch (*this, 0xFF, s);
      }
      /*!
       * Receive a number of bytes from 1-wire bus while transmitting 0xFFs
       * \param in   Pointer to data to store
       * \param n    Number of bytes
       * \param s    Speed to use
       * \return     The number of transmitted bytes
       */
      size_t rx_data (byte_t *in, size_t n, Speed s = Speed::STD);

      /*!
       * Send match rom command
       * \param   id    The ID to select on the bus
       * \param   s     The speed to use for the command
       */
      void match (_1wire_id_t& id, Speed s = Speed::STD) {
         _1wire_i_det::_match (*this, id, s);
      }
      /*!
       * Match and overdrive sequence
       * \param   obj   The object from which we call private members
       * \param   id    The ID to select on the bus
       */
      void match_n_ovdr (_1wire_id_t& id) {
         _1wire_i_det::_match_n_ovdr (*this, id);
      }
      /*!
       * Send skip command to the bus
       * \param   id    The ID to select on the bus
       */
      void skip (Speed s = Speed::STD) {
         _1wire_i_det::_skip (*this, s);
      }
      /*!
       * Send the Skip and Overdrive sequence
       */
      void skip_n_ovdr () {
         _1wire_i_det::_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 = Speed::STD, bool alarm =false) {
         return _1wire_i_det::_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 = Speed::STD, bool alarm =false) {
         return _1wire_i_det::_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
   };


   size_t _1wire_i<virtual_tag>::tx_data (const byte_t *out, byte_t *in, size_t n, Speed s){
      for (size_t nn {n} ; nn ; --nn)
         *in++ = tx_data (*out++, s);
      return n;
   }

   size_t _1wire_i<virtual_tag>::rx_data(byte_t *in, size_t n, Speed s) {
      for (size_t nn {n} ; nn ; --nn)
         *in++ = tx_data (0xFF, s);
      return n;
   }

/*!
 * \name Friend API to provide common functionality to all specializations
 */
//!@{
namespace _1wire_i_det {

   /*!
    * \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 _touch (_T& obj, byte_t out, 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;
         ret |= (obj.bit (out & 0x01)) ? 0x80 : 0x00;
         out >>= 1;
         /*^
          * We shift bits to right as LSB comes first and mask it to MSB
          * If we need to read we have to write 1
          */
      }
      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 _match (_T& obj, _1wire_id_t& id, typename _T::Speed s) {
      _touch (obj, (s == _T::Speed::STD) ? _T::CMD_MATCH : _T::CMD_OVDR_MATCH, s);
      for (uint8_t& b : id)
         _touch (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 _match_n_ovdr (_T& obj, _1wire_id_t& id) {
      _touch (obj, _T::CMD_MATCH, _T::Speed::STD);
      for (uint8_t& b : id)
         _touch (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 _skip (_T& obj, typename _T::Speed s) {
      _touch (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 _skip_n_ovdr (_T& obj) {
      _touch (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 _first (_T& obj, typename _T::Speed s, bool alarm) {
      obj.dec_ = obj.pos_ = obj.cur_ = _1wire_id_t::nullDev();
      return _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 _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.tx_data (_T::CMD_ALARM_SEARCH, s);
         else        obj.tx_data (_T::CMD_SEARCH_ROM, s);

         // Select speed once
         if (obj.speed () != s)
            obj.speed (s);

         // traverse entire RomID from LSB to MSB
         for (i =0 ; i<64 ; ++i) {
            // Get response pair bits
            bxx = obj.bit (1);   // bit
            bxx <<= 1;
            bxx |= obj.bit (1);  // 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;
   }
} // namespace _1wire_i_det
//!@}


#if defined _utl_have_concepts
   /*!
    * \name 1-wire type interface concept
    */
   template <typename T>
   concept bool _1Wire_i = 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.tx_data(1)} -> byte_t;
      {t.rx_data(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_det {
      using std::declval;

      template <class _Tp> using try_reset_t    = decltype (declval<_Tp>().reset (declval<typename _Tp::Speed>()));
      template <class _Tp> using try_rx1_t      = decltype (declval<_Tp>().rx_data (declval<typename _Tp::Speed>()));
      template <class _Tp> using try_tx1_t      = decltype (declval<_Tp>().tx_data (declval<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_ : meta::false_ {};

      //! template to catch a proper 1-wire interface type
      template <typename _Tp>
      struct is_1wire_ <_Tp,
         meta::void_t <
//            typename _Tp::Speed,
//            typename _Tp::Command,
//            meta::use_if_same_t <try_reset_t <_Tp>,    bool>,
//            meta::use_if_same_t <try_rx1_t <_Tp>,      byte_t>,
//            //meta::use_if_same_t <try_rx2_t <_Tp>,      size_t>,
//            meta::use_if_same_t <try_tx1_t <_Tp>,      byte_t>,
//            //meta::use_if_same_t <try_tx2_t <_Tp>,      size_t>,
//            meta::use_if_same_t <try_match_t<_Tp>,        void>,
//            meta::use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
//            meta::use_if_same_t <try_skip_t<_Tp>,         void>,
//            meta::use_if_same_t <try_skip_n_ovdr_t<_Tp>,  void>,
//            meta::use_if_same_t <try_first_t <_Tp>,    _1wire_id_t>,
//            meta::use_if_same_t <try_next_t <_Tp>,     _1wire_id_t>
            void
         >  //!^ SFINAE may apply
      > : meta::true_ {};
   } // namespace _1wire_i_det

   /*!
    * 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_i = _1wire_i_det::is_1wire_<_Tp>::value;
#endif

//!@}
}  //namespace utl

#endif /* __utl_com_1wire_h__ */
