Skip to content

Commit 3d96dd4

Browse files
authored
Merge pull request #35 from bcmi-labs/sink-with-size-greater-zero
Support `Sink` with multiple elements
2 parents 0679ae8 + 6c16c41 commit 3d96dd4

File tree

4 files changed

+158
-23
lines changed

4 files changed

+158
-23
lines changed

Diff for: examples/Threading/Demo_Source_Sink_Counter/Consumer.inot

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
SINK(counter, int);
1+
SINK(counter, int, 10);
22

33
void setup()
44
{

Diff for: src/Arduino_Threads.h

+29-11
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,37 @@ public: \
4444
Source<type> name; \
4545
private:
4646

47-
#define SINK(name, type) \
47+
/* We need to call the SinkBlocking<T>(size_t const size)
48+
* non-default constructor using size as parameter.
49+
50+
* This is achieved via
51+
* SinkBlocking<type> name{size};
52+
* instead of
53+
* SinkBlocking<type> name(size);
54+
* otherwise the compiler will read it as a declaration
55+
* of a method called "name" and we get a syntax error.
56+
*
57+
* This is called "C++11 uniform init" (using "{}" instead
58+
* of "()" without "="... yikes!)
59+
* https://chromium.googlesource.com/chromium/src/+/master/styleguide/c++/c++-dos-and-donts.md
60+
*/
61+
62+
#define SINK_2_ARG(name, type) \
63+
public: \
64+
SinkBlocking<type> name{1}; \
65+
private:
66+
67+
#define SINK_3_ARG(name, type, size) \
4868
public: \
49-
SinkBlocking<type> name; \
69+
SinkBlocking<type> name{size}; \
5070
private:
51-
// we need to call the Sink<T>(int size) non-default constructor using size as parameter.
52-
// This is done by writing
53-
// Sink<type> name{size};
54-
// instead of:
55-
// Sink<type> name(size);
56-
// otherwise the compiler will read it as a declaration of a method called "name" and we
57-
// get a syntax error.
58-
// This is called "C++11 uniform init" (using "{}" instead of "()" without "="... yikes!)
59-
// https://chromium.googlesource.com/chromium/src/+/master/styleguide/c++/c++-dos-and-donts.md
71+
72+
/* Black C macro magic enabling "macro overloading"
73+
* with same name macro, but multiple arguments.
74+
* https://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
75+
*/
76+
#define GET_SINK_MACRO(_1,_2,_3,NAME,...) NAME
77+
#define SINK(...) GET_SINK_MACRO(__VA_ARGS__, SINK_3_ARG, SINK_2_ARG)(__VA_ARGS__)
6078

6179
#define SHARED(name, type) \
6280
Shared<type> name;

Diff for: src/threading/CircularBuffer.hpp

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* This file is part of the Arduino_ThreadsafeIO library.
3+
* Copyright (c) 2021 Arduino SA.
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2.1 of the License, or (at your option) any later version.
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+
*/
18+
19+
#ifndef ARDUINO_THREADS_RINGBUFFER_HPP_
20+
#define ARDUINO_THREADS_RINGBUFFER_HPP_
21+
22+
/**************************************************************************************
23+
* INCLUDE
24+
**************************************************************************************/
25+
26+
#include <SharedPtr.h>
27+
28+
/**************************************************************************************
29+
* CLASS DECLARATION
30+
**************************************************************************************/
31+
32+
template <typename T>
33+
class CircularBuffer
34+
{
35+
public:
36+
37+
CircularBuffer(size_t const size);
38+
39+
void store(T const data);
40+
T read();
41+
bool isFull() const;
42+
bool isEmpty() const;
43+
44+
45+
private:
46+
47+
mbed::SharedPtr<T> _data;
48+
size_t const _size;
49+
size_t _head, _tail, _num_elems;
50+
51+
size_t next(size_t const idx);
52+
};
53+
54+
/**************************************************************************************
55+
* CTOR/DTOR
56+
**************************************************************************************/
57+
58+
template <typename T>
59+
CircularBuffer<T>::CircularBuffer(size_t const size)
60+
: _data{new T[size]}
61+
, _size{size}
62+
, _head{0}
63+
, _tail{0}
64+
, _num_elems{0}
65+
{
66+
}
67+
68+
/**************************************************************************************
69+
* PUBLIC MEMBER FUNCTIONS
70+
**************************************************************************************/
71+
72+
template <typename T>
73+
void CircularBuffer<T>::store(T const data)
74+
{
75+
if (!isFull())
76+
{
77+
_data.get()[_head] = data;
78+
_head = next(_head);
79+
_num_elems++;
80+
}
81+
}
82+
83+
template <typename T>
84+
T CircularBuffer<T>::read()
85+
{
86+
if (isEmpty())
87+
return T{0};
88+
89+
T const value = _data.get()[_tail];
90+
_tail = next(_tail);
91+
_num_elems--;
92+
93+
return value;
94+
}
95+
96+
template <typename T>
97+
bool CircularBuffer<T>::isFull() const
98+
{
99+
return (_num_elems == _size);
100+
}
101+
102+
template <typename T>
103+
bool CircularBuffer<T>::isEmpty() const
104+
{
105+
return (_num_elems == 0);
106+
}
107+
108+
/**************************************************************************************
109+
* PRIVATE MEMBER FUNCTIONS
110+
**************************************************************************************/
111+
112+
template <typename T>
113+
size_t CircularBuffer<T>::next(size_t const idx)
114+
{
115+
return ((idx + 1) % _size);
116+
}
117+
118+
#endif /* ARDUINO_THREADS_RINGBUFFER_HPP_ */

Diff for: src/threading/Sink.hpp

+10-11
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#include <mbed.h>
2727

28+
#include "CircularBuffer.hpp"
29+
2830
/**************************************************************************************
2931
* CLASS DECLARATION
3032
**************************************************************************************/
@@ -64,7 +66,7 @@ class SinkBlocking : public SinkBase<T>
6466
{
6567
public:
6668

67-
SinkBlocking();
69+
SinkBlocking(size_t const size);
6870
virtual ~SinkBlocking() { }
6971

7072
virtual operator T() override;
@@ -73,8 +75,7 @@ class SinkBlocking : public SinkBase<T>
7375

7476
private:
7577

76-
T _data;
77-
bool _is_data_available;
78+
CircularBuffer<T> _data;
7879
rtos::Mutex _mutex;
7980
rtos::ConditionVariable _cond_data_available;
8081
rtos::ConditionVariable _cond_slot_available;
@@ -106,8 +107,8 @@ void SinkNonBlocking<T>::inject(T const & value)
106107
**************************************************************************************/
107108

108109
template<typename T>
109-
SinkBlocking<T>::SinkBlocking()
110-
: _is_data_available{false}
110+
SinkBlocking<T>::SinkBlocking(size_t const size)
111+
: _data(size)
111112
, _cond_data_available(_mutex)
112113
, _cond_slot_available(_mutex)
113114
{ }
@@ -116,10 +117,9 @@ template<typename T>
116117
SinkBlocking<T>::operator T()
117118
{
118119
_mutex.lock();
119-
while (!_is_data_available)
120+
while (_data.isEmpty())
120121
_cond_data_available.wait();
121-
T const d = _data;
122-
_is_data_available = false;
122+
T const d = _data.read();
123123
_cond_slot_available.notify_all();
124124
_mutex.unlock();
125125
return d;
@@ -129,10 +129,9 @@ template<typename T>
129129
void SinkBlocking<T>::inject(T const & value)
130130
{
131131
_mutex.lock();
132-
while (_is_data_available)
132+
while (_data.isFull())
133133
_cond_slot_available.wait();
134-
_data = value;
135-
_is_data_available = true;
134+
_data.store(value);
136135
_cond_data_available.notify_all();
137136
_mutex.unlock();
138137
}

0 commit comments

Comments
 (0)