Skip to content

Commit bef5368

Browse files
committed
add PacketBuffer .incoming_ and .outgoing_packet_length
1 parent b0383f4 commit bef5368

File tree

5 files changed

+143
-40
lines changed

5 files changed

+143
-40
lines changed

ports/nrf/common-hal/_bleio/PacketBuffer.c

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -281,21 +281,33 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self
281281
return ret;
282282
}
283283

284-
void common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len) {
284+
mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len) {
285285
if (self->outgoing[0] == NULL) {
286286
mp_raise_bleio_BluetoothError(translate("Writes not supported on Characteristic"));
287287
}
288288
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
289-
return;
289+
return -1;
290+
}
291+
uint16_t outgoing_packet_length = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self);
292+
293+
if (len + header_len > outgoing_packet_length) {
294+
// Supplied data will not fit in a single BLE packet.
295+
mp_raise_ValueError(translate("Total data to write is larger than outgoing_packet_length"));
290296
}
291-
uint16_t packet_size = common_hal_bleio_packet_buffer_get_packet_size(self);
292-
uint16_t max_size = packet_size - len;
293-
while (max_size < self->pending_size && self->conn_handle != BLE_CONN_HANDLE_INVALID) {
294-
RUN_BACKGROUND_TASKS;
297+
298+
if (len + self->pending_size > outgoing_packet_length) {
299+
// No room to append len bytes to packet. Wait until we get a free buffer,
300+
// and keep checking that we haven't been disconnected.
301+
while (self->pending_size != 0 && self->conn_handle != BLE_CONN_HANDLE_INVALID) {
302+
RUN_BACKGROUND_TASKS;
303+
}
295304
}
296305
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
297-
return;
306+
return -1;
298307
}
308+
309+
size_t num_bytes_written = 0;
310+
299311
uint8_t is_nested_critical_region;
300312
sd_nvic_critical_region_enter(&is_nested_critical_region);
301313

@@ -304,35 +316,44 @@ void common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8
304316
if (self->pending_size == 0) {
305317
memcpy(pending, header, header_len);
306318
self->pending_size += header_len;
319+
num_bytes_written += header_len;
307320
}
308321
memcpy(pending + self->pending_size, data, len);
309322
self->pending_size += len;
323+
num_bytes_written += len;
310324

311325
sd_nvic_critical_region_exit(is_nested_critical_region);
312326

313327
// If no writes are queued then sneak in this data.
314328
if (!self->packet_queued) {
315329
queue_next_write(self);
316330
}
331+
return num_bytes_written;
317332
}
318333

319-
mp_int_t common_hal_bleio_packet_buffer_get_packet_size(bleio_packet_buffer_obj_t *self) {
320-
// If this PacketBuffer is being used for NOTIFY or INDICATE,
334+
mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) {
335+
// If this PacketBuffer is coming from a remote service via NOTIFY or INDICATE
321336
// the maximum size is what can be sent in one
322337
// BLE packet. But we must be connected to know that value.
323338
//
324339
// Otherwise it can be as long as the characteristic
325340
// will permit, whether or not we're connected.
326341

327-
if (self->characteristic != NULL &&
328-
self->characteristic->service != NULL &&
342+
if (self->characteristic == NULL) {
343+
return -1;
344+
}
345+
346+
if (self->characteristic->service != NULL &&
347+
self->characteristic->service->is_remote &&
329348
(common_hal_bleio_characteristic_get_properties(self->characteristic) &
330-
(CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY)) &&
331-
self->conn_handle != BLE_CONN_HANDLE_INVALID) {
332-
bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle);
333-
if (connection) {
334-
return MIN(common_hal_bleio_connection_get_max_packet_length(connection),
335-
self->characteristic->max_length);
349+
(CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) {
350+
// We are talking to a remote service, and data is arriving via NOTIFY or INDICATE.
351+
if (self->conn_handle != BLE_CONN_HANDLE_INVALID) {
352+
bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle);
353+
if (connection) {
354+
return MIN(common_hal_bleio_connection_get_max_packet_length(connection),
355+
self->characteristic->max_length);
356+
}
336357
}
337358
// There's no current connection, so we don't know the MTU, and
338359
// we can't tell what the largest incoming packet length would be.
@@ -341,6 +362,37 @@ mp_int_t common_hal_bleio_packet_buffer_get_packet_size(bleio_packet_buffer_obj_
341362
return self->characteristic->max_length;
342363
}
343364

365+
mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) {
366+
// If we are sending data via NOTIFY or INDICATE, the maximum size
367+
// is what can be sent in one BLE packet. But we must be connected
368+
// to know that value.
369+
//
370+
// Otherwise it can be as long as the characteristic
371+
// will permit, whether or not we're connected.
372+
373+
if (self->characteristic == NULL) {
374+
return -1;
375+
}
376+
377+
if (self->characteristic->service != NULL &&
378+
!self->characteristic->service->is_remote &&
379+
(common_hal_bleio_characteristic_get_properties(self->characteristic) &
380+
(CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) {
381+
// We are sending to a client, via NOTIFY or INDICATE.
382+
if (self->conn_handle != BLE_CONN_HANDLE_INVALID) {
383+
bleio_connection_internal_t *connection = bleio_conn_handle_to_connection(self->conn_handle);
384+
if (connection) {
385+
return MIN(common_hal_bleio_connection_get_max_packet_length(connection),
386+
self->characteristic->max_length);
387+
}
388+
}
389+
// There's no current connection, so we don't know the MTU, and
390+
// we can't tell what the largest outgoing packet length would be.
391+
return -1;
392+
}
393+
return self->characteristic->max_length;
394+
}
395+
344396
bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) {
345397
return self->characteristic == NULL;
346398
}

ports/nrf/common-hal/_bleio/PacketBuffer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ typedef struct {
4040
// Two outgoing buffers to alternate between. One will be queued for transmission by the SD and
4141
// the other is waiting to be queued and can be extended.
4242
uint8_t* outgoing[2];
43-
uint16_t pending_size;
43+
volatile uint16_t pending_size;
4444
// We remember the conn_handle so we can do a NOTIFY/INDICATE to a client.
4545
// We can find out the conn_handle on a Characteristic write or a CCCD write (but not a read).
46-
uint16_t conn_handle;
46+
volatile uint16_t conn_handle;
4747
uint8_t pending_index;
4848
uint8_t write_type;
4949
bool client;

ports/nrf/common-hal/_bleio/__init__.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ void common_hal_bleio_check_connected(uint16_t conn_handle) {
119119
// GATTS read of a Characteristic or Descriptor.
120120
size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len) {
121121
// conn_handle is ignored unless this is a system attribute.
122-
// If we're not connected, but that's OK, because we can still read and write the local value.
122+
// If we're not connected, that's OK, because we can still read and write the local value.
123123

124124
ble_gatts_value_t gatts_value = {
125125
.p_value = buf,
@@ -133,7 +133,7 @@ size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_
133133

134134
void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) {
135135
// conn_handle is ignored unless this is a system attribute.
136-
// If we're not connected, but that's OK, because we can still read and write the local value.
136+
// If we're not connected, that's OK, because we can still read and write the local value.
137137

138138
ble_gatts_value_t gatts_value = {
139139
.p_value = bufinfo->buf,

shared-bindings/_bleio/PacketBuffer.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@
4242
//|
4343
//| Accumulates a Characteristic's incoming packets in a FIFO buffer and facilitates packet aware
4444
//| outgoing writes. A packet's size is either the characteristic length or the maximum transmission
45-
//| unit (MTU), whichever is smaller. The MTU can change so check `packet_size` before creating a
46-
//| buffer to store data.
45+
//| unit (MTU) minus overhead, whichever is smaller. The MTU can change so check `incoming_packet_length`
46+
//| and `outgoing_packet_length` before creating a buffer to store data.
4747
//|
4848
//| When we're the server, we ignore all connections besides the first to subscribe to
4949
//| notifications.
5050
//|
5151
//| .. class:: PacketBuffer(characteristic, *, buffer_size)
5252
//|
5353
//| Monitor the given Characteristic. Each time a new value is written to the Characteristic
54-
//| add the newly-written bytes to a FIFO buffer.
54+
//| add the newly-written packet of bytes to a FIFO buffer.
5555
//|
5656
//| :param Characteristic characteristic: The Characteristic to monitor.
5757
//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic
@@ -125,6 +125,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_packet_buffer_readinto_obj, bleio_packet_
125125
//|
126126
//| This does not block until the data is sent. It only blocks until the data is pending.
127127
//|
128+
//| :return: number of bytes written. May include header bytes when packet is empty.
129+
//| :rtype: int
130+
//|
128131
// TODO: Add a kwarg `merge=False` to dictate whether subsequent writes are merged into a pending
129132
// one.
130133
STATIC mp_obj_t bleio_packet_buffer_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@@ -149,9 +152,21 @@ STATIC mp_obj_t bleio_packet_buffer_write(mp_uint_t n_args, const mp_obj_t *pos_
149152
mp_get_buffer_raise(args[ARG_header].u_obj, &header_bufinfo, MP_BUFFER_READ);
150153
}
151154

152-
common_hal_bleio_packet_buffer_write(self, data_bufinfo.buf, data_bufinfo.len,
153-
header_bufinfo.buf, header_bufinfo.len);
154-
return mp_const_none;
155+
mp_int_t num_bytes_written = common_hal_bleio_packet_buffer_write(
156+
self, data_bufinfo.buf, data_bufinfo.len, header_bufinfo.buf, header_bufinfo.len);
157+
if (num_bytes_written < 0) {
158+
// TODO: Raise an error if not connected. Right now the not-connected error
159+
// is unreliable, because common_hal_bleio_packet_buffer_write()
160+
// checks for conn_handle being set, but setting that
161+
// can be delayed because conn_handle is discovered by spying on
162+
// gatts write events, which may not have been sent yet.
163+
//
164+
// IDEAL:
165+
// mp_raise_bleio_ConnectionError(translate("Not connected"));
166+
// TEMPORARY:
167+
num_bytes_written = 0;
168+
}
169+
return MP_OBJ_NEW_SMALL_INT(num_bytes_written);
155170
}
156171
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_packet_buffer_write_obj, 1, bleio_packet_buffer_write);
157172

@@ -168,37 +183,72 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_deinit_obj, bleio_packet_bu
168183

169184
//| .. attribute:: packet_size
170185
//|
171-
//| Maximum size of a packet.
186+
//| `packet_size` is the same as `incoming_packet_length`.
187+
//| The name `packet_size` is deprecated and
188+
//| will be removed in CircuitPython 6.0.0.
189+
//|
190+
//| .. attribute:: incoming_packet_length
191+
//|
192+
//| Maximum length in bytes of a packet we are reading.
172193
//| If the packet is arriving from a remote service via notify or indicate,
173-
//| the maximum size is `Connection.max_packet_length`.
194+
//| the maximum length is `Connection.max_packet_length`.
195+
//| Otherwise it is the ``max_length`` of the :py:class:`~_bleio.Characteristic`.
196+
//|
197+
STATIC mp_obj_t bleio_packet_buffer_get_incoming_packet_length(mp_obj_t self_in) {
198+
bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
199+
200+
mp_int_t size = common_hal_bleio_packet_buffer_get_incoming_packet_length(self);
201+
if (size < 0) {
202+
mp_raise_ValueError(translate("No connection: size cannot be determined"));
203+
}
204+
return MP_OBJ_NEW_SMALL_INT(size);
205+
}
206+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_get_incoming_packet_length_obj, bleio_packet_buffer_get_incoming_packet_length);
207+
208+
const mp_obj_property_t bleio_packet_buffer_incoming_packet_length_obj = {
209+
.base.type = &mp_type_property,
210+
.proxy = { (mp_obj_t)&bleio_packet_buffer_get_incoming_packet_length_obj,
211+
(mp_obj_t)&mp_const_none_obj,
212+
(mp_obj_t)&mp_const_none_obj },
213+
};
214+
215+
//| .. attribute:: outgoing_packet_length
216+
//|
217+
//| Maximum length in bytes of a packet we are writing.
218+
//| If the packet is being sent via notify or indicate,
219+
//| the maximum length is `Connection.max_packet_length`.
174220
//| Otherwise it is the ``max_length`` of the :py:class:`~_bleio.Characteristic`.
175221
//|
176-
STATIC mp_obj_t bleio_packet_buffer_get_packet_size(mp_obj_t self_in) {
222+
STATIC mp_obj_t bleio_packet_buffer_get_outgoing_packet_length(mp_obj_t self_in) {
177223
bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
178224

179-
mp_int_t size = common_hal_bleio_packet_buffer_get_packet_size(self);
225+
mp_int_t size = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self);
180226
if (size < 0) {
181227
mp_raise_ValueError(translate("No connection: size cannot be determined"));
182228
}
183229
return MP_OBJ_NEW_SMALL_INT(size);
184230
}
185-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_get_packet_size_obj, bleio_packet_buffer_get_packet_size);
231+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_get_outgoing_packet_length_obj, bleio_packet_buffer_get_outgoing_packet_length);
186232

187-
const mp_obj_property_t bleio_packet_buffer_packet_size_obj = {
233+
const mp_obj_property_t bleio_packet_buffer_outgoing_packet_length_obj = {
188234
.base.type = &mp_type_property,
189-
.proxy = { (mp_obj_t)&bleio_packet_buffer_get_packet_size_obj,
235+
.proxy = { (mp_obj_t)&bleio_packet_buffer_get_outgoing_packet_length_obj,
190236
(mp_obj_t)&mp_const_none_obj,
191237
(mp_obj_t)&mp_const_none_obj },
192238
};
193239

194240
STATIC const mp_rom_map_elem_t bleio_packet_buffer_locals_dict_table[] = {
195-
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_packet_buffer_deinit_obj) },
241+
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_packet_buffer_deinit_obj) },
196242

197243
// Standard stream methods.
198-
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bleio_packet_buffer_readinto_obj) },
199-
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&bleio_packet_buffer_write_obj) },
244+
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bleio_packet_buffer_readinto_obj) },
245+
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&bleio_packet_buffer_write_obj) },
200246

201-
{ MP_OBJ_NEW_QSTR(MP_QSTR_packet_size), MP_ROM_PTR(&bleio_packet_buffer_packet_size_obj) },
247+
// .packet_size is now an alias for .incoming_packet_length
248+
// TODO: It will be removed in 6.0.0.
249+
{ MP_OBJ_NEW_QSTR(MP_QSTR_packet_size), MP_ROM_PTR(&bleio_packet_buffer_incoming_packet_length_obj) },
250+
{ MP_OBJ_NEW_QSTR(MP_QSTR_incoming_packet_length), MP_ROM_PTR(&bleio_packet_buffer_incoming_packet_length_obj) },
251+
{ MP_OBJ_NEW_QSTR(MP_QSTR_outgoing_packet_length), MP_ROM_PTR(&bleio_packet_buffer_outgoing_packet_length_obj) },
202252
};
203253

204254
STATIC MP_DEFINE_CONST_DICT(bleio_packet_buffer_locals_dict, bleio_packet_buffer_locals_dict_table);

shared-bindings/_bleio/PacketBuffer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ extern const mp_obj_type_t bleio_packet_buffer_type;
3434
extern void common_hal_bleio_packet_buffer_construct(
3535
bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic,
3636
size_t buffer_size);
37-
void common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len);
37+
mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len, uint8_t* header, size_t header_len);
3838
mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len);
39-
mp_int_t common_hal_bleio_packet_buffer_get_packet_size(bleio_packet_buffer_obj_t *self);
39+
mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self);
40+
mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self);
4041
bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self);
4142
void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self);
4243

0 commit comments

Comments
 (0)