Skip to content

Commit 1dea124

Browse files
committed
Add circular byte buffer using dynamic memory
Add the ByteBuffer class which is similar to the CircularBuffer class but uses dynamic memory rather than template parameters and is optimized for byte transfers. This is required for USBAudio which needs a high performance circular buffer which can be resized at runtime.
1 parent c18f2fc commit 1dea124

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed

usb/device/utilities/ByteBuffer.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "ByteBuffer.h"
18+
#include "mbed_assert.h"
19+
#include <string.h>
20+
21+
ByteBuffer::ByteBuffer(uint32_t size): _head(0), _tail(0), _size(0), _buf(NULL)
22+
{
23+
resize(_size);
24+
}
25+
26+
ByteBuffer::~ByteBuffer()
27+
{
28+
delete[] _buf;
29+
_buf = 0;
30+
}
31+
32+
void ByteBuffer::resize(uint32_t size)
33+
{
34+
delete[] _buf;
35+
_head = 0;
36+
_tail = 0;
37+
_size = size + 1;
38+
_buf = new uint8_t[_size]();
39+
}
40+
41+
void ByteBuffer::push(uint8_t data)
42+
{
43+
_buf[_tail] = data;
44+
_tail++;
45+
if (_tail >= _size) {
46+
_tail -= _size;
47+
}
48+
// Overflow not allowed
49+
MBED_ASSERT(_head != _tail);
50+
}
51+
52+
void ByteBuffer::write(uint8_t *data, uint32_t size)
53+
{
54+
MBED_ASSERT(size <= free());
55+
56+
if (size == 0) {
57+
return;
58+
}
59+
60+
uint32_t new_tail = _tail + size;
61+
if (new_tail >= _size) {
62+
new_tail -= _size;
63+
}
64+
65+
// Perform first memcpy
66+
uint32_t until_end = _size - _tail;
67+
uint32_t copy_size = until_end < size ? until_end : size;
68+
memcpy(_buf + _tail, data, copy_size);
69+
data += copy_size;
70+
size -= copy_size;
71+
72+
// Perform second memcpy
73+
if (size > 0) {
74+
memcpy(_buf, data, size);
75+
}
76+
77+
// Update tail
78+
_tail = new_tail;
79+
}
80+
81+
uint8_t ByteBuffer::pop()
82+
{
83+
// Underflow not allowed
84+
MBED_ASSERT(_head != _tail);
85+
uint8_t val = _buf[_head];
86+
_head++;
87+
if (_head >= _size) {
88+
_head -= _size;
89+
}
90+
return val;
91+
}
92+
93+
void ByteBuffer::read(uint8_t *data, uint32_t size)
94+
{
95+
MBED_ASSERT(size <= ByteBuffer::size());
96+
97+
if (size == 0) {
98+
return;
99+
}
100+
101+
uint32_t new_head = _head + size;
102+
if (new_head >= _size) {
103+
new_head -= _size;
104+
}
105+
106+
// Perform first memcpy
107+
uint32_t until_end = _size - _head;
108+
uint32_t copy_size = until_end < size ? until_end : size;
109+
memcpy(data, _buf + _head, copy_size);
110+
data += copy_size;
111+
size -= copy_size;
112+
113+
// Perform second memcpy
114+
if (size > 0) {
115+
memcpy(data, _buf, size);
116+
}
117+
118+
// Update head
119+
_head = new_head;
120+
}
121+
122+
uint32_t ByteBuffer::size()
123+
{
124+
uint32_t size;
125+
if (_tail < _head) {
126+
size = _size + _tail - _head;
127+
} else {
128+
size = _tail - _head;
129+
}
130+
return size;
131+
}
132+
133+
uint32_t ByteBuffer::free()
134+
{
135+
return _size - size() - 1;
136+
}
137+
138+
bool ByteBuffer::full()
139+
{
140+
uint32_t next = _tail + 1;
141+
if (next >= _size) {
142+
next -= _size;
143+
}
144+
return next == _head;
145+
}
146+
147+
bool ByteBuffer::empty()
148+
{
149+
return _head == _tail;
150+
}
151+

usb/device/utilities/ByteBuffer.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2018-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef BYTE_BUFFER_H
18+
#define BYTE_BUFFER_H
19+
20+
#include <stdint.h>
21+
22+
class ByteBuffer {
23+
public:
24+
25+
/**
26+
* Create a byte buffer of the given size
27+
*
28+
* @param size Number of bytes this buffer can hold
29+
*/
30+
ByteBuffer(uint32_t size=0);
31+
32+
/**
33+
* Delete this byte buffer
34+
*/
35+
~ByteBuffer();
36+
37+
/**
38+
* Set the size of the buffer
39+
*
40+
* Buffer contents are reset.
41+
*
42+
* @param size New buffer size
43+
*/
44+
void resize(uint32_t size);
45+
46+
/**
47+
* Add a single byte to this buffer
48+
*
49+
* There must be enough space in the buffer or the behavior is undefined.
50+
*
51+
* @param data byte to add
52+
*/
53+
void push(uint8_t data);
54+
55+
/**
56+
* Write a block of data to this ByteBuffer
57+
*
58+
* There must be enough space in the ByteBuffer or the behavior is undefined.
59+
*
60+
* @param data Block of data to write
61+
* @param size Size of data to write
62+
*/
63+
void write(uint8_t *data, uint32_t size);
64+
65+
/**
66+
* Remove a byte from this buffer
67+
*
68+
* @return data byte
69+
*/
70+
uint8_t pop();
71+
72+
/**
73+
* Read a block of data from this ByteBuffer into a buffer pointed by 'data'
74+
*
75+
* There must be enough data in the ByteBuffer or the behavior is undefined.
76+
*
77+
* @param data Block of data to read
78+
* @param size Size of data to read
79+
*/
80+
void read(uint8_t *data, uint32_t size);
81+
82+
/**
83+
* Return the number bytes in this byte buffer
84+
*
85+
* @return Number of used bytes
86+
*/
87+
uint32_t size();
88+
89+
/**
90+
* Return the number of additional bytes this buffer can hold
91+
*
92+
* @return Number of free bytes
93+
*/
94+
uint32_t free();
95+
96+
/**
97+
* Check if this byte buffer is full
98+
*
99+
* @return true if full, false otherwise
100+
*/
101+
bool full();
102+
103+
/**
104+
* Check if this byte buffer is empty
105+
*
106+
* @return true if empty, false otherwise
107+
*/
108+
bool empty();
109+
110+
private:
111+
112+
uint32_t _head;
113+
uint32_t _tail;
114+
uint32_t _size;
115+
uint8_t *_buf;
116+
};
117+
118+
119+
#endif

0 commit comments

Comments
 (0)