RingBuf.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /**
  2. * Copyright (c) 2011-2022 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef RingBuf_h
  26. #define RingBuf_h
  27. /**
  28. * \file
  29. * \brief Ring buffer for data loggers.
  30. */
  31. #include "common/SysCall.h"
  32. #include "common/FmtNumber.h"
  33. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  34. // Teensy 3.5/3.6 has hard fault at 0x20000000 for unaligned memcpy.
  35. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  36. inline bool is_aligned(const void* ptr, uintptr_t alignment) {
  37. auto iptr = reinterpret_cast<uintptr_t>(ptr);
  38. return !(iptr % alignment);
  39. }
  40. inline void memcpyBuf(void* dst, const void* src, size_t len) {
  41. const uint8_t* b = reinterpret_cast<const uint8_t*>(0X20000000UL);
  42. uint8_t* d = reinterpret_cast<uint8_t*>(dst);
  43. const uint8_t *s = reinterpret_cast<const uint8_t*>(src);
  44. if ((is_aligned(d, 4) && is_aligned(s, 4) && (len & 3) == 0) ||
  45. !((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
  46. memcpy(dst, src, len);
  47. } else {
  48. while (len--) {
  49. *d++ = *s++;
  50. }
  51. }
  52. }
  53. #else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
  54. inline void memcpyBuf(void* dst, const void* src, size_t len) {
  55. memcpy(dst, src, len);
  56. }
  57. #endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
  58. #endif // DOXYGEN_SHOULD_SKIP_THIS
  59. /**
  60. * \class RingBuf
  61. * \brief Ring buffer for data loggers.
  62. *
  63. * This ring buffer may be used in ISRs. bytesFreeIsr(), bytesUsedIsr(),
  64. * memcopyIn(), and memcopyOut() are ISR callable. For ISR use call
  65. * memcopyIn() in the ISR and use writeOut() in non-interrupt code
  66. * to write data to a file. readIn() and memcopyOut can be use in a
  67. * similar way to provide file data to an ISR.
  68. *
  69. * Print into a RingBuf in an ISR should also work but has not been verified.
  70. */
  71. template<class F, size_t Size>
  72. class RingBuf : public Print {
  73. public:
  74. /**
  75. * RingBuf Constructor.
  76. */
  77. RingBuf() {}
  78. /**
  79. * Initialize RingBuf.
  80. * \param[in] file Underlying file.
  81. */
  82. void begin(F* file) {
  83. m_file = file;
  84. m_count = 0;
  85. m_head = 0;
  86. m_tail = 0;
  87. clearWriteError();
  88. }
  89. /**
  90. *
  91. * \return the RingBuf free space in bytes. Not ISR callable.
  92. */
  93. size_t bytesFree() const {
  94. size_t count;
  95. noInterrupts();
  96. count = m_count;
  97. interrupts();
  98. return Size - count;
  99. }
  100. /**
  101. * \return the RingBuf free space in bytes. ISR callable.
  102. */
  103. size_t bytesFreeIsr() const {
  104. return Size - m_count;
  105. }
  106. /**
  107. * \return the RingBuf used space in bytes. Not ISR callable.
  108. */
  109. size_t bytesUsed() const {
  110. size_t count;
  111. noInterrupts();
  112. count = m_count;
  113. interrupts();
  114. return count;
  115. }
  116. /**
  117. * \return the RingBuf used space in bytes. ISR callable.
  118. */
  119. size_t bytesUsedIsr() const {
  120. return m_count;
  121. }
  122. /**
  123. * Copy data to the RingBuf from buf.
  124. * The number of bytes copied may be less than count if
  125. * count is greater than bytesFree.
  126. *
  127. * This function may be used in an ISR with writeOut()
  128. * in non-interrupt code.
  129. *
  130. * \param[in] buf Location of data to be copied.
  131. * \param[in] count number of bytes to be copied.
  132. * \return Number of bytes actually copied.
  133. */
  134. size_t memcpyIn(const void* buf, size_t count) {
  135. const uint8_t* src = (const uint8_t*)buf;
  136. size_t n = Size - m_count;
  137. if (count > n) {
  138. count = n;
  139. }
  140. size_t nread = 0;
  141. while (nread != count) {
  142. n = minSize(Size - m_head, count - nread);
  143. memcpyBuf(m_buf + m_head, src + nread, n);
  144. m_head = advance(m_head, n);
  145. nread += n;
  146. }
  147. m_count += nread;
  148. return nread;
  149. }
  150. /**
  151. * Copy date from the RingBuf to buf.
  152. * The number of bytes copied may be less than count if
  153. * bytesUsed is less than count.
  154. *
  155. * This function may be used in an ISR with readIn() in
  156. * non-interrupt code.
  157. *
  158. * \param[out] buf Location to receive the data.
  159. * \param[in] count number of bytes to be copied.
  160. * \return Number of bytes actually copied.
  161. */
  162. size_t memcpyOut(void* buf, size_t count) {
  163. uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
  164. size_t nwrite = 0;
  165. size_t n = m_count;
  166. if (count > n) {
  167. count = n;
  168. }
  169. while (nwrite != count) {
  170. n = minSize(Size - m_tail, count - nwrite);
  171. memcpyBuf(dst + nwrite, m_buf + m_tail, n);
  172. m_tail = advance(m_tail, n);
  173. nwrite += n;
  174. }
  175. m_count -= nwrite;
  176. return nwrite;
  177. }
  178. /** Print a number followed by a field terminator.
  179. * \param[in] value The number to be printed.
  180. * \param[in] term The field terminator. Use '\\n' for CR LF.
  181. * \param[in] prec Number of digits after decimal point.
  182. * \return The number of bytes written.
  183. */
  184. size_t printField(double value, char term, uint8_t prec = 2) {
  185. char buf[24];
  186. char* str = buf + sizeof(buf);
  187. if (term) {
  188. *--str = term;
  189. if (term == '\n') {
  190. *--str = '\r';
  191. }
  192. }
  193. str = fmtDouble(str, value, prec, false);
  194. return write(str, buf + sizeof(buf) - str);
  195. }
  196. /** Print a number followed by a field terminator.
  197. * \param[in] value The number to be printed.
  198. * \param[in] term The field terminator. Use '\\n' for CR LF.
  199. * \param[in] prec Number of digits after decimal point.
  200. * \return The number of bytes written or -1 if an error occurs.
  201. */
  202. size_t printField(float value, char term, uint8_t prec = 2) {
  203. return printField(static_cast<double>(value), term, prec);
  204. }
  205. /** Print a number followed by a field terminator.
  206. * \param[in] value The number to be printed.
  207. * \param[in] term The field terminator. Use '\\n' for CR LF.
  208. * \return The number of bytes written or -1 if an error occurs.
  209. */
  210. template <typename Type>
  211. size_t printField(Type value, char term) {
  212. char sign = 0;
  213. char buf[3*sizeof(Type) + 3];
  214. char* str = buf + sizeof(buf);
  215. if (term) {
  216. *--str = term;
  217. if (term == '\n') {
  218. *--str = '\r';
  219. }
  220. }
  221. if (value < 0) {
  222. value = -value;
  223. sign = '-';
  224. }
  225. if (sizeof(Type) < 4) {
  226. str = fmtBase10(str, (uint16_t)value);
  227. } else {
  228. str = fmtBase10(str, (uint32_t)value);
  229. }
  230. if (sign) {
  231. *--str = sign;
  232. }
  233. return write((const uint8_t*)str, &buf[sizeof(buf)] - str);
  234. }
  235. /**
  236. * Read data into the RingBuf from the underlying file.
  237. * the number of bytes read may be less than count if
  238. * bytesFree is less than count.
  239. *
  240. * This function may be used in non-interrupt code with
  241. * memcopyOut() in an ISR.
  242. *
  243. * \param[in] count number of bytes to be read.
  244. * \return Number of bytes actually read.
  245. */
  246. size_t readIn(size_t count) {
  247. size_t nread = 0;
  248. size_t n = bytesFree(); // Protected from interrupts.
  249. if (count > n) {
  250. count = n;
  251. }
  252. while (nread != count) {
  253. n = minSize(Size - m_head, count - nread);
  254. if ((size_t)m_file->read(m_buf + m_head, n) != n) {
  255. return nread;
  256. }
  257. m_head = advance(m_head, n);
  258. nread += n;
  259. }
  260. noInterrupts();
  261. m_count += nread;
  262. interrupts();
  263. return nread;
  264. }
  265. /**
  266. * Write all data in the RingBuf to the underlying file.
  267. * \return true for success.
  268. */
  269. bool sync() {
  270. size_t n = bytesUsed();
  271. return writeOut(n) == n;
  272. }
  273. /**
  274. * Copy data to the RingBuf from buf.
  275. *
  276. * The number of bytes copied may be less than count if
  277. * count is greater than bytesFree.
  278. * Use getWriteError() to check for print errors and
  279. * clearWriteError() to clear error.
  280. *
  281. * \param[in] buf Location of data to be written.
  282. * \param[in] count number of bytes to be written.
  283. * \return Number of bytes actually written.
  284. */
  285. size_t write(const void* buf, size_t count) {
  286. if (count > bytesFree()) {
  287. setWriteError();
  288. }
  289. return memcpyIn(buf, count);
  290. }
  291. /**
  292. * Copy str to RingBuf.
  293. *
  294. * \param[in] str Location of data to be written.
  295. * \return Number of bytes actually written.
  296. */
  297. size_t write(const char* str) {
  298. return Print::write(str);
  299. }
  300. /**
  301. * Override virtual function in Print for efficiency.
  302. *
  303. * \param[in] buf Location of data to be written.
  304. * \param[in] count number of bytes to be written.
  305. * \return Number of bytes actually written.
  306. */
  307. size_t write(const uint8_t* buf, size_t count) override {
  308. return write((const void*)buf, count);
  309. }
  310. /**
  311. * Required function for Print.
  312. * \param[in] data Byte to be written.
  313. * \return Number of bytes actually written.
  314. */
  315. size_t write(uint8_t data) override {
  316. return write(&data, 1);
  317. }
  318. /**
  319. * Write data to file from RingBuf buffer.
  320. * \param[in] count number of bytes to be written.
  321. *
  322. * The number of bytes written may be less than count if
  323. * bytesUsed is less than count or if an error occurs.
  324. *
  325. * This function may be used in non-interrupt code with
  326. * memcopyIn() in an ISR.
  327. *
  328. * \return Number of bytes actually written.
  329. */
  330. size_t writeOut(size_t count) {
  331. size_t n = bytesUsed(); // Protected from interrupts;
  332. if (count > n) {
  333. count = n;
  334. }
  335. size_t nwrite = 0;
  336. while (nwrite != count) {
  337. n = minSize(Size - m_tail, count - nwrite);
  338. if (m_file->write(m_buf + m_tail, n) != n) {
  339. break;
  340. }
  341. m_tail = advance(m_tail, n);
  342. nwrite += n;
  343. }
  344. noInterrupts();
  345. m_count -= nwrite;
  346. interrupts();
  347. return nwrite;
  348. }
  349. private:
  350. uint8_t __attribute__((aligned(4))) m_buf[Size];
  351. F* m_file = nullptr;
  352. volatile size_t m_count;
  353. size_t m_head;
  354. size_t m_tail;
  355. size_t advance(size_t index, size_t n) {
  356. index += n;
  357. return index < Size ? index : index - Size;
  358. }
  359. // avoid macro MIN
  360. size_t minSize(size_t a, size_t b) {return a < b ? a : b;}
  361. };
  362. #endif // RingBuf_h