77#include <string.h>
88
99#include "py/runtime.h"
10+ #include "shared/runtime/interrupt_char.h"
1011
1112#include "shared-bindings/_bleio/__init__.h"
1213#include "shared-bindings/_bleio/Characteristic.h"
1314#include "shared-bindings/_bleio/CharacteristicBuffer.h"
1415#include "shared-bindings/_bleio/Descriptor.h"
1516#include "shared-bindings/_bleio/PacketBuffer.h"
1617#include "shared-bindings/_bleio/Service.h"
18+ #include "shared-bindings/time/__init__.h"
1719
1820#include "common-hal/_bleio/Adapter.h"
1921#include "common-hal/_bleio/Service.h"
2022
21-
2223static int characteristic_on_ble_gap_evt (struct ble_gap_event * event , void * param );
2324
25+ static volatile int _completion_status ;
26+ static uint64_t _timeout_start_time ;
27+
28+ static void _reset_completion_status (void ) {
29+ _completion_status = 0 ;
30+ }
31+
32+ // Wait for a status change, recorded in a callback.
33+ // Try twice because sometimes we get a BLE_HS_EAGAIN.
34+ // Maybe we should try more than twice.
35+ static int _wait_for_completion (uint32_t timeout_msecs ) {
36+ for (int tries = 1 ; tries <= 2 ; tries ++ ) {
37+ _timeout_start_time = common_hal_time_monotonic_ms ();
38+ while ((_completion_status == 0 ) &&
39+ (common_hal_time_monotonic_ms () < _timeout_start_time + timeout_msecs ) &&
40+ !mp_hal_is_interrupted ()) {
41+ RUN_BACKGROUND_TASKS ;
42+ }
43+ if (_completion_status != BLE_HS_EAGAIN ) {
44+ // Quit, because either the status is either zero (OK) or it's an error.
45+ break ;
46+ }
47+ }
48+ return _completion_status ;
49+ }
50+
2451void common_hal_bleio_characteristic_construct (bleio_characteristic_obj_t * self , bleio_service_obj_t * service ,
2552 uint16_t handle , bleio_uuid_obj_t * uuid , bleio_characteristic_properties_t props ,
2653 bleio_attribute_security_mode_t read_perm , bleio_attribute_security_mode_t write_perm ,
@@ -34,7 +61,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self,
3461 self -> props = props ;
3562 self -> read_perm = read_perm ;
3663 self -> write_perm = write_perm ;
37- self -> observer = NULL ;
64+ self -> observer = mp_const_none ;
3865
3966 // Map CP's property values to Nimble's flag values.
4067 self -> flags = 0 ;
@@ -125,7 +152,6 @@ bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_character
125152}
126153
127154typedef struct {
128- TaskHandle_t task ;
129155 uint8_t * buf ;
130156 uint16_t len ;
131157} _read_info_t ;
@@ -148,9 +174,9 @@ static int _read_cb(uint16_t conn_handle,
148174 // For debugging.
149175 mp_printf (& mp_plat_print , "Read status: %d\n" , error -> status );
150176 #endif
151- xTaskNotify (read_info -> task , error -> status , eSetValueWithOverwrite );
152177 break ;
153178 }
179+ _completion_status = error -> status ;
154180
155181 return 0 ;
156182}
@@ -163,14 +189,12 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel
163189 uint16_t conn_handle = bleio_connection_get_conn_handle (self -> service -> connection );
164190 if (common_hal_bleio_service_get_is_remote (self -> service )) {
165191 _read_info_t read_info = {
166- .task = xTaskGetCurrentTaskHandle (),
167192 .buf = buf ,
168193 .len = len
169194 };
195+ _reset_completion_status ();
170196 CHECK_NIMBLE_ERROR (ble_gattc_read (conn_handle , self -> handle , _read_cb , & read_info ));
171- int error_code ;
172- xTaskNotifyWait (0 , 0 , (uint32_t * )& error_code , 200 );
173- CHECK_BLE_ERROR (error_code );
197+ CHECK_NIMBLE_ERROR (_wait_for_completion (2000 ));
174198 return read_info .len ;
175199 } else {
176200 len = MIN (self -> current_value_len , len );
@@ -189,8 +213,7 @@ static int _write_cb(uint16_t conn_handle,
189213 const struct ble_gatt_error * error ,
190214 struct ble_gatt_attr * attr ,
191215 void * arg ) {
192- TaskHandle_t task = (TaskHandle_t )arg ;
193- xTaskNotify (task , error -> status , eSetValueWithOverwrite );
216+ _completion_status = error -> status ;
194217
195218 return 0 ;
196219}
@@ -201,10 +224,9 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self,
201224 if ((self -> props & CHAR_PROP_WRITE_NO_RESPONSE ) != 0 ) {
202225 CHECK_NIMBLE_ERROR (ble_gattc_write_no_rsp_flat (conn_handle , self -> handle , bufinfo -> buf , bufinfo -> len ));
203226 } else {
204- CHECK_NIMBLE_ERROR (ble_gattc_write_flat (conn_handle , self -> handle , bufinfo -> buf , bufinfo -> len , _write_cb , xTaskGetCurrentTaskHandle ()));
205- int error_code ;
206- xTaskNotifyWait (0 , 0 , (uint32_t * )& error_code , 200 );
207- CHECK_BLE_ERROR (error_code );
227+ _reset_completion_status ();
228+ CHECK_NIMBLE_ERROR (ble_gattc_write_flat (conn_handle , self -> handle , bufinfo -> buf , bufinfo -> len , _write_cb , NULL ));
229+ CHECK_NIMBLE_ERROR (_wait_for_completion (2000 ));
208230 }
209231 } else {
210232 // Validate data length for local characteristics only.
@@ -338,6 +360,10 @@ bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties
338360void common_hal_bleio_characteristic_add_descriptor (bleio_characteristic_obj_t * self ,
339361 bleio_descriptor_obj_t * descriptor ) {
340362 size_t i = self -> descriptor_list -> len ;
363+ if (i >= MAX_DESCRIPTORS ) {
364+ mp_raise_bleio_BluetoothError (MP_ERROR_TEXT ("Too many descriptors" ));
365+ }
366+
341367 mp_obj_list_append (MP_OBJ_FROM_PTR (self -> descriptor_list ),
342368 MP_OBJ_FROM_PTR (descriptor ));
343369
@@ -368,10 +394,9 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self,
368394 (notify ? 1 << 0 : 0 ) |
369395 (indicate ? 1 << 1 : 0 );
370396
371- CHECK_NIMBLE_ERROR (ble_gattc_write_flat (conn_handle , self -> cccd_handle , & cccd_value , 2 , _write_cb , xTaskGetCurrentTaskHandle ()));
372- int error_code ;
373- xTaskNotifyWait (0 , 0 , (uint32_t * )& error_code , 200 );
374- CHECK_BLE_ERROR (error_code );
397+ _reset_completion_status ();
398+ CHECK_NIMBLE_ERROR (ble_gattc_write_flat (conn_handle , self -> cccd_handle , & cccd_value , 2 , _write_cb , NULL ));
399+ CHECK_NIMBLE_ERROR (_wait_for_completion (2000 ));
375400}
376401
377402void bleio_characteristic_set_observer (bleio_characteristic_obj_t * self , mp_obj_t observer ) {
0 commit comments