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.
 
 
 
 

286 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/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__