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.
 
 
 
 

334 lines
11 KiB

  1. /*!
  2. * \file utl/com/_1wire_uart.h
  3. * \brief
  4. * A 1-wire implementation using a microprocessor's uart for bit timing
  5. * \note
  6. * This 1-wire implementation is based on MCU UART functionality. The implementation
  7. * expects:
  8. * 1) An Open drain tx and a floating(or pull-up) rx UART pin configuration with both pins
  9. * connected to the 1-wire bus wire
  10. * 2) A Transmit/receive function even in blocking/polling mode
  11. * 3) A baudrate set function
  12. *
  13. * Copyright (C) 2018 Christos Choutouridis
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Lesser General Public License as
  17. * published by the Free Software Foundation, either version 3
  18. * of the License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Lesser General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Lesser General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *
  28. */
  29. #ifndef __utl_com_1wire_uart_h__
  30. #define __utl_com_1wire_uart_h__
  31. #include <utl/impl/impl.h>
  32. #include <utl/helper/crtp.h>
  33. #include <utl/com/_1wire.h>
  34. namespace utl {
  35. /*!
  36. * \ingroup Communication
  37. * A 1-wire implementation using a microprocessor's uart for bit timing
  38. * inherited from \ref _1wire_i base class.
  39. * \sa _1wire_i
  40. */
  41. //!@{
  42. /*!
  43. * \brief
  44. * 1-wire UART interface template class using CRTP
  45. * Using the private virtual interface we provide the interface from
  46. * _1wire_i<>
  47. */
  48. template <typename Impl_t>
  49. class _1wire_uart_i : public _1wire_i<_1wire_uart_i<Impl_t>> {
  50. _CRTP_IMPL(Impl_t); //! \brief Syntactic sugar to CRTP casting
  51. friend _1wire_i <_1wire_uart_i<Impl_t>>;
  52. public:
  53. using type = _1wire_uart_i<Impl_t>; //!< Export type as identity meta-function
  54. using Speed = typename _1wire_i<type>::Speed; //!< Bring bus speed
  55. /*!
  56. * \name Object lifetime
  57. */
  58. //!@{
  59. protected:
  60. _1wire_uart_i () = default; //!< Allow constructor from derived only
  61. ~_1wire_uart_i () = default; //!< Allow destructor from derived only
  62. //!@}
  63. /*!
  64. * \name Implementation requirements
  65. * \note
  66. * In order for the implementation to have the following as private members
  67. * it also need to declare this class as friend
  68. */
  69. //!@{
  70. private:
  71. /*!
  72. * \brief
  73. * Implementers's (driver) read-write function. We expect the following
  74. * USART configuration:
  75. * - Word Length = 8 Bits
  76. * - Stop Bit = One Stop bit
  77. * - Parity = No parity
  78. * \param The byte to send
  79. * \return The byte received.
  80. * \note
  81. * Due to the nature of the technique, the received byte is the actual bus
  82. * condition during the communication frame (time slot)
  83. */
  84. byte_t UART_RW (byte_t byte) { return impl().UART_RW (byte); }
  85. /*!
  86. * \brief
  87. * Implementers's (driver) baudrate function.
  88. * \param The desired Baudrate
  89. */
  90. void UART_BR (uint32_t br) { impl().UART_BR (br); }
  91. //!@}
  92. //! \name Implementation of base requirements
  93. //!@{
  94. private:
  95. //! 1-wire UART baudrates
  96. enum BR {
  97. BR_STD_RST =9600,
  98. BR_OVR_RST =57600,
  99. BR_STD =115200,
  100. BR_OVR =921600
  101. };
  102. Speed _speed {Speed::STD};
  103. Speed speed () const { return _speed; } //!< Get the 1-wire bus speed
  104. void speed (Speed s); //!< Set the 1-wire bus speed
  105. /*!
  106. * \brief
  107. * Send a 1-Wire write bit and read the response
  108. *
  109. * Write 1 --- --------------------------------------
  110. * Read 0/1 \ /
  111. * ----
  112. * RS: | | | | | | | | | | |
  113. * bit: ST 0 1 2 3 4 5 6 7 SP
  114. * TX: 0xFF RX: 0xFF->1, less->0
  115. *
  116. * Write 0 --- ------
  117. * Read 0 \ /
  118. * -------------------------------------
  119. * RS: | | | | | | | | | | |
  120. * bit: ST 0 1 2 3 4 5 6 7 SP
  121. * < ------------- 87/11 usec ------------->
  122. * TX: 0x00 RX: 0x00
  123. *
  124. * \param b The bit to send
  125. * \return The response
  126. */
  127. bool bit (bool b) {
  128. if (b)
  129. return (UART_RW (0xFF) < 0xFF) ? 0 : 1;
  130. else {
  131. UART_RW (0x00);
  132. return 0;
  133. }
  134. }
  135. bool _reset (Speed s);
  136. //!@}
  137. };
  138. /*!
  139. * Set the 1-wire bus speed for normal operation only
  140. * \note
  141. * We have moved the BR set functionality here to reduce the code inside bit().
  142. * This is OK as long as the _1wire_i<> always check speed.
  143. * \param s The desired speed
  144. */
  145. template <typename Impl_t>
  146. void _1wire_uart_i<Impl_t>::speed (Speed s) {
  147. switch (_speed = s) {
  148. case Speed::STD: UART_BR (BR_STD); break;
  149. case Speed::OVDR: UART_BR (BR_OVR); break;
  150. }
  151. }
  152. /*!
  153. * \brief
  154. * Generate a 1-wire reset
  155. * --- ---- - - - -------
  156. * Reset \ / \ X X X /
  157. * -------------------- - - - -
  158. * RS: | | | | | | | | | | |
  159. * bit: ST 0 1 2 3 4 5 6 7 SP
  160. * < ---------- 1024/174 usec ------------->
  161. *
  162. * TX: (STD)0xF0, (OVDR)0xF8 RX: less if present
  163. *
  164. * \param t Timing
  165. * \return The status of the operation
  166. * \arg 0 Fail
  167. * \arg 1 Success
  168. */
  169. template <typename Impl_t>
  170. bool _1wire_uart_i<Impl_t>::_reset (Speed s) {
  171. // Select frame to send
  172. uint8_t w = ((_speed = s) == Speed::STD) ? 0xF0 : 0xF8;
  173. // Select baudrate
  174. impl().UART_BR ((_speed == Speed::STD) ? BR_STD_RST : BR_OVR_RST);
  175. // Send frame and check the result
  176. return (impl().UART_RW (w) < w);
  177. }
  178. /*!
  179. * \brief
  180. * A virtual base class interface implementation.
  181. * Using the private virtual interface we provide the interface from
  182. * _1wire_i<virtual_tag>
  183. * \param impl_t = virtual_tag
  184. */
  185. template <>
  186. class _1wire_uart_i<virtual_tag> : public _1wire_i<virtual_tag> {
  187. public:
  188. using type = _1wire_uart_i<virtual_tag>; //!< Export type as identity meta-function
  189. using Speed = typename _1wire_i<virtual_tag>::Speed; //!< Bring bus speed
  190. /*!
  191. * \name Object lifetime
  192. */
  193. //!@{
  194. protected:
  195. _1wire_uart_i () = default; //!< Allow constructor from derived only
  196. ~_1wire_uart_i () = default; //!< Allow destructor from derived only
  197. //!@}
  198. /*!
  199. * \name Implementation requirements
  200. */
  201. //!@{
  202. private:
  203. /*!
  204. * \brief
  205. * Implementers's (driver) read-write function. We use the following
  206. * USART configuration:
  207. * - Word Length = 8 Bits
  208. * - Stop Bit = One Stop bit
  209. * - Parity = No parity
  210. * \param The byte to send
  211. * \return The byte received.
  212. * \note
  213. * Due to the nature of the technique, the received byte is the actual bus
  214. * condition during the communication frame (time slot)
  215. */
  216. virtual byte_t UART_RW (byte_t byte) =0;
  217. /*!
  218. * \brief
  219. * Implementers's (driver) baudrate function.
  220. * \param The desired Baudrate
  221. */
  222. virtual void UART_BR (uint32_t br) =0;
  223. //!@}
  224. //! \name Implementation of base requirements
  225. //!@{
  226. private:
  227. //! 1-wire UART baudrates
  228. enum BR {
  229. BR_STD_RST =9600,
  230. BR_OVR_RST =57600,
  231. BR_STD =115200,
  232. BR_OVR =921600
  233. };
  234. Speed _speed {Speed::STD};
  235. Speed speed () const { return _speed; } //!< Get the 1-wire bus speed
  236. void speed (Speed s); //!< Set the 1-wire bus speed
  237. /*!
  238. * \brief
  239. * Send a 1-Wire write bit and read the response
  240. *
  241. * Write 1 --- --------------------------------------
  242. * Read 0/1 \ /
  243. * ----
  244. * RS: | | | | | | | | | | |
  245. * bit: ST 0 1 2 3 4 5 6 7 SP
  246. * TX: 0xFF RX: 0xFF->1, less->0
  247. *
  248. * Write 0 --- ------
  249. * Read 0 \ /
  250. * -------------------------------------
  251. * RS: | | | | | | | | | | |
  252. * bit: ST 0 1 2 3 4 5 6 7 SP
  253. * < ------------- 87/11 usec ------------->
  254. * TX: 0x00 RX: 0x00
  255. *
  256. * \param b The bit to send
  257. * \return The response
  258. */
  259. bool bit (bool b) {
  260. if (b)
  261. return (UART_RW (0xFF) < 0xFF) ? 0 : 1;
  262. else {
  263. UART_RW (0x00);
  264. return 0;
  265. }
  266. }
  267. bool _reset (Speed s);
  268. //!@}
  269. };
  270. /*!
  271. * Set the 1-wire bus speed for normal operation only
  272. * \note
  273. * We have moved the BR set functionality here to reduce the code inside bit().
  274. * This is OK as long as the _1wire_i<> always check speed.
  275. * \param s The desired speed
  276. */
  277. void _1wire_uart_i<virtual_tag>::speed (Speed s) {
  278. switch (_speed = s) {
  279. case Speed::STD: UART_BR (BR_STD); break;
  280. case Speed::OVDR: UART_BR (BR_OVR); break;
  281. }
  282. }
  283. /*!
  284. * \brief
  285. * Generate a 1-wire reset
  286. * --- ---- - - - -------
  287. * Reset \ / \ X X X /
  288. * -------------------- - - - -
  289. * RS: | | | | | | | | | | |
  290. * bit: ST 0 1 2 3 4 5 6 7 SP
  291. * < ---------- 1024/174 usec ------------->
  292. *
  293. * TX: (STD)0xF0, (OVDR)0xF8 RX: less if present
  294. *
  295. * \param t Timing
  296. * \return The status of the operation
  297. * \arg 0 Fail
  298. * \arg 1 Success
  299. */
  300. bool _1wire_uart_i<virtual_tag>::_reset (Speed s) {
  301. // Select frame to send
  302. uint8_t w = ((_speed = s) == Speed::STD) ? 0xF0 : 0xF8;
  303. // Select baudrate
  304. UART_BR ((_speed == Speed::STD) ? BR_STD_RST : BR_OVR_RST);
  305. // Send frame and check the result
  306. return (UART_RW (w) < w);
  307. }
  308. //!@}
  309. } // namespace utl
  310. #endif /* __utl_com_1wire_uart_h__ */