33 *
44 * The MIT License (MIT)
55 *
6- * Copyright (c) 2018 Artur Pacholec
6+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
77 *
88 * Permission is hereby granted, free of charge, to any person obtaining a copy
99 * of this software and associated documentation files (the "Software"), to deal
2929
3030#include "ble_drv.h"
3131#include "ble_gatts.h"
32- #include "nrf_soc .h"
32+ #include "sd_mutex .h"
3333
34+ #include "lib/utils/interrupt_char.h"
3435#include "py/runtime.h"
36+ #include "py/stream.h"
37+
38+ #include "tick.h"
3539
3640#include "common-hal/bleio/__init__.h"
3741#include "common-hal/bleio/CharacteristicBuffer.h"
@@ -43,33 +47,89 @@ STATIC void characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) {
4347 ble_gatts_evt_write_t * evt_write = & ble_evt -> evt .gatts_evt .params .write ;
4448 // Event handle must match the handle for my characteristic.
4549 if (evt_write -> handle == self -> characteristic -> handle ) {
46- // Push all the data onto the ring buffer.
50+ // Push all the data onto the ring buffer, but wait for any reads to finish.
51+ sd_mutex_acquire_wait_no_vm (& self -> ringbuf_mutex );
4752 for (size_t i = 0 ; i < evt_write -> len ; i ++ ) {
4853 ringbuf_put (& self -> ringbuf , evt_write -> data [i ]);
4954 }
55+ // Don't check for errors: we're in an event handler.
56+ sd_mutex_release (& self -> ringbuf_mutex );
5057 break ;
5158 }
5259 }
5360 }
5461
5562}
5663
57- // Assumes that buffer_size has been validated before call.
58- void common_hal_bleio_characteristic_buffer_construct (bleio_characteristic_buffer_obj_t * self , bleio_characteristic_obj_t * characteristic , size_t buffer_size ) {
64+ // Assumes that timeout and buffer_size have been validated before call.
65+ void common_hal_bleio_characteristic_buffer_construct (bleio_characteristic_buffer_obj_t * self ,
66+ bleio_characteristic_obj_t * characteristic ,
67+ mp_float_t timeout ,
68+ size_t buffer_size ) {
5969
6070 self -> characteristic = characteristic ;
71+ self -> timeout_ms = timeout * 1000 ;
6172 // This is a macro.
62- ringbuf_alloc (& self -> ringbuf , buffer_size );
73+ // true means long-lived, so it won't be moved.
74+ ringbuf_alloc (& self -> ringbuf , buffer_size , true);
75+ sd_mutex_new (& self -> ringbuf_mutex );
6376
6477 ble_drv_add_event_handler (characteristic_buffer_on_ble_evt , self );
6578
6679}
6780
68- // Returns a uint8_t byte value, or -1 if no data is available.
69- int common_hal_bleio_characteristic_buffer_read (bleio_characteristic_buffer_obj_t * self ) {
70- return ringbuf_get (& self -> ringbuf );
81+ int common_hal_bleio_characteristic_buffer_read (bleio_characteristic_buffer_obj_t * self , uint8_t * data , size_t len , int * errcode ) {
82+ uint64_t start_ticks = ticks_ms ;
83+
84+ // Wait for all bytes received or timeout
85+ while ( (ringbuf_count (& self -> ringbuf ) < len ) && (ticks_ms - start_ticks < self -> timeout_ms ) ) {
86+ #ifdef MICROPY_VM_HOOK_LOOP
87+ MICROPY_VM_HOOK_LOOP ;
88+ // Allow user to break out of a timeout with a KeyboardInterrupt.
89+ if ( mp_hal_is_interrupted () ) {
90+ return 0 ;
91+ }
92+ #endif
93+ }
94+
95+ // Copy received data. Lock out writes while copying.
96+ sd_mutex_acquire_wait (& self -> ringbuf_mutex );
97+
98+ size_t rx_bytes = MIN (ringbuf_count (& self -> ringbuf ), len );
99+ for ( size_t i = 0 ; i < rx_bytes ; i ++ ) {
100+ data [i ] = ringbuf_get (& self -> ringbuf );
101+ }
102+
103+ // Writes now OK.
104+ sd_mutex_release_check (& self -> ringbuf_mutex );
105+
106+ return rx_bytes ;
107+ }
108+
109+ uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available (bleio_characteristic_buffer_obj_t * self ) {
110+ return ringbuf_count (& self -> ringbuf );
111+ }
112+
113+ void common_hal_bleio_characteristic_buffer_clear_rx_buffer (bleio_characteristic_buffer_obj_t * self ) {
114+ // prevent conflict with uart irq
115+ sd_mutex_acquire_wait (& self -> ringbuf_mutex );
116+ ringbuf_clear (& self -> ringbuf );
117+ sd_mutex_release_check (& self -> ringbuf_mutex );
118+ }
119+
120+ bool common_hal_bleio_characteristic_buffer_deinited (bleio_characteristic_buffer_obj_t * self ) {
121+ return self -> characteristic == NULL ;
71122}
72123
73124void common_hal_bleio_characteristic_buffer_deinit (bleio_characteristic_buffer_obj_t * self ) {
74- ble_drv_remove_event_handler (characteristic_buffer_on_ble_evt , self );
125+ if (!common_hal_bleio_characteristic_buffer_deinited (self )) {
126+ ble_drv_remove_event_handler (characteristic_buffer_on_ble_evt , self );
127+ }
128+ }
129+
130+ bool common_hal_bleio_characteristic_buffer_connected (bleio_characteristic_buffer_obj_t * self ) {
131+ return self -> characteristic != NULL &&
132+ self -> characteristic -> service != NULL &&
133+ self -> characteristic -> service -> device != NULL &&
134+ common_hal_bleio_device_get_conn_handle (self -> characteristic -> service -> device ) != BLE_CONN_HANDLE_INVALID ;
75135}
0 commit comments