[FL-1922] BLE buffer overflow (#789)
* rpc: increase RPC buffer size. Add get available buffer size API * bt: add flow control characteristic to serial service * ble: change updating flow control characteristic logic * rpc: add buffer is empty callback * bt: add notification about empty RPC buffer * ble: add more debug info * serial_service: add mutex guarding available buffer size * ble: remove debug logs in serial service
This commit is contained in:
27
applications/rpc/rpc.c
Normal file → Executable file
27
applications/rpc/rpc.c
Normal file → Executable file
@@ -53,6 +53,7 @@ static RpcSystemCallbacks rpc_systems[] = {
|
||||
|
||||
struct RpcSession {
|
||||
RpcSendBytesCallback send_bytes_callback;
|
||||
RpcBufferIsEmptyCallback buffer_is_empty_callback;
|
||||
RpcSessionClosedCallback closed_callback;
|
||||
void* context;
|
||||
osMutexId_t callbacks_mutex;
|
||||
@@ -292,7 +293,7 @@ static Rpc* rpc_alloc(void) {
|
||||
rpc->busy_mutex = osMutexNew(NULL);
|
||||
rpc->busy = false;
|
||||
rpc->events = osEventFlagsNew(NULL);
|
||||
rpc->stream = xStreamBufferCreate(256, 1);
|
||||
rpc->stream = xStreamBufferCreate(RPC_BUFFER_SIZE, 1);
|
||||
|
||||
rpc->decoded_message = furi_alloc(sizeof(PB_Main));
|
||||
rpc->decoded_message->cb_content.funcs.decode = content_callback;
|
||||
@@ -365,6 +366,7 @@ static void rpc_free_session(RpcSession* session) {
|
||||
session->context = NULL;
|
||||
session->closed_callback = NULL;
|
||||
session->send_bytes_callback = NULL;
|
||||
session->buffer_is_empty_callback = NULL;
|
||||
}
|
||||
|
||||
void rpc_session_set_context(RpcSession* session, void* context) {
|
||||
@@ -397,6 +399,18 @@ void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallba
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
}
|
||||
|
||||
void rpc_session_set_buffer_is_empty_callback(
|
||||
RpcSession* session,
|
||||
RpcBufferIsEmptyCallback callback) {
|
||||
furi_assert(session);
|
||||
furi_assert(callback);
|
||||
furi_assert(session->rpc->busy);
|
||||
|
||||
osMutexAcquire(session->callbacks_mutex, osWaitForever);
|
||||
session->buffer_is_empty_callback = callback;
|
||||
osMutexRelease(session->callbacks_mutex);
|
||||
}
|
||||
|
||||
/* Doesn't forbid using rpc_feed_bytes() after session close - it's safe.
|
||||
* Because any bytes received in buffer will be flushed before next session.
|
||||
* If bytes get into stream buffer before it's get epmtified and this
|
||||
@@ -415,6 +429,12 @@ size_t
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
size_t rpc_session_get_available_size(RpcSession* session) {
|
||||
furi_assert(session);
|
||||
Rpc* rpc = session->rpc;
|
||||
return xStreamBufferSpacesAvailable(rpc->stream);
|
||||
}
|
||||
|
||||
bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
||||
Rpc* rpc = istream->state;
|
||||
uint32_t flags = 0;
|
||||
@@ -425,6 +445,11 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) {
|
||||
while(1) {
|
||||
bytes_received +=
|
||||
xStreamBufferReceive(rpc->stream, buf + bytes_received, count - bytes_received, 0);
|
||||
if(xStreamBufferIsEmpty(rpc->stream)) {
|
||||
if(rpc->session.buffer_is_empty_callback) {
|
||||
rpc->session.buffer_is_empty_callback(rpc->session.context);
|
||||
}
|
||||
}
|
||||
if(count == bytes_received) {
|
||||
break;
|
||||
} else {
|
||||
|
21
applications/rpc/rpc.h
Normal file → Executable file
21
applications/rpc/rpc.h
Normal file → Executable file
@@ -4,6 +4,8 @@
|
||||
#include <stdbool.h>
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#define RPC_BUFFER_SIZE (1024)
|
||||
|
||||
/** Rpc interface. Used for opening session only. */
|
||||
typedef struct Rpc Rpc;
|
||||
/** Rpc session interface */
|
||||
@@ -11,6 +13,8 @@ typedef struct RpcSession RpcSession;
|
||||
|
||||
/** Callback to send to client any data (e.g. response to command) */
|
||||
typedef void (*RpcSendBytesCallback)(void* context, uint8_t* bytes, size_t bytes_len);
|
||||
/** Callback to notify client that buffer is empty */
|
||||
typedef void (*RpcBufferIsEmptyCallback)(void* context);
|
||||
/** Callback to notify transport layer that close_session command
|
||||
* is received. Any other actions lays on transport layer.
|
||||
* No destruction or session close preformed. */
|
||||
@@ -59,6 +63,15 @@ void rpc_session_set_context(RpcSession* session, void* context);
|
||||
*/
|
||||
void rpc_session_set_send_bytes_callback(RpcSession* session, RpcSendBytesCallback callback);
|
||||
|
||||
/** Set callback to notify that buffer is empty
|
||||
*
|
||||
* @param session pointer to RpcSession descriptor
|
||||
* @param callback callback to notify client that buffer is empty (can be NULL)
|
||||
*/
|
||||
void rpc_session_set_buffer_is_empty_callback(
|
||||
RpcSession* session,
|
||||
RpcBufferIsEmptyCallback callback);
|
||||
|
||||
/** Set callback to be called when RPC command to close session is received
|
||||
* WARN: It's forbidden to call RPC API within RpcSessionClosedCallback
|
||||
*
|
||||
@@ -77,3 +90,11 @@ void rpc_session_set_close_callback(RpcSession* session, RpcSessionClosedCallbac
|
||||
* @return actually consumed bytes
|
||||
*/
|
||||
size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, TickType_t timeout);
|
||||
|
||||
/** Get available size of RPC buffer
|
||||
*
|
||||
* @param session pointer to RpcSession descriptor
|
||||
*
|
||||
* @return bytes available in buffer
|
||||
*/
|
||||
size_t rpc_session_get_available_size(RpcSession* session);
|
||||
|
Reference in New Issue
Block a user