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.
 
 
 
 

334 lignes
11 KiB

  1. /*!
  2. * \file /utl/com/spi.h
  3. * \brief An Abstract base class interface for the spi 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_spi_h__
  22. #define _utl_com_spi_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 spi bus
  30. */
  31. //!@{
  32. namespace spi {
  33. /*!
  34. * SPI implementation bit order
  35. */
  36. enum class bitOrder {
  37. LSB_First =0x01, //!< Most significant first
  38. MSB_First =0x80 //!< Less significant first
  39. };
  40. /*!
  41. * SPI implementation Clock Polarity
  42. */
  43. enum class cpol {
  44. LOW =0, //!< LOW
  45. HIGH //!< HIGH
  46. };
  47. /*!
  48. * SPI implementation Clock Phase
  49. */
  50. enum class cpha {
  51. LOW =0, //!< LOW
  52. HIGH //!< HIGH
  53. };
  54. }
  55. /*!
  56. * Template base class for SPI communication interface using CRTP
  57. * This class force a common interface for SPI communication
  58. * protocol implementations.
  59. * \param impl_t The CRTP type (the derived/implementation class typename).
  60. */
  61. template <typename impl_t>
  62. class spi_i {
  63. _CRTP_IMPL(impl_t); //! \brief Syntactic sugar to CRTP casting
  64. public:
  65. using type = spi_i<impl_t>; //!< Export type as identity meta-function
  66. /*!
  67. * \name Object lifetime
  68. */
  69. //!@{
  70. protected:
  71. spi_i () = default; //!< Allow constructor from derived only
  72. ~spi_i () = default; //!< Allow destructor from derived only
  73. spi_i (const type&) = delete; //!< No copies
  74. type& operator= (const type&) = delete;
  75. //!@}
  76. /*!
  77. * \name Implementation requirements
  78. * \note
  79. * In order for the implementation to have the following as private members
  80. * it also need to declare this class as friend
  81. */
  82. //! @{
  83. private:
  84. uint32_t _clock () const { return impl()._clock (); } //!< clock frequency of the bus [Hz]
  85. void _clock (uint32_t c) { impl()._clock (c); } //!< set clock frequency of the bus [Hz]
  86. byte_t _tx_data (byte_t b) { return impl()._tx_data (b); } //!< Transmit a byte on the bus and return the response
  87. //! @}
  88. /*!
  89. * \name Get/Set functions provided by the interface
  90. */
  91. //!@{
  92. public:
  93. uint32_t clock () const { return _clock (); } //!< \return clock frequency of the bus
  94. void clock (uint32_t c) { _clock (c); } //!< \brief set clock frequency of the bus
  95. //!@}
  96. /*!
  97. * \name I/O functions provided by the interface
  98. */
  99. //!@{
  100. public:
  101. /*!
  102. * Transmit a byte to spi bus and return the response
  103. */
  104. byte_t tx_data (byte_t out) {
  105. return _tx_data (out);
  106. }
  107. /*!
  108. * \brief
  109. * Transmit a number of bytes to the spi bus and read the response.
  110. * \param out Pointer to data to send to the bus
  111. * \param in Pointer to buffer to store the data from the bus
  112. * \param n The number of bytes to transmit/receive
  113. * \return The number of bytes.
  114. */
  115. size_t tx_data (const byte_t *out, byte_t *in, size_t n);
  116. /*!
  117. * Receive a byte from spi bus while transmitting 0xFF
  118. */
  119. byte_t rx_data () {
  120. return _tx_data(0xFF);
  121. }
  122. /*!
  123. * \brief
  124. * Receive a number of bytes from the spi bus while transmitting 0xFFs.
  125. * \param in Pointer to buffer to store the data
  126. * \param n The number of bytes to read
  127. * \return The number of received bytes.
  128. */
  129. size_t rx_data (byte_t *in, size_t n);
  130. //!@}
  131. };
  132. /*!
  133. * \brief
  134. * Transmit a number of bytes to the spi bus and read the response.
  135. * \param out Pointer to data to send to the bus
  136. * \param in Pointer to buffer to store the data from the bus
  137. * \param n The number of bytes to transmit/receive
  138. * \return The number of bytes.
  139. */
  140. template<typename _I>
  141. size_t spi_i<_I>::tx_data (const byte_t *out, byte_t *in, size_t n) {
  142. for (size_t nn {n} ; nn ; --nn)
  143. *in++ = _tx_data (*out++);
  144. return n;
  145. }
  146. /*!
  147. * \brief
  148. * Receive a number of bytes from the spi bus while transmitting 0xFFs.
  149. * \param in Pointer to buffer to store the data
  150. * \param n The number of bytes to read
  151. * \return The number of received bytes.
  152. */
  153. template<typename _I>
  154. size_t spi_i<_I>::rx_data (byte_t *in, size_t n) {
  155. for (size_t nn {n} ; nn ; --nn)
  156. *in++ = _tx_data (0xFF);
  157. return n;
  158. }
  159. /*!
  160. * \brief
  161. * A virtual base class implementation
  162. * \param none
  163. */
  164. template <>
  165. class spi_i <virtual_tag> {
  166. public:
  167. using type = spi_i<virtual_tag>; //!< Export type as identity meta-function
  168. /*!
  169. * \name Object lifetime
  170. */
  171. //!@{
  172. protected:
  173. spi_i () = default; //!< Allow constructor from derived only
  174. spi_i (const type&) = delete; //!< No copies
  175. type& operator= (const type&) = delete;
  176. public:
  177. virtual ~spi_i () = default; //!< Virtual default destructor
  178. //!@}
  179. /*!
  180. * \name Implementation requirements
  181. */
  182. //! @{
  183. private:
  184. virtual uint32_t _clock () const =0; //!< Read the clock frequency of the bus
  185. virtual void _clock (uint32_t) =0; //!< Set the clock frequency of the bus
  186. virtual byte_t _tx_data (byte_t) =0; //!< Transmit a byte on the bus and return the response
  187. //! @}
  188. /*!
  189. * \name Get/Set functions provided by the interface
  190. */
  191. //!@{
  192. public:
  193. uint32_t clock () const { return _clock (); } //!< \return clock frequency of the bus
  194. void clock (uint32_t c) { _clock (c); } //!< \brief set clock frequency of the bus
  195. //!@}
  196. /*!
  197. * \name I/O functions provided by the interface
  198. */
  199. //!@{
  200. public:
  201. /*!
  202. * Transmit a byte to spi bus and return the response
  203. */
  204. byte_t tx_data (byte_t out) {
  205. return _tx_data (out);
  206. }
  207. /*!
  208. * \brief
  209. * Transmit a number of bytes to the spi bus and read the response.
  210. * \param out Pointer to data to send to the bus
  211. * \param in Pointer to buffer to store the data from the bus
  212. * \param n The number of bytes to transmit/receive
  213. * \return The number of bytes.
  214. */
  215. size_t tx_data (const byte_t *out, byte_t *in, size_t n);
  216. /*!
  217. * Receive a byte from spi bus while transmitting 0xFF
  218. */
  219. byte_t rx_data () {
  220. return _tx_data (0xFF);
  221. }
  222. /*!
  223. * \brief
  224. * Receive a number of bytes from the spi bus while transmitting 0xFFs.
  225. * \param in Pointer to buffer to store the data
  226. * \param n The number of bytes to read
  227. * \return The number of received bytes.
  228. */
  229. size_t rx_data (byte_t *in, size_t n);
  230. //!@}
  231. };
  232. /*!
  233. * \brief
  234. * Transmit a number of bytes to the spi bus and read the response.
  235. * \param out Pointer to data to send to the bus
  236. * \param in Pointer to buffer to store the data from the bus
  237. * \param n The number of bytes to transmit/receive
  238. * \return The number of bytes.
  239. */
  240. size_t spi_i<virtual_tag>::tx_data (const byte_t *out, byte_t *in, size_t n) {
  241. for (size_t nn {n} ; nn ; --nn)
  242. *in++ = _tx_data (*out++);
  243. return n;
  244. }
  245. /*!
  246. * \brief
  247. * Receive a number of bytes from the spi bus while transmitting 0xFFs.
  248. * \param in Pointer to buffer to store the data
  249. * \param n The number of bytes to read
  250. * \return The number of received bytes.
  251. */
  252. size_t spi_i<virtual_tag>::rx_data (byte_t *in, size_t n) {
  253. for (size_t nn {n} ; nn ; --nn)
  254. *in++ = _tx_data (0xFF);
  255. return n;
  256. }
  257. /*!
  258. * i2c interface concept
  259. */
  260. //! @{
  261. #if defined _utl_have_concepts
  262. template <typename T>
  263. concept bool Spi_i = requires (T t, const T ct, typename T::Sequence s) {
  264. // Object type
  265. requires not_<std::is_copy_constructible<T>::value>::value;
  266. requires not_<std::is_copy_assignable<T>::value>::value;
  267. // Methods
  268. {ct.clock()} -> uint32_t;
  269. {t.clock(0)} -> void;
  270. {t.tx_data(1)} -> byte_t;
  271. {t.rx_data()} -> byte_t;
  272. };
  273. #else
  274. namespace spi_i_details {
  275. using std::declval;
  276. template <class _Tp> using try_cclock_t= decltype (declval<const _Tp>().clock());
  277. template <class _Tp> using try_clock_t = decltype (declval<_Tp>().clock(declval<uint32_t>()));
  278. template <class _Tp> using try_tx_t = decltype (declval<_Tp>().tx_data(declval<byte_t>()));
  279. template <class _Tp> using try_rx_t = decltype (declval<_Tp>().rx_data());
  280. //! Primary template to catch any non SPI interface types
  281. template <typename _Tp, typename =void>
  282. struct is_spi_ : meta::false_ {};
  283. //! template to catch a proper SPI interface type
  284. template <typename _Tp>
  285. struct is_spi_ <
  286. _Tp,
  287. meta::void_t <
  288. meta::use_if_same_t <try_cclock_t<_Tp>, uint32_t>,
  289. meta::use_if_same_t <try_clock_t<_Tp>, void>,
  290. meta::use_if_same_t <try_tx_t<_Tp>, byte_t>,
  291. meta::use_if_same_t <try_rx_t<_Tp>, byte_t>
  292. >
  293. > : meta::true_ {};
  294. }
  295. /*!
  296. * Value meta-programming function for SPI interface checking
  297. * \param _Tp Type to check
  298. * \return True if _Tp is a spi interface
  299. */
  300. // template <typename _Tp>
  301. // constexpr bool Spi_i = spi_i_details::is_spi_<_Tp>::value;
  302. #endif
  303. //! @}
  304. //! @}
  305. } // namespace utl
  306. #endif /* #ifndef _utl_com_spi_h__ */