Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

288 lignes
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/core/impl.h>
  24. #include <utl/core/crtp.h>
  25. #include <utl/meta/meta.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. private:
  67. uint32_t _clock () const { return impl()._clock (); } //!< clock frequency of the bus [Hz]
  68. void _clock (uint32_t c) { impl()._clock (c); } //!< set clock frequency of the bus [Hz]
  69. void _start() { impl()._start (); } //!< Send start functionality
  70. void _stop() { impl()._stop (); } //!< Send stop functionality
  71. byte_t _rx_data (bool ack, Sequence seq) { return impl()._rx_data (ack, seq); }
  72. bool _tx_data (byte_t byte, Sequence seq) { return impl()._tx_data (byte, seq); }
  73. //!@}
  74. /*!
  75. * \name Get/Set functions
  76. */
  77. //!@{
  78. public:
  79. uint32_t clock () const { return _clock (); } //!< \return clock frequency of the bus
  80. void clock (uint32_t f) { _clock (f); } //!< \brief set clock frequency of the bus
  81. //!@}
  82. /*!
  83. * \name User functions
  84. */
  85. //!@{
  86. public:
  87. void start() { _start (); } //!< Send start functionality
  88. void stop () { _stop (); } //!< Send stop functionality
  89. /*!
  90. * \brief
  91. * Receive a byte from the i2c bus.
  92. * \param ack Optional ack bit.
  93. * \arg 1 ACK the reception
  94. * \arg 0 Don't ACK the reception.
  95. * \param seq The operation sequence to execute
  96. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  97. * \arg Sequence::ACK Send only the ack bit
  98. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  99. * \return The byte received.
  100. */
  101. byte_t rx_data (bool ack, Sequence seq =Sequence::BYTEnACK) {
  102. return _rx_data (ack, seq);
  103. }
  104. /*!
  105. * \brief
  106. * Transmit a byte to the i2c bus.
  107. * \param byte The byte to send.
  108. * \param seq The operation sequence to execute
  109. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  110. * \arg Sequence::ACK Read only the ack bit
  111. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  112. * \return Slave's ACK bit
  113. * \arg false Slave didn't ACK
  114. * \arg true Slave did ACK
  115. */
  116. bool tx_data (byte_t byte, Sequence seq =Sequence::BYTEnACK) {
  117. return _tx_data (byte, seq);
  118. }
  119. //!@}
  120. };
  121. /*!
  122. * \brief
  123. * A virtual base class specialization
  124. * \param impl_t = virtual_tag
  125. */
  126. template<>
  127. class i2c_i <virtual_tag> {
  128. public:
  129. using type = i2c_i <virtual_tag>; //!< Export type as identity meta-function
  130. //! I2C transmit/receive sequence
  131. enum class Sequence {
  132. BYTE=0, //!< Only read/write byte [8 clocks]
  133. ACK, //!< Only send/receive ack [1 clock]
  134. BYTEnACK //!< Read/Write byte and ack [9 clocks]
  135. };
  136. /*!
  137. * \name Object lifetime
  138. */
  139. //!@{
  140. protected:
  141. i2c_i () = default; //!< Allow constructor from derived only
  142. i2c_i (const type&) = delete; //!< No copies
  143. type& operator= (const type&) = delete;
  144. public:
  145. virtual ~i2c_i () = default; //!< Virtual default destructor
  146. //!@}
  147. /*!
  148. * \name Implementation requirements
  149. */
  150. //!@{
  151. private:
  152. virtual uint32_t _clock () const = 0; //!< \return clock frequency of the bus [Hz]
  153. virtual void _clock (uint32_t) = 0; //!< \brief set clock frequency of the bus [Hz]
  154. virtual void _start() = 0; //!< Send start functionality
  155. virtual void _stop() = 0; //!< Send stop functionality
  156. virtual byte_t _rx_data (bool ack, Sequence seq) = 0; //!< Receive a byte from the i2c bus.
  157. virtual bool _tx_data (byte_t byte, Sequence seq) = 0; //!< Transmit a byte to the i2c bus.
  158. //!@}
  159. /*!
  160. * \name Get/Set functions
  161. */
  162. //!@{
  163. public:
  164. uint32_t clock () const { return _clock(); } //!< \return clock frequency of the bus [Hz]
  165. void clock (uint32_t c) { _clock(c); } //!< \brief set clock frequency of the bus [Hz]
  166. //!@}
  167. /*!
  168. * \name User functions
  169. */
  170. //!@{
  171. public:
  172. void start () { _start(); }
  173. void stop () { _stop(); }
  174. /*!
  175. * \brief
  176. * Receive a byte from the i2c bus.
  177. * \param ack Optional ack bit.
  178. * \arg 1 ACK the reception
  179. * \arg 0 Don't ACK the reception.
  180. * \param seq The operation sequence to execute
  181. * \arg Sequence::BYTE Receive only the byte, do not send ack clock
  182. * \arg Sequence::ACK Send only the ack bit
  183. * \arg Sequence::BYTEnACK Receive the byte and send the ack bit
  184. * \return The byte received.
  185. */
  186. byte_t rx_data (bool ack, Sequence seq =Sequence::BYTEnACK) {
  187. return _rx_data (ack, seq);
  188. }
  189. /*!
  190. * \brief
  191. * Transmit a byte to the i2c bus.
  192. * \param byte The byte to send.
  193. * \param seq The operation sequence to execute
  194. * \arg Sequence::BYTE Transmit only the byte, do not read ack bit
  195. * \arg Sequence::ACK Read only the ack bit
  196. * \arg Sequence::BYTEnACK Transmit the byte and read the ack bit
  197. * \return Slave's ACK bit
  198. * \arg false Slave didn't ACK
  199. * \arg true Slave did ACK
  200. */
  201. bool tx_data (byte_t byte, Sequence seq =Sequence::BYTEnACK) {
  202. return _tx_data (byte, seq);
  203. }
  204. //!@}
  205. };
  206. #if defined _utl_have_concepts
  207. /*!
  208. * i2c interface concept
  209. */
  210. template <typename T>
  211. concept bool I2c_i = requires (T t, const T ct, typename T::Sequence s) {
  212. // Object type
  213. requires not_<std::is_copy_constructible<T>::value>::value;
  214. requires not_<std::is_copy_assignable<T>::value>::value;
  215. // Methods
  216. {ct.clock()} -> uint32_t;
  217. {t.clock(0)} -> void;
  218. {t.start()} -> void;
  219. {t.stop()} -> void;
  220. {t.rx_data (1, s)} -> byte_t;
  221. {t.tx_data (0, s)} -> bool;
  222. };
  223. #else
  224. namespace i2c_i_details {
  225. using std::declval;
  226. template <class _Tp> using try_cclk_t = decltype (declval<const _Tp>().clock());
  227. template <class _Tp> using try_clk_t = decltype (declval<_Tp>().clock(declval<uint32_t>()));
  228. template <class _Tp> using try_start_t = decltype (declval<_Tp>().start());
  229. template <class _Tp> using try_stop_t = decltype (declval<_Tp>().stop());
  230. template <class _Tp> using try_rx_data_t
  231. = decltype (declval<_Tp>().rx_data (declval<bool>(), declval<typename _Tp::Sequence>()));
  232. template <class _Tp> using try_tx_data_t
  233. = decltype (declval<_Tp>().tx_data (declval<byte_t>(), declval<typename _Tp::Sequence>()));
  234. //! Primary template to catch any non I2C interface types
  235. template <typename _Tp, typename =void>
  236. struct is_i2c_ : meta::false_ { };
  237. //! template to catch a proper I2C interface type
  238. template <typename _Tp>
  239. struct is_i2c_ <_Tp,
  240. meta::void_t <
  241. typename _Tp::Sequence,
  242. // meta::use_if_same_t <uint32_t,try_cclk_t <_Tp>>,
  243. // meta::use_if_same_t <void, try_clk_t <_Tp>>,
  244. // meta::use_if_same_t <void, try_start_t <_Tp>>,
  245. // meta::use_if_same_t <void, try_stop_t <_Tp>>,
  246. // meta::use_if_same_t <byte_t, try_rx_data_t <_Tp>>,
  247. // meta::use_if_same_t <bool, try_tx_data_t <_Tp>>
  248. void
  249. >
  250. > : meta::true_ { };
  251. }
  252. /*!
  253. * Value meta-programming function alias for I2C interface checking
  254. * \param _Tp Type to check
  255. * \return True if _Tp is a i2c interface
  256. */
  257. // template <typename _Tp>
  258. // constexpr bool I2c_i = i2c_i_details::is_i2c_<_Tp>::value;
  259. #endif
  260. //!@}
  261. } // namespace utl
  262. #endif // _utl_com_i2c_h__