Mark3 Realtime Kernel
streamer.cpp
Go to the documentation of this file.
1 /*===========================================================================
2  _____ _____ _____ _____
3  ___| _|__ __|_ |__ __|__ |__ __| __ |__ ______
4 | \ / | || \ || | || |/ / ||___ |
5 | \/ | || \ || \ || \ ||___ |
6 |__/\__/|__|_||__|\__\ __||__|\__\ __||__|\__\ __||______|
7  |_____| |_____| |_____| |_____|
8 
9 --[Mark3 Realtime Platform]--------------------------------------------------
10 
11 Copyright (c) 2012 - 2019 m0slevin, all rights reserved.
12 See license.txt for more information
13 =========================================================================== */
20 #include "kerneltypes.h"
21 #include "mark3.h"
22 #include "streamer.h"
23 
24 namespace Mark3
25 {
26 //---------------------------------------------------------------------------
27 void Streamer::Init(uint8_t* pau8Buffer_, uint16_t u16Size_)
28 {
29  m_u16Head = 0;
30  m_u16Tail = 0;
31  m_u16Size = u16Size_;
33  m_pau8Buffer = pau8Buffer_;
34  m_pu8LockAddr = 0;
35 }
36 
37 //---------------------------------------------------------------------------
38 bool Streamer::Read(uint8_t* pu8Data_)
39 {
40  auto rc = true;
41 
42  const auto cs = CriticalGuard{};
43 
44  if (m_u16Avail == m_u16Size) {
45  rc = false;
46  } else {
47  auto* pu8Dest = &m_pau8Buffer[m_u16Tail];
48  if (pu8Dest == m_pu8LockAddr) {
49  rc = false;
50  } else {
51  *pu8Data_ = *pu8Dest;
52  m_u16Tail++;
53  if (m_u16Tail >= m_u16Size) {
54  m_u16Tail = 0;
55  }
56  m_u16Avail++;
57  }
58  }
59 
60  return rc;
61 }
62 
63 //---------------------------------------------------------------------------
64 uint16_t Streamer::Read(uint8_t* pu8Data_, uint16_t u16Len_)
65 {
66  auto u16ToRead = uint16_t{};
67 
68  if (m_pu8LockAddr != 0) {
69  return 0;
70  }
71 
72  auto u16Allocated = uint16_t{};
73  auto u16PreWrap = uint16_t{};
74  auto* pu8Src = (uint8_t*){};
75  auto* pu8Dst = (uint8_t*){};
76 
77  { // Begin critical section
78  const auto cs = CriticalGuard{};
79  u16Allocated = m_u16Size - m_u16Avail;
80 
81  if (u16Allocated > u16Len_) {
82  u16ToRead = u16Len_;
83  } else {
84  u16ToRead = u16Allocated;
85  }
86 
87  u16PreWrap = m_u16Size - m_u16Tail;
88 
89  pu8Src = &m_pau8Buffer[m_u16Tail];
90  pu8Dst = pu8Data_;
91 
92  Lock(pu8Src);
93  } // end critical section
94 
95  if (u16Allocated != 0u) {
96  if (u16PreWrap >= u16ToRead) {
97  for (auto i = uint16_t{0}; i < u16ToRead; i++) { *pu8Dst++ = *pu8Src++; }
98  } else {
99  for (auto i = uint16_t{0}; i < u16PreWrap; i++) { *pu8Dst++ = *pu8Src++; }
100  pu8Src = m_pau8Buffer;
101  for (auto i = u16PreWrap; i < u16ToRead; i++) { *pu8Dst++ = *pu8Src++; }
102  }
103  }
104 
105  { // Begin critical section
106  const auto cs = CriticalGuard{};
107  m_u16Avail += u16ToRead;
108  if (u16PreWrap >= u16ToRead) {
109  m_u16Tail += u16ToRead;
110  } else {
111  m_u16Tail += u16ToRead - m_u16Size;
112  }
113 
114  Unlock();
115  } // end critical section
116  return u16ToRead;
117 }
118 
119 //---------------------------------------------------------------------------
120 bool Streamer::Write(uint8_t u8Data_)
121 {
122  auto rc = true;
123 
124  const auto cs = CriticalGuard{};
125  if (m_u16Avail == 0u) {
126  rc = false;
127  } else {
129  rc = false;
130  } else {
131  m_pau8Buffer[m_u16Head] = u8Data_;
132  m_u16Head++;
133  if (m_u16Head >= m_u16Size) {
134  m_u16Head = 0;
135  }
136  m_u16Avail--;
137  }
138  }
139 
140  return rc;
141 }
142 
143 //---------------------------------------------------------------------------
144 uint16_t Streamer::Write(const uint8_t* pu8Data_, uint16_t u16Len_)
145 {
146  auto u16ToWrite = uint16_t{};
147 
148  // Bail if the buffer is currently locked.
149  if (m_pu8LockAddr != 0) {
150  return 0;
151  }
152 
153  // Update the buffer metadata in a critical section, and lock it so that
154  // we can safely write to it with interrupts enabled.
155 
156  auto u16PreWrap = uint16_t{};
157  auto* pu8Src = (const uint8_t*){};
158  auto* pu8Dst = (uint8_t*){};
159 
160  { // Begin critical section
161  const auto cs = CriticalGuard{};
162  if (m_u16Avail > u16Len_) {
163  u16ToWrite = u16Len_;
164  } else {
165  u16ToWrite = m_u16Avail;
166  }
167 
168  u16PreWrap = m_u16Size - m_u16Head;
169 
170  pu8Src = pu8Data_;
171  pu8Dst = &m_pau8Buffer[m_u16Head];
172 
173  m_u16Avail -= u16ToWrite;
174 
175  if (u16PreWrap >= u16ToWrite) {
176  m_u16Head += u16ToWrite;
177  } else {
178  m_u16Head += u16ToWrite - m_u16Size;
179  }
180 
181  Lock(pu8Dst);
182  } // End critical section
183 
184  // Perform the buffer writes with interrupts enabled, buffers locked.
185  if (u16ToWrite != 0u) {
186  if (u16PreWrap >= u16ToWrite) {
187  for (auto i = uint16_t{0}; i < u16ToWrite; i++) { *pu8Dst++ = *pu8Src++; }
188  } else {
189  for (auto i = uint16_t{0}; i < u16PreWrap; i++) { *pu8Dst++ = *pu8Src++; }
190  pu8Dst = m_pau8Buffer;
191  for (auto i = u16PreWrap; i < u16ToWrite; i++) { *pu8Dst++ = *pu8Src++; }
192  }
193  }
194 
195  Unlock();
196  return u16ToWrite;
197 }
198 
199 //---------------------------------------------------------------------------
201 {
202  auto bRc = true;
203  const auto cs = CriticalGuard{};
204  if (m_u16Avail == m_u16Size) {
205  bRc = false;
206  }
207  return bRc;
208 }
209 
210 //---------------------------------------------------------------------------
212 {
213  auto bRc = false;
214 
215  const auto cs = CriticalGuard{};
216  if (m_u16Avail != 0u) {
217  bRc = true;
218  }
219 
220  return bRc;
221 }
222 
223 //---------------------------------------------------------------------------
224 bool Streamer::Claim(uint8_t** pu8Addr_)
225 {
226  auto rc = true;
227 
228  const auto cs = CriticalGuard{};
229  if (m_u16Avail == 0u) {
230  rc = false;
231  } else {
233  rc = false;
234  } else {
235  *pu8Addr_ = &m_pau8Buffer[m_u16Head];
236  if (m_pu8LockAddr == 0) {
238  }
239  m_u16Head++;
240  if (m_u16Head >= m_u16Size) {
241  m_u16Head = 0;
242  }
243  m_u16Avail--;
244  }
245  }
246  return rc;
247 }
248 
249 //---------------------------------------------------------------------------
250 void Streamer::Lock(uint8_t* pu8LockAddr_)
251 {
252  const auto cs = CriticalGuard{};
253  m_pu8LockAddr = pu8LockAddr_;
254 }
255 
256 //---------------------------------------------------------------------------
258 {
259  const auto cs = CriticalGuard{};
260  m_pu8LockAddr = 0;
261 }
262 
263 //---------------------------------------------------------------------------
265 {
266  const auto cs = CriticalGuard{};
267  return m_u16Avail == m_u16Size;
268 }
269 } // namespace Mark3
Basic data type primatives used throughout the OS.
void Init(uint8_t *pau8Buffer_, uint16_t u16Size_)
Init. Initialize the Streamer object prior to its use, providing a blob of memory for the object to m...
Definition: streamer.cpp:27
uint8_t * m_pau8Buffer
Pointer to the buffer managed in this object.
Definition: streamer.h:154
void Unlock(void)
Unlock. Reset the lock pointer in the object, allowing a consumer to read any previously unavailable ...
Definition: streamer.cpp:257
bool Write(uint8_t u8Data_)
Write. Write a byte of data into the stream.
Definition: streamer.cpp:120
uint16_t m_u16Size
Size of the stream&#39;s circular buffer (in bytes)
Definition: streamer.h:157
uint16_t m_u16Avail
Number of bytes free in the stream.
Definition: streamer.h:158
bool Claim(uint8_t **pu8Addr_)
Claim. Claim a byte of data for writing, without actually writing into it. When the writer is ready t...
Definition: streamer.cpp:224
Definition: atomic.cpp:23
uint16_t m_u16Tail
Current tail index (read from) of the stream.
Definition: streamer.h:160
Single include file given to users of the Mark3 Kernel API.
bool Read(uint8_t *pu8Data_)
Read. Read a byte of data from the stream, if available.
Definition: streamer.cpp:38
uint16_t m_u16Head
Current head index (write to) of the stream.
Definition: streamer.h:159
uint8_t * m_pu8LockAddr
Address of the lock point in the stream.
Definition: streamer.h:155
The CriticalGuard class. This class provides an implemention of RAII for critical sections...
Definition: criticalguard.h:38
bool IsEmpty(void)
IsEmpty.
Definition: streamer.cpp:264
void Lock(uint8_t *pu8LockAddr_)
Lock. When the lock is set, a client can neither read from, or write to the buffer at the index speci...
Definition: streamer.cpp:250
Thread/Interrupt-safe byte-based data streaming.
bool CanRead(void)
CanRead.
Definition: streamer.cpp:200
bool CanWrite(void)
CanWrite.
Definition: streamer.cpp:211