Control Surface
main
MIDI Control Surface library for Arduino
Toggle main menu visibility
Loading...
Searching...
No Matches
src
MIDI_Interfaces
BLEMIDI
BLERingBuf.hpp
Go to the documentation of this file.
1
#pragma once
2
3
#include <cstdint>
4
#include <cstring>
5
6
#include <
Settings/NamespaceSettings.hpp
>
7
8
#include <
MIDI_Interfaces/BLEMIDI/BLEAPI.hpp
>
9
10
BEGIN_CS_NAMESPACE
11
12
template
<
class
T>
13
struct
NonatomicBLERingBufSize
{
14
T
value
;
16
constexpr
static
size_t
alignment
=
alignof
(T);
17
T
load_acquire
()
const
{
return
value
; }
18
void
add_release
(T t) {
value
+= t; }
19
void
sub_release
(T t) {
value
-= t; }
20
};
21
32
template
<uint_fast16_t Capacity,
33
class
SizeT =
NonatomicBLERingBufSize<uint_fast16_t>
>
34
class
BLERingBuf
{
35
private
:
36
struct
Header
{
37
uint16_t
size
: 14;
38
uint8_t
type
: 2;
39
Header
() =
default
;
40
Header
(uint16_t
size
,
BLEDataType
type
)
41
:
size
{
size
},
type
{static_cast<uint8_t>(
type
)} {}
42
BLEDataType
getType
()
const
{
return
static_cast<
BLEDataType
>
(
type
); }
43
};
44
constexpr
static
uint_fast16_t
header_size
=
sizeof
(
Header
);
45
static_assert
(
header_size
== 2,
""
);
46
47
constexpr
static
uint_fast16_t
capacity
= Capacity;
48
unsigned
char
buffer
[
capacity
];
49
alignas
(SizeT::alignment) uint_fast16_t
read_p
= 0;
50
alignas
(SizeT::alignment) uint_fast16_t
write_p
=
header_size
;
51
alignas
(SizeT::alignment) SizeT
size
{
header_size
};
52
53
constexpr
static
uint_fast16_t
ceil_h
(uint_fast16_t i) {
54
return
((i +
header_size
- 1) /
header_size
) *
header_size
;
55
}
56
57
public
:
58
BLERingBuf
() {
59
Header
header {0,
BLEDataType::None
};
60
static_assert
(
capacity
%
header_size
== 0,
""
);
61
std::memcpy(
buffer
, &header,
header_size
);
62
}
63
68
bool
push
(
BLEDataView
data,
BLEDataType
type =
BLEDataType::Packet
) {
69
if
(type ==
BLEDataType::None
)
70
return
false
;
71
uint_fast16_t loc_size =
size
.load_acquire();
72
uint_fast16_t add_size = 0;
73
assert(loc_size <=
capacity
);
74
assert(
write_p
<
capacity
);
75
assert(
write_p
%
header_size
== 0);
76
// We need to write at least one header
77
uint_fast16_t expected_req_size = loc_size + data.
length
+
header_size
;
78
if
(expected_req_size >
capacity
)
79
return
false
;
// not enough space
80
// Contiguous size remaining (excluding header)
81
uint_fast16_t contig_size =
capacity
-
write_p
-
header_size
;
82
assert(contig_size <
capacity
);
83
// We may need to write a second header
84
uint_fast16_t worst_case_req_size = expected_req_size +
header_size
;
85
if
(data.
length
> contig_size && worst_case_req_size >
capacity
)
86
return
false
;
// not enough space
87
// Write the first header for the packet
88
uint16_t size_1 = std::min<uint_fast16_t>(contig_size, data.
length
);
89
Header
header {size_1, type};
90
std::memcpy(
buffer
+
write_p
, &header,
sizeof
(header));
91
write_p
+=
header_size
;
92
add_size +=
header_size
;
93
// Write first data
94
if
(size_1 > 0)
// avoid memcpy with nullptr
95
std::memcpy(
buffer
+
write_p
, data.
data
, size_1);
96
write_p
+=
ceil_h
(size_1);
97
add_size +=
ceil_h
(size_1);
98
if
(
write_p
==
capacity
)
99
write_p
= 0;
100
// Now write the remainder at the beginning of the circular buffer
101
uint16_t size_2 = data.
length
- size_1;
102
if
(size_2 > 0) {
103
// Write the continuation header
104
Header
header {size_2,
BLEDataType::Continuation
};
105
std::memcpy(
buffer
+
write_p
, &header,
sizeof
(header));
106
write_p
+=
header_size
;
107
add_size +=
header_size
;
108
// Write the remainder of the data
109
std::memcpy(
buffer
+
write_p
, data.
data
+ size_1, size_2);
110
write_p
+=
ceil_h
(size_2);
111
add_size +=
ceil_h
(size_2);
112
}
113
size
.add_release(add_size);
114
return
true
;
115
}
116
127
BLEDataType
pop
(
BLEDataView
&data) {
128
uint_fast16_t loc_size =
size
.load_acquire();
129
assert(loc_size >=
header_size
);
130
assert(
read_p
<
capacity
);
131
assert(
read_p
%
header_size
== 0);
132
// Read the old header
133
Header
old_header;
134
std::memcpy(&old_header,
buffer
+
read_p
,
sizeof
(old_header));
135
// If the previous chunk is the only thing left in the buffer
136
if
(loc_size -
header_size
==
ceil_h
(old_header.
size
)) {
137
// If there is still actual data left in the buffer
138
if
(old_header.
getType
() !=
BLEDataType::None
) {
139
// Free the old data, preserving space for a header
140
read_p
+=
ceil_h
(old_header.
size
);
141
size
.sub_release(
ceil_h
(old_header.
size
));
142
// Write an empty header
143
Header
header {0,
BLEDataType::None
};
144
std::memcpy(
buffer
+
read_p
, &header,
sizeof
(header));
145
}
146
data = {
nullptr
, 0};
147
return
BLEDataType::None
;
148
}
else
{
149
// Otherwise, discard the old data and header
150
read_p
+=
header_size
+
ceil_h
(old_header.
size
);
151
size
.sub_release(
header_size
+
ceil_h
(old_header.
size
));
152
if
(
read_p
==
capacity
)
153
read_p
= 0;
154
// Read the next header
155
Header
header;
156
std::memcpy(&header,
buffer
+
read_p
,
sizeof
(header));
157
data = {
buffer
+
read_p
+
header_size
, header.
size
};
158
return
header.
getType
();
159
}
160
}
161
};
162
163
END_CS_NAMESPACE
BLEAPI.hpp
Type definitions and callback interfaces for communication between the low-level BLE stacks and highe...
BLEDataType
BLEDataType
Describes a byte buffer containing (part of) a BLE packet.
Definition
BLEAPI.hpp:58
BLEDataType::None
@ None
No buffers available.
Definition
BLEAPI.hpp:59
BLEDataType::Continuation
@ Continuation
Buffer contains a chunk of a BLE packet.
Definition
BLEAPI.hpp:61
BLEDataType::Packet
@ Packet
Buffer contains the start of a BLE packet.
Definition
BLEAPI.hpp:60
NamespaceSettings.hpp
END_CS_NAMESPACE
#define END_CS_NAMESPACE
Definition
Settings/NamespaceSettings.hpp:14
BEGIN_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Definition
Settings/NamespaceSettings.hpp:11
BLERingBuf::ceil_h
static constexpr uint_fast16_t ceil_h(uint_fast16_t i)
Definition
BLERingBuf.hpp:53
BLERingBuf::buffer
unsigned char buffer[capacity]
Definition
BLERingBuf.hpp:48
BLERingBuf::pop
BLEDataType pop(BLEDataView &data)
Get a view to the next chunk of data.
Definition
BLERingBuf.hpp:127
BLERingBuf::push
bool push(BLEDataView data, BLEDataType type=BLEDataType::Packet)
Copy the given data into the buffer.
Definition
BLERingBuf.hpp:68
BLERingBuf::BLERingBuf
BLERingBuf()
Definition
BLERingBuf.hpp:58
BLERingBuf::read_p
uint_fast16_t read_p
Definition
BLERingBuf.hpp:49
BLERingBuf::header_size
static constexpr uint_fast16_t header_size
Definition
BLERingBuf.hpp:44
BLERingBuf::size
SizeT size
Definition
BLERingBuf.hpp:51
BLERingBuf::write_p
uint_fast16_t write_p
Definition
BLERingBuf.hpp:50
BLERingBuf::capacity
static constexpr uint_fast16_t capacity
Definition
BLERingBuf.hpp:47
BLEDataView
Non-owning, std::span-style read-only view of BLE data.
Definition
BLEAPI.hpp:42
BLEDataView::length
uint16_t length
Definition
BLEAPI.hpp:44
BLEDataView::data
const uint8_t * data
Definition
BLEAPI.hpp:43
BLERingBuf::Header
Definition
BLERingBuf.hpp:36
BLERingBuf::Header::type
uint8_t type
Definition
BLERingBuf.hpp:38
BLERingBuf::Header::Header
Header()=default
BLERingBuf::Header::getType
BLEDataType getType() const
Definition
BLERingBuf.hpp:42
BLERingBuf::Header::size
uint16_t size
Definition
BLERingBuf.hpp:37
BLERingBuf::Header::Header
Header(uint16_t size, BLEDataType type)
Definition
BLERingBuf.hpp:40
NonatomicBLERingBufSize
Definition
BLERingBuf.hpp:13
NonatomicBLERingBufSize::value
T value
Definition
BLERingBuf.hpp:14
NonatomicBLERingBufSize::sub_release
void sub_release(T t)
Definition
BLERingBuf.hpp:19
NonatomicBLERingBufSize::load_acquire
T load_acquire() const
Definition
BLERingBuf.hpp:17
NonatomicBLERingBufSize::add_release
void add_release(T t)
Definition
BLERingBuf.hpp:18
NonatomicBLERingBufSize::alignment
static constexpr size_t alignment
Alignment for size, and read/write pointers to avoid false sharing.
Definition
BLERingBuf.hpp:16
Generated by
1.17.0