diff --git a/include/utl/com/_1wire.h b/include/utl/com/_1wire.h
new file mode 100644
index 0000000..0fa34c9
--- /dev/null
+++ b/include/utl/com/_1wire.h
@@ -0,0 +1,708 @@
+/*!
+ * \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 .
+ *
+ */
+#ifndef __utl_com_1wire_h__
+#define __utl_com_1wire_h__
+
+#include
+#include
+#include
+#include
+
+#include
+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
+ 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 friend bool _1wire_i_reset (_T&, typename _T::Speed);
+ template friend byte_t _1wire_i_rw (_T&, byte_t, typename _T::Speed);
+ template friend byte_t _1wire_i_rx (_T&, typename _T::Speed);
+ template friend size_t _1wire_i_rx (_T&, span, typename _T::Speed);
+ template friend size_t _1wire_i_tx (_T&, byte_t, typename _T::Speed);
+ template friend size_t _1wire_i_tx (_T&, const span, typename _T::Speed);
+ template friend void _1wire_i_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
+ template friend void _1wire_i_match_n_ovdr (_T& obj, _1wire_id_t& id);
+ template friend void _1wire_i_skip (_T& obj, typename _T::Speed s);
+ template friend void _1wire_i_skip_n_ovdr (_T& obj);
+ template friend _1wire_id_t _1wire_i_first (_T&, typename _T::Speed, bool);
+ template 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 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 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 {
+ 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 (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 friend bool _1wire_i_reset (_T&, typename _T::Speed);
+ template friend byte_t _1wire_i_rw (_T&, byte_t, typename _T::Speed);
+ template friend byte_t _1wire_i_rx (_T&, typename _T::Speed);
+ template friend size_t _1wire_i_rx (_T&, span, typename _T::Speed);
+ template friend size_t _1wire_i_tx (_T&, byte_t, typename _T::Speed);
+ template friend size_t _1wire_i_tx (_T&, const span, typename _T::Speed);
+ template friend void _1wire_i_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
+ template friend void _1wire_i_match_n_ovdr (_T& obj, _1wire_id_t& id);
+ template friend void _1wire_i_skip (_T& obj, typename _T::Speed s);
+ template friend void _1wire_i_skip_n_ovdr (_T& obj);
+ template friend _1wire_id_t _1wire_i_first (_T&, typename _T::Speed, bool);
+ template 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 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 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
+ 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
+ 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
+ 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
+ size_t _1wire_i_rx (_T& obj, span 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
+ 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
+ size_t _1wire_i_tx (_T& obj, const span 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
+ 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
+ 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
+ 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
+ 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
+ _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
+ _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
+ concept bool _1wire_c = requires (T t, typename T::Speed s, _1wire_id_t id) {
+ // Object type
+ requires not_::value>::value;
+ requires not_::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 using try_reset_t = decltype (declval<_Tp>().reset (declval()));
+ template using try_rw_t = decltype (declval<_Tp>().rw (declval(), declval()));
+ template using try_rx1_t = decltype (declval<_Tp>().read (declval()));
+ template using try_rx2_t = decltype (declval<_Tp>().read (declval>(), declval()));
+ template using try_tx1_t = decltype (declval<_Tp>().write (declval(), declval()));
+ template using try_tx2_t = decltype (declval<_Tp>().write (declval>(), declval()));
+
+
+ template using try_match_t = decltype (declval<_Tp>().match (declval<_1wire_id_t&>(), declval()));
+ template using try_match_n_ovdr_t = decltype (declval<_Tp>().match_n_ovdr (declval<_1wire_id_t&>()));
+ template using try_skip_t = decltype (declval<_Tp>().skip (declval()));
+ template using try_skip_n_ovdr_t = decltype (declval<_Tp>().skip_n_ovdr ());
+ template using try_first_t = decltype (declval<_Tp>().first (declval()));
+ template using try_next_t = decltype (declval<_Tp>().next (declval()));
+
+ //! Primary template to catch any non 1-wire interface types
+ template
+ struct is_1wire_ : false_ {};
+
+ //! template to catch a proper 1-wire interface type
+ template
+ struct is_1wire_ <_Tp,
+ void_t <
+// typename _Tp::Speed,
+// typename _Tp::Command,
+ use_if_same_t , bool>,
+ use_if_same_t , byte_t>,
+ use_if_same_t , byte_t>,
+ use_if_same_t , size_t>,
+ use_if_same_t , size_t>,
+ use_if_same_t , size_t>,
+ use_if_same_t , void>,
+ use_if_same_t , void>,
+ use_if_same_t , void>,
+ use_if_same_t , void>,
+ use_if_same_t , _1wire_id_t>,
+ use_if_same_t , _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
+ constexpr bool _1wire_c = _1wire_i_cnpt::is_1wire_<_Tp>::value;
+#endif
+
+//!@}
+} //namespace utl
+
+#endif /* __utl_com_1wire_h__ */
diff --git a/include/utl/com/_1wire_uart.h b/include/utl/com/_1wire_uart.h
new file mode 100644
index 0000000..546d19b
--- /dev/null
+++ b/include/utl/com/_1wire_uart.h
@@ -0,0 +1,412 @@
+/*!
+ * \file utl/com/_1wire_uart.h
+ * \brief
+ * A 1-wire implementation using a microprocessor's uart for bit timing
+ * \note
+ * This 1-wire implementation is based on MCU UART io functionality. In order
+ * to work it needs:
+ * 1) A Open drain tx and floating(or pull-up) rx UART pin configuration with both pins
+ * connected to the 1-wire bus wire
+ * 2) A Transmit/receive function even in blocking/polling mode
+ * 3) A baudrate set function
+ *
+ * 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 .
+ *
+ */
+#ifndef __utl_com_1wire_uart_h__
+#define __utl_com_1wire_uart_h__
+
+#include
+#include
+#include
+
+namespace utl {
+/*!
+ * \ingroup Communication
+ * A 1-wire implementation using a microprocessor's uart for bit timing
+ * inherited from \ref _1wire_i base class.
+ * \sa _1wire_i
+ */
+//!@{
+
+ /*!
+ * \brief
+ * 1-wire UART interface template class using CRTP
+ * Using the private virtual interface we provide the interface from
+ * _1wire_i<>
+ */
+ template
+ class _1wire_uart_i : public _1wire_i<_1wire_uart_i> {
+ _CRTP_IMPL(Impl_t); //! \brief Syntactic sugar to CRTP casting
+ friend _1wire_i <_1wire_uart_i>;
+ public:
+ using type = _1wire_uart_i; //!< Export type as identity meta-function
+ using Speed = typename _1wire_i::Speed; //!< Bring bus speed
+
+ /*!
+ * \name Object lifetime
+ */
+ //!@{
+ protected:
+ _1wire_uart_i () = default; //!< Allow constructor from derived only
+ ~_1wire_uart_i () = default; //!< Allow destructor from derived only
+ //!@}
+
+ /*!
+ * \name Implementation requirements
+ * \note
+ * In order for the implementation to have the following as private members
+ * it also need to declare this class as friend
+ * for ex:
+ * class Foo : public _1wire_uart {
+ * friend _1wire_uart;
+ * byte_t UART_RW (byte_t byte);
+ * void UART_BR (uint32_t br);
+ * // ...
+ * };
+ */
+ //!@{
+ private:
+ /*!
+ * \brief
+ * Implementers's (driver) read-write function. We use the following USART configuration.
+ * - Word Length = 8 Bits
+ * - Stop Bit = One Stop bit
+ * - Parity = No parity
+ * \param The byte to send
+ * \return The byte received.
+ * \note
+ * Due to the nature of the technique, the received byte is the actual bus
+ * condition during the communication frame (time slot)
+ */
+ byte_t UART_RW (byte_t byte) { return impl().UART_RW (byte); }
+
+ /*!
+ * \brief
+ * Implementers's (driver) baudrate function.
+ * \param The desired Baudrate
+ */
+ void UART_BR (uint32_t br) { impl().UART_BR (br); }
+ //!@}
+
+ //! \name Implementation of base requirements
+ //!@{
+ private:
+ //! 1-wire UART baudrates
+ enum BR {
+ BR_STD_RST =9600,
+ BR_OVR_RST =57600,
+ BR_STD =115200,
+ BR_OVR =921600
+ };
+ Speed _speed {Speed::STD};
+
+ Speed speed () { return _speed; } //!< Get the 1-wire bus speed
+ void speed (Speed s); //!< Set the 1-wire bus speed
+
+ /*!
+ * \brief
+ * Read a bit from the 1-Wire bus, return it and provide
+ * the recovery time.
+ *
+ * --- - - - - - - - - - - - - - - - - ------
+ * Read \ / X X X X X X X X X X X X X X X /
+ * ---- - - - - - - - - - - - - - - - -
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ------------- 87/11 usec ------------->
+ * ^
+ * |
+ * Master sample
+ *
+ * 8 bits, no parity, 1 stop
+ * standard: BR: 115200
+ * Overdrive: BR: 921600
+ * TX: 0xFF
+ * RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
+ *
+ * \return The answer
+ * \arg 0 Read 0
+ * \arg 1 Read 1 (This is also returned on transition error).
+ */
+ bool bit () {
+ return (impl().UART_RW (0xFF) < 0xFF);
+ }
+
+
+ /*!
+ * \brief
+ * Send a 1-Wire write bit
+ * 8 bits, no parity, 1 stop
+ * standard: BR: 115200
+ * Overdrive: BR: 921600
+ *
+ * --- --------------------------------------
+ * Write 1 \ /
+ * ----
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * TX: 0xFF RX: 0xFF
+ *
+ * --- ------
+ * Write 0 \ /
+ * -------------------------------------
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ------------- 87/11 usec ------------->
+ * TX: 0x00 RX: 0x00
+ *
+ * \param b The bit to send
+ * \return Status of the operation
+ * \arg 0 Fail
+ * \arg 1 Success
+ */
+ bool bit (bool b) {
+ uint8_t w = (b) ? 0xFF : 0x00; // Select write frame to send
+ return (w == impl().UART_RW (w)); // Return status
+ }
+ bool _reset ();
+ //!@}
+ };
+
+ /*!
+ * Set the 1-wire bus speed for normal operation only
+ * \note
+ * We have moved the BR set functionality here to reduce the code inside bit().
+ * This is OK as long as the _1wire_i<> always check speed.
+ * \param s The desired speed
+ */
+ template
+ void _1wire_uart_i::speed (Speed s) {
+ switch (_speed = s) {
+ case Speed::STD: impl().UART_BR (BR_STD); break;
+ case Speed::OVDR: impl().UART_BR (BR_OVR); break;
+ }
+ }
+
+ /*!
+ * \brief
+ * Generate a 1-wire reset
+ *
+ * --- ---- - - - -------
+ * Reset \ / \ X X X /
+ * -------------------- - - - -
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ---------- 1024/174 usec ------------->
+ *
+ * 8 bits, no parity, 1 stop
+ * Standard: Overdrive :
+ * BR: 9600, BR: 57600
+ * TX: 0xF0, TX: 0xF8
+ * RX: 0xF0 not present RX: 0xF8 not present
+ * less if present less if present
+ *
+ * \param t Timing
+ * \return The status of the operation
+ * \arg 0 Fail
+ * \arg 1 Success
+ */
+ template
+ bool _1wire_uart_i::_reset () {
+ // Select frame to send
+ uint8_t w = (_speed == Speed::STD) ? 0xF0 : 0xF8;
+ // Select baudrate
+ impl().UART_BR ((_speed == Speed::STD) ? BR_STD_RST : BR_OVR_RST);
+ // Send frame and check the result
+ return (impl().UART_RW (w) < w);
+ }
+
+ /*!
+ * \brief
+ * A virtual base class interface implementation.
+ * Using the private virtual interface we provide the interface from
+ * _1wire_i
+ * \param impl_t = virtual_tag
+ */
+ template <>
+ class _1wire_uart_i : public _1wire_i {
+ public:
+ using type = _1wire_uart_i; //!< Export type as identity meta-function
+ using Speed = typename _1wire_i::Speed; //!< Bring bus speed
+
+ /*!
+ * \name Object lifetime
+ */
+ //!@{
+ protected:
+ _1wire_uart_i () = default; //!< Allow constructor from derived only
+ ~_1wire_uart_i () = default; //!< Allow destructor from derived only
+ //!@}
+
+ /*!
+ * \name Implementation requirements
+ */
+ //!@{
+ private:
+ /*!
+ * \brief
+ * Implementers's (driver) read-write function. We use the following USART configuration.
+ * - Word Length = 8 Bits
+ * - Stop Bit = One Stop bit
+ * - Parity = No parity
+ * \param The byte to send
+ * \return The byte received.
+ * \note
+ * Due to the nature of the technique, the received byte is the actual bus
+ * condition during the communication frame (time slot)
+ */
+ virtual byte_t UART_RW (byte_t byte) =0;
+
+ /*!
+ * \brief
+ * Implementers's (driver) baudrate function.
+ * \param The desired Baudrate
+ */
+ virtual void UART_BR (uint32_t br) =0;
+ //!@}
+
+ //! \name Implementation of base requirements
+ //!@{
+ private:
+ //! 1-wire UART baudrates
+ enum BR {
+ BR_STD_RST =9600,
+ BR_OVR_RST =57600,
+ BR_STD =115200,
+ BR_OVR =921600
+ };
+ Speed _speed {Speed::STD};
+
+ Speed speed () { return _speed; } //!< Get the 1-wire bus speed
+ void speed (Speed s); //!< Set the 1-wire bus speed
+
+ /*!
+ * \brief
+ * Read a bit from the 1-Wire bus, return it and provide
+ * the recovery time.
+ *
+ * --- - - - - - - - - - - - - - - - - ------
+ * Read \ / X X X X X X X X X X X X X X X /
+ * ---- - - - - - - - - - - - - - - - -
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ------------- 87/11 usec ------------->
+ * ^
+ * |
+ * Master sample
+ *
+ * 8 bits, no parity, 1 stop
+ * standard: BR: 115200
+ * Overdrive: BR: 921600
+ * TX: 0xFF
+ * RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
+ *
+ * \return The answer
+ * \arg 0 Read 0
+ * \arg 1 Read 1 (This is also returned on transition error).
+ */
+ bool bit () {
+ return (UART_RW (0xFF) < 0xFF);
+ }
+
+
+ /*!
+ * \brief
+ * Send a 1-Wire write bit
+ * 8 bits, no parity, 1 stop
+ * standard: BR: 115200
+ * Overdrive: BR: 921600
+ *
+ * --- --------------------------------------
+ * Write 1 \ /
+ * ----
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * TX: 0xFF RX: 0xFF
+ *
+ * --- ------
+ * Write 0 \ /
+ * -------------------------------------
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ------------- 87/11 usec ------------->
+ * TX: 0x00 RX: 0x00
+ *
+ * \param b The bit to send
+ * \return Status of the operation
+ * \arg 0 Fail
+ * \arg 1 Success
+ */
+ bool bit (bool b) {
+ uint8_t w = (b) ? 0xFF : 0x00; // Select write frame to send
+ return (w == UART_RW (w)); // Return status
+ }
+ bool _reset ();
+ //!@}
+ };
+
+ /*!
+ * Set the 1-wire bus speed for normal operation only
+ * \note
+ * We have moved the BR set functionality here to reduce the code inside bit().
+ * This is OK as long as the _1wire_i<> always check speed.
+ * \param s The desired speed
+ */
+ void _1wire_uart_i::speed (Speed s) {
+ switch (_speed = s) {
+ case Speed::STD: UART_BR (BR_STD); break;
+ case Speed::OVDR: UART_BR (BR_OVR); break;
+ }
+ }
+
+ /*!
+ * \brief
+ * Generate a 1-wire reset
+ *
+ * --- ---- - - - -------
+ * Reset \ / \ X X X /
+ * -------------------- - - - -
+ * RS: | | | | | | | | | | |
+ * bit: ST 0 1 2 3 4 5 6 7 SP
+ * < ---------- 1024/174 usec ------------->
+ *
+ * 8 bits, no parity, 1 stop
+ * Standard: Overdrive :
+ * BR: 9600, BR: 57600
+ * TX: 0xF0, TX: 0xF8
+ * RX: 0xF0 not present RX: 0xF8 not present
+ * less if present less if present
+ *
+ * \param t Timing
+ * \return The status of the operation
+ * \arg 0 Fail
+ * \arg 1 Success
+ */
+ bool _1wire_uart_i::_reset () {
+ // Select frame to send
+ uint8_t w = (_speed == Speed::STD) ? 0xF0 : 0xF8;
+ // Select baudrate
+ UART_BR ((_speed == Speed::STD) ? BR_STD_RST : BR_OVR_RST);
+ // Send frame and check the result
+ return (UART_RW (w) < w);
+ }
+
+//!@}
+
+} // namespace utl
+
+#endif /* __utl_com_1wire_uart_h__ */