BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
write_queue.hpp
1#ifndef BLUETOE_WRITE_QUEUE_HPP
2#define BLUETOE_WRITE_QUEUE_HPP
3
4#include <cstdint>
5#include <cstddef>
6#include <cassert>
7#include <utility>
8#include <bluetoe/meta_types.hpp>
9
10namespace bluetoe {
11
12 namespace details {
13 struct write_queue_meta_type {};
14 }
15
47 template < std::uint16_t S >
50 struct meta_type :
51 details::write_queue_meta_type,
52 details::valid_server_option_meta_type {};
53
54 static constexpr std::uint16_t queue_size = S;
56 };
57
58namespace details {
59
60 /*
61 * Interface to access a write queue. All member named are some kind of prefixed with 'write_queue', because this type will be fixed into the server
62 */
63 template < typename QueueParameter >
64 class write_queue;
65
66 template < std::uint16_t S >
67 class write_queue< shared_write_queue< S > >
68 {
69 public:
70 write_queue();
71
72 /*
73 * Allocate n bytes for the given client. Returns 0 if it was not possible to allocate out of the queue.
74 * If successful, the function returns the start of an n byte size array.
75 */
76 template < typename ConData >
77 std::uint8_t* allocate_from_write_queue( std::size_t n, ConData& client );
78
79 /*
80 * Deallocates all elements allocated by the given client
81 */
82 template < typename ConData >
83 void free_write_queue( ConData& client );
84
85 /*
86 * return the first element of the queue for the given client. If no element was allocated, the function returns nullptr.
87 */
88 template < typename ConData >
89 std::pair< std::uint8_t*, std::size_t > first_write_queue_element( ConData& client );
90
91 /*
92 * Returns the next element in the queue to current. current must not be nullptr and must be obtained by a call to
93 * first_element() or next_element()
94 */
95 template < typename ConData >
96 std::pair< std::uint8_t*, std::size_t > next_write_queue_element( std::uint8_t* current, ConData& );
97 private:
98
99 std::size_t read_size( std::uint8_t* ) const;
100
101 void* current_client_;
102 std::uint8_t buffer_[ S ];
103 std::uint16_t buffer_end_;
104 };
105
106 struct no_such_type;
107
108 template <>
109 class write_queue< no_such_type >
110 {
111 public:
112 template < typename ConData >
113 void free_write_queue( ConData& ) {}
114 };
115
116 /*
117 * guard to make sure, that free_write_queue is called when this guard goes out of scope
118 */
119 template < typename ConData, typename WriteQueue >
120 class write_queue_guard
121 {
122 public:
123 write_queue_guard( ConData& client, WriteQueue& queue );
124 ~write_queue_guard();
125
126 private:
127 write_queue_guard( const write_queue_guard& ) = delete;
128 write_queue_guard& operator=( const write_queue_guard& ) = delete;
129
130 ConData& client_;
131 WriteQueue& queue_;
132 };
133
134 // implementation
135 template < std::uint16_t S >
136 write_queue< shared_write_queue< S > >::write_queue()
137 : current_client_( nullptr )
138 , buffer_end_( 0 )
139 {
140 }
141
142 template < std::uint16_t S >
143 template < typename ConData >
144 std::uint8_t* write_queue< shared_write_queue< S > >::allocate_from_write_queue( std::size_t size, ConData& client )
145 {
146 assert( size );
147
148 if ( size + 2 > static_cast< std::size_t >( S - buffer_end_ ) || ( current_client_ != nullptr && current_client_ != &client ) )
149 return nullptr;
150
151 buffer_[ buffer_end_ ] = size & 0xff;
152 buffer_[ buffer_end_ + 1 ] = size >> 8;
153
154 current_client_ = &client;
155 buffer_end_ += size + 2;
156
157 return &buffer_[ buffer_end_ - size ];
158 }
159
160 template < std::uint16_t S >
161 template < typename ConData >
162 void write_queue< shared_write_queue< S > >::free_write_queue( ConData& client )
163 {
164 if( current_client_ == &client )
165 {
166 buffer_end_ = 0;
167 current_client_ = nullptr;
168 }
169 }
170
171 template < std::uint16_t S >
172 template < typename ConData >
173 std::pair< std::uint8_t*, std::size_t > write_queue< shared_write_queue< S > >::first_write_queue_element( ConData& client )
174 {
175 if( current_client_ != &client || buffer_end_ == 0 )
176 {
177 return std::make_pair( nullptr, 0 );
178 }
179
180 return std::make_pair( &buffer_[ 2 ], read_size( &buffer_[ 2 ] ) );
181 }
182
183 template < std::uint16_t S >
184 template < typename ConData >
185 std::pair< std::uint8_t*, std::size_t > write_queue< shared_write_queue< S > >::next_write_queue_element( std::uint8_t* last, ConData& client )
186 {
187 assert( last );
188 assert( last >= &buffer_[ 2 ] );
189 assert( last <= &buffer_[ S ] );
190 assert( &client == current_client_ );
191 static_cast< void >( client );
192
193 const std::size_t size = read_size( last );
194
195 // lets point last to the next size value
196 last += size;
197
198 return last == &buffer_[ buffer_end_ ]
199 ? std::make_pair( nullptr, 0 )
200 : std::make_pair( last + 2, read_size( last + 2 ) );
201 }
202
203 template < std::uint16_t S >
204 std::size_t write_queue< shared_write_queue< S > >::read_size( std::uint8_t* last ) const
205 {
206 return *( last - 2 ) + *( last - 1 ) * 256;
207 }
208
209 template < typename ConData, typename WriteQueue >
210 write_queue_guard< ConData, WriteQueue >::write_queue_guard( ConData& client, WriteQueue& queue )
211 : client_( client )
212 , queue_( queue )
213 {
214 }
215
216 template < typename ConData, typename WriteQueue >
217 write_queue_guard< ConData, WriteQueue >::~write_queue_guard()
218 {
219 queue_.free_write_queue( client_ );
220 }
221
222}
223}
224#endif
defines a write queue size that is shared among all connected clients
Definition: write_queue.hpp:48