Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

286 lines
10 KiB

  1. /*!
  2. * \file /utl/com/i2c.h
  3. * \brief An Abstract base class interface for the i2c bus
  4. *
  5. * Copyright (C) 2018 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #ifndef _utl_com_i2c_h__
  22. #define _utl_com_i2c_h__
  23. #include <utl/impl/impl.h>
  24. #include <utl/helper/crtp.h>
  25. #include <utl/meta/sfinae.h>
  26. namespace utl {
  27. /*!
  28. * \ingroup Communication
  29. * \brief Abstract base class for i2c bus
  30. */
  31. //!@{
  32. /*!
  33. * \brief
  34. * this class force a common interface for I2C communication
  35. * protocol implementations using CRTP
  36. * \param impl_t The CRTP type (the derived/implementation class typename).
  37. */
  38. template <typename impl_t>
  39. class i2c_i {
  40. _CRTP_IMPL(impl_t);
  41. public:
  42. using type = i2c_i<impl_t>; //!< Export type as identity meta-function
  43. //! I2C transmit/receive sequence
  44. enum class Sequence {
  45. BYTE =0, //!< Only read/write byte [8 clocks]
  46. ACK, //!< Only send/receive ack [1 clock]
  47. BYTEnACK //!< Read/Write byte and ack [9 clocks]
  48. };
  49. /*!
  50. * \name Object lifetime
  51. */
  52. //!@{
  53. protected:
  54. i2c_i () = default; //!< Allow constructor from derived only
  55. ~i2c_i () = default; //!< Allow destructor from derived only
  56. i2c_i (const type&) = delete; //!< No copies
  57. type& operator= (const type&) = delete;
  58. //!@}
  59. /*!
  60. * \name Implementation requirements
  61. * \note
  62. * In order for the implementation to have the following as private members
  63. * it also need to declare this class as friend
  64. */
  65. //!@{
  66. //! uint32_t _frequency () const; < clock frequency of the bus [Hz]
  67. //! void _frequency (uint32_t); < set clock frequency of the bus [Hz]
  68. //! void _start(); < Send start functionality
  69. //! void _stop(); < Send stop functionality
  70. //! byte_t _read (bool ack, Sequence seq); < Receive a byte from the i2c bus.
  71. //! bool _write (byte_t byte, Sequence seq);< Transmit a byte to the i2c bus.
  72. //!@}
  73. /*!
  74. * \name Get/Set functions
  75. */
  76. //!@{
  77. public:
  78. uint32_t frequency () const { return impl()._frequency (); } //!< \return clock frequency of the bus
  79. void frequency (uint32_t f) { impl()._frequency (f); } //!< \brief set clock frequency of the bus
  80. //!@}
  81. /*!
  82. * \name User functions
  83. */
  84. //!@{
  85. public:
  86. void start() { impl()._start (); } //!< Send start functionality
  87. void stop () { impl()._stop (); } //!< Send stop functionality
  88. /*!
  89. * \brief
  90. * Receive a byte from the i2c bus.
  91. * \param ack Optional ack bit.
  92. * \arg 1 ACK the reception
  93. * \arg 0 Don't ACK the reception.
  94. * \param seq The operation sequence to execute
  95. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  96. * \arg Sequence::ACK Send only the ack bit
  97. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  98. * \return The byte received.
  99. */
  100. byte_t read (bool ack, Sequence seq =Sequence::BYTEnACK) {
  101. return impl()._read (ack, seq);
  102. }
  103. /*!
  104. * \brief
  105. * Transmit a byte to the i2c bus.
  106. * \param byte The byte to send.
  107. * \param seq The operation sequence to execute
  108. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  109. * \arg Sequence::ACK Read only the ack bit
  110. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  111. * \return Slave's ACK bit
  112. * \arg false Slave didn't ACK
  113. * \arg true Slave did ACK
  114. */
  115. bool write (byte_t byte, Sequence seq =Sequence::BYTEnACK) {
  116. return impl()._write (byte, seq);
  117. }
  118. //!@}
  119. };
  120. /*!
  121. * \brief
  122. * A virtual base class specialization
  123. * \param impl_t = virtual_tag
  124. */
  125. template<>
  126. class i2c_i <virtual_tag> {
  127. public:
  128. using type = i2c_i <virtual_tag>; //!< Export type as identity meta-function
  129. //! I2C transmit/receive sequence
  130. enum class Sequence {
  131. BYTE=0, //!< Only read/write byte [8 clocks]
  132. ACK, //!< Only send/receive ack [1 clock]
  133. BYTEnACK //!< Read/Write byte and ack [9 clocks]
  134. };
  135. /*!
  136. * \name Object lifetime
  137. */
  138. //!@{
  139. protected:
  140. i2c_i () = default; //!< Allow constructor from derived only
  141. i2c_i (const type&) = delete; //!< No copies
  142. type& operator= (const type&) = delete;
  143. public:
  144. virtual ~i2c_i () = default; //!< Virtual default destructor
  145. //!@}
  146. /*!
  147. * \name Implementation requirements
  148. */
  149. //!@{
  150. private:
  151. virtual uint32_t _frequency () const = 0; //!< \return clock frequency of the bus [Hz]
  152. virtual void _frequency (uint32_t) = 0; //!< \brief set clock frequency of the bus [Hz]
  153. virtual void _start() = 0; //!< Send start functionality
  154. virtual void _stop() = 0; //!< Send stop functionality
  155. virtual byte_t _read (bool ack, Sequence seq) = 0; //!< Receive a byte from the i2c bus.
  156. virtual bool _write (byte_t byte, Sequence seq) = 0; //!< Transmit a byte to the i2c bus.
  157. //!@}
  158. /*!
  159. * \name Get/Set functions
  160. */
  161. //!@{
  162. public:
  163. uint32_t frequency () const { return _frequency(); } //!< \return clock frequency of the bus [Hz]
  164. void frequency (uint32_t f) { _frequency(f); } //!< \brief set clock frequency of the bus [Hz]
  165. //!@}
  166. /*!
  167. * \name User functions
  168. */
  169. //!@{
  170. public:
  171. void start () { _start(); }
  172. void stop () { _stop(); }
  173. /*!
  174. * \brief
  175. * Receive a byte from the i2c bus.
  176. * \param ack Optional ack bit.
  177. * \arg 1 ACK the reception
  178. * \arg 0 Don't ACK the reception.
  179. * \param seq The operation sequence to execute
  180. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  181. * \arg Sequence::ACK Send only the ack bit
  182. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  183. * \return The byte received.
  184. */
  185. byte_t read (bool ack, Sequence seq =Sequence::BYTEnACK) {
  186. return _read (ack, seq);
  187. }
  188. /*!
  189. * \brief
  190. * Transmit a byte to the i2c bus.
  191. * \param byte The byte to send.
  192. * \param seq The operation sequence to execute
  193. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  194. * \arg Sequence::ACK Read only the ack bit
  195. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  196. * \return Slave's ACK bit
  197. * \arg false Slave didn't ACK
  198. * \arg true Slave did ACK
  199. */
  200. bool write (byte_t byte, Sequence seq =Sequence::BYTEnACK) {
  201. return _write (byte, seq);
  202. }
  203. //!@}
  204. };
  205. #if defined _utl_have_concepts
  206. /*!
  207. * i2c interface concept
  208. */
  209. template <typename T>
  210. concept bool i2c_c = requires (T t, const T ct, typename T::Sequence s) {
  211. // Object type
  212. requires not_<std::is_copy_constructible<T>::value>::value;
  213. requires not_<std::is_copy_assignable<T>::value>::value;
  214. // Methods
  215. {ct.frequency()} -> uint32_t;
  216. {t.frequency(0)} -> void;
  217. {t.start()} -> void;
  218. {t.stop()} -> void;
  219. {t.read (1, s)} -> byte_t;
  220. {t.write(0, s)} -> bool;
  221. };
  222. #else
  223. namespace i2c_i_cnpt {
  224. using std::declval;
  225. template <class _Tp> using try_cfreq_t = decltype (declval<const _Tp>().frequency());
  226. template <class _Tp> using try_freq_t = decltype (declval<_Tp>().frequency(declval<uint32_t>()));
  227. template <class _Tp> using try_start_t = decltype (declval<_Tp>().start());
  228. template <class _Tp> using try_stop_t = decltype (declval<_Tp>().stop());
  229. template <class _Tp> using try_read_t
  230. = decltype (declval<_Tp>().read (declval<bool>(), declval<typename _Tp::Sequence>()));
  231. template <class _Tp> using try_write_t
  232. = decltype (declval<_Tp>().write (declval<byte_t>(), declval<typename _Tp::Sequence>()));
  233. //! Primary template to catch any non I2C interface types
  234. template <typename _Tp, typename =void>
  235. struct is_i2c_ : false_ { };
  236. //! template to catch a proper I2C interface type
  237. template <typename _Tp>
  238. struct is_i2c_ <_Tp,
  239. void_t <
  240. typename _Tp::Sequence,
  241. use_if_same_t <uint32_t,try_cfreq_t <_Tp>>,
  242. use_if_same_t <void, try_freq_t <_Tp>>,
  243. use_if_same_t <void, try_start_t <_Tp>>,
  244. use_if_same_t <void, try_stop_t <_Tp>>,
  245. use_if_same_t <byte_t, try_read_t <_Tp>>,
  246. use_if_same_t <bool, try_write_t <_Tp>>
  247. > //!^ SFINAE may apply inside if_same_t<> also
  248. > : true_ { };
  249. }
  250. /*!
  251. * Value meta-programming function alias for I2C interface checking
  252. * \param _Tp Type to check
  253. * \return True if _Tp is a i2c interface
  254. */
  255. template <typename _Tp>
  256. constexpr bool i2c_c = i2c_i_cnpt::is_i2c_<_Tp>::value;
  257. #endif
  258. //!@}
  259. } // namespace utl
  260. #endif // _utl_com_i2c_h__