Skip to content

Commit b38f1bf

Browse files
committed
bt: Implement application level acknowledgements
This updates the GATT transport to use application level acknowledgements on top of unacknowledged GATT writes and notifications. This significantly increases throughput and matches the work done in the pouch repository. Signed-off-by: Sam Friedman <sam@golioth.io>
1 parent 604991d commit b38f1bf

9 files changed

Lines changed: 616 additions & 378 deletions

File tree

Kconfig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@ config POUCH_GATEWAY_SERVER_CERT_BUILTIN
3939
bool
4040
default y if !POUCH_GATEWAY_CLOUD
4141

42+
config POUCH_GATT_INFO_WINDOW_SIZE
43+
int "Info GATT Window Size"
44+
range 1 127
45+
default 4
46+
help
47+
The number of unacknowledged packets that can be received by
48+
the device on the info characteristic. Larger numbers can
49+
increase throughput but will use more RAM.
50+
51+
config POUCH_GATT_DEVICE_CERT_WINDOW_SIZE
52+
int "Device Cert GATT Window Size"
53+
range 1 127
54+
default 4
55+
help
56+
The number of unacknowledged packets that can be received by
57+
the device on the device certificate characteristic. Larger
58+
numbers can increase throughput but will use more RAM.
59+
60+
config POUCH_GATT_UPLINK_WINDOW_SIZE
61+
int "Uplink GATT Window Size"
62+
range 1 127
63+
default 4
64+
help
65+
The number of unacknowledged packets that can be received by
66+
the device on the uplink characteristic. Larger numbers can
67+
increase throughput but will use more RAM.
68+
4269
module = POUCH_GATEWAY
4370
module-str = Pouch Gateway Library
4471
source "subsys/logging/Kconfig.template.log_config"

include/pouch_gateway/types.h

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ enum pouch_gateway_gatt_attr
2323
POUCH_GATEWAY_GATT_ATTRS,
2424
};
2525

26+
enum server_cert_next_state
27+
{
28+
SERVER_CERT_NEXT_DEVICE_CERT,
29+
SERVER_CERT_NEXT_SERVER_CERT,
30+
SERVER_CERT_NEXT_END
31+
};
32+
2633
struct pouch_gateway_attr_handle
2734
{
2835
uint16_t value;
@@ -32,37 +39,24 @@ struct pouch_gateway_attr_handle
3239
struct pouch_gateway_node_info
3340
{
3441
struct pouch_gateway_attr_handle attr_handles[POUCH_GATEWAY_GATT_ATTRS];
35-
union
36-
{
37-
struct bt_gatt_discover_params discover_params;
38-
struct bt_gatt_read_params read_params;
39-
struct bt_gatt_subscribe_params subscribe_params;
40-
struct bt_gatt_write_params write_params;
41-
};
42+
struct bt_gatt_discover_params discover_params;
43+
struct bt_gatt_subscribe_params info_subscribe_params;
44+
struct bt_gatt_subscribe_params server_cert_subscribe_params;
45+
struct bt_gatt_subscribe_params device_cert_subscribe_params;
46+
struct bt_gatt_subscribe_params uplink_subscribe_params;
47+
struct bt_gatt_subscribe_params downlink_subscribe_params;
4248
struct pouch_gateway_downlink_context *downlink_ctx;
43-
void *downlink_scratch;
44-
void *server_cert_scratch;
49+
struct pouch_gatt_receiver *info_receiver;
50+
struct pouch_gatt_sender *server_cert_sender;
51+
struct pouch_gatt_receiver *device_cert_receiver;
52+
struct pouch_gatt_sender *downlink_sender;
53+
struct pouch_gatt_receiver *uplink_receiver;
4554
struct pouch_gatt_packetizer *packetizer;
4655
struct pouch_gateway_uplink *uplink;
4756
struct pouch_gateway_info_context *info_ctx;
4857
struct pouch_gateway_device_cert_context *device_cert_ctx;
4958
struct pouch_gateway_server_cert_context *server_cert_ctx;
59+
enum server_cert_next_state server_cert_next;
5060
bool server_cert_provisioned;
5161
bool device_cert_provisioned;
5262
};
53-
54-
/**
55-
* Allocate a buffer the size of the current MTU for GATT operations.
56-
* @param conn Bluetooth connection
57-
* @return Pointer to allocated buffer or NULL on failure
58-
*/
59-
static inline void *pouch_gateway_bt_gatt_mtu_malloc(struct bt_conn *conn)
60-
{
61-
size_t mtu = bt_gatt_get_mtu(conn);
62-
if (mtu < POUCH_GATEWAY_BT_ATT_OVERHEAD)
63-
{
64-
return NULL;
65-
}
66-
67-
return malloc(mtu - POUCH_GATEWAY_BT_ATT_OVERHEAD);
68-
}

lib/bt/device_cert.c

Lines changed: 107 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <zephyr/bluetooth/gatt.h>
1212

1313
#include <pouch/transport/gatt/common/packetizer.h>
14+
#include <pouch/transport/gatt/common/receiver.h>
1415

1516
#include <pouch_gateway/bt/connect.h>
1617

@@ -22,7 +23,6 @@
2223
#include <zephyr/logging/log.h>
2324
LOG_MODULE_REGISTER(device_cert_gatt, CONFIG_POUCH_GATEWAY_GATT_LOG_LEVEL);
2425

25-
2626
static void device_cert_cleanup(struct bt_conn *conn)
2727
{
2828
struct pouch_gateway_node_info *node = pouch_gateway_get_node_info(conn);
@@ -32,80 +32,120 @@ static void device_cert_cleanup(struct bt_conn *conn)
3232
pouch_gateway_device_cert_abort(node->device_cert_ctx);
3333
node->device_cert_ctx = NULL;
3434
}
35+
36+
if (node->device_cert_receiver)
37+
{
38+
pouch_gatt_receiver_destroy(node->device_cert_receiver);
39+
node->device_cert_receiver = NULL;
40+
}
3541
}
3642

37-
static uint8_t device_cert_read_cb(struct bt_conn *conn,
38-
uint8_t err,
39-
struct bt_gatt_read_params *params,
40-
const void *data,
41-
uint16_t length)
43+
static int device_cert_data_received_cb(void *conn,
44+
const void *data,
45+
size_t length,
46+
bool is_first,
47+
bool is_last)
4248
{
4349
struct pouch_gateway_node_info *node = pouch_gateway_get_node_info(conn);
4450

51+
int err = pouch_gateway_device_cert_push(node->device_cert_ctx, data, length);
4552
if (err)
4653
{
47-
LOG_ERR("Failed to read BLE GATT %s (err %d)", "device cert", err);
48-
device_cert_cleanup(conn);
49-
pouch_gateway_bt_finished(conn);
50-
return BT_GATT_ITER_STOP;
54+
LOG_ERR("Failed to push device cert");
55+
goto finish;
5156
}
5257

53-
if (length == 0)
58+
if (is_last)
5459
{
55-
LOG_ERR("No device cert");
56-
device_cert_cleanup(conn);
57-
pouch_gateway_bt_finished(conn);
58-
return BT_GATT_ITER_STOP;
60+
err = pouch_gateway_device_cert_finish(node->device_cert_ctx);
61+
if (err)
62+
{
63+
LOG_ERR("Failed to finish device cert: %d", err);
64+
goto finish;
65+
}
66+
node->device_cert_ctx = NULL;
5967
}
6068

61-
bool is_first = false;
62-
bool is_last = false;
63-
const void *payload = NULL;
64-
ssize_t payload_len = pouch_gatt_packetizer_decode(data, length, &payload, &is_first, &is_last);
65-
if (payload_len < 0)
69+
finish:
70+
if (err)
6671
{
67-
LOG_ERR("Failed to decode BLE GATT %s (err %d)", "device cert", (int) payload_len);
6872
device_cert_cleanup(conn);
6973
pouch_gateway_bt_finished(conn);
70-
return BT_GATT_ITER_STOP;
7174
}
7275

73-
if (data)
76+
return err;
77+
}
78+
79+
static int send_ack_cb(void *conn, const void *data, size_t length)
80+
{
81+
struct pouch_gateway_node_info *node = pouch_gateway_get_node_info(conn);
82+
uint16_t handle = node->attr_handles[POUCH_GATEWAY_GATT_ATTR_DEVICE_CERT].value;
83+
84+
return bt_gatt_write_without_response(conn, handle, data, length, false);
85+
}
86+
87+
static uint8_t device_cert_notify_cb(struct bt_conn *conn,
88+
struct bt_gatt_subscribe_params *params,
89+
const void *data,
90+
uint16_t length)
91+
{
92+
struct pouch_gateway_node_info *node = pouch_gateway_get_node_info(conn);
93+
94+
if (NULL == data)
7495
{
75-
LOG_HEXDUMP_DBG(data, length, "[READ] BLE GATT device cert");
76-
}
96+
LOG_DBG("Subscription terminated");
97+
device_cert_cleanup(conn);
7798

78-
pouch_gateway_device_cert_push(node->device_cert_ctx, payload, payload_len);
99+
return BT_GATT_ITER_STOP;
100+
}
79101

80-
if (is_last)
102+
if (NULL == node->device_cert_receiver)
81103
{
82-
int err = pouch_gateway_device_cert_finish(node->device_cert_ctx);
83-
if (err)
104+
enum pouch_gatt_ack_code code;
105+
if (pouch_gatt_packetizer_is_fin(data, length, &code))
84106
{
85-
LOG_ERR("Failed to finish device cert: %d", err);
86-
device_cert_cleanup(conn);
87-
pouch_gateway_bt_finished(conn);
88-
return BT_GATT_ITER_STOP;
107+
LOG_WRN("Received FIN while idle: %d", code);
108+
}
109+
else
110+
{
111+
LOG_ERR("Received packet while idle");
112+
113+
pouch_gatt_receiver_send_nack(send_ack_cb, conn, POUCH_GATT_NACK_IDLE);
89114
}
90115

91-
pouch_gateway_uplink_start(conn);
92116
return BT_GATT_ITER_STOP;
93117
}
94118

95-
err = bt_gatt_read(conn, params);
119+
bool complete = false;
120+
int err = pouch_gatt_receiver_receive_data(node->device_cert_receiver, data, length, &complete);
96121
if (err)
97122
{
98-
LOG_ERR("BT (re)read request failed: %d", err);
123+
LOG_ERR("Error receiving data: %d", err);
124+
99125
device_cert_cleanup(conn);
126+
100127
pouch_gateway_bt_finished(conn);
128+
101129
return BT_GATT_ITER_STOP;
102130
}
103131

104-
return BT_GATT_ITER_STOP;
132+
if (complete)
133+
{
134+
device_cert_cleanup(conn);
135+
136+
pouch_gateway_uplink_start(conn);
137+
138+
return BT_GATT_ITER_STOP;
139+
}
140+
141+
142+
return BT_GATT_ITER_CONTINUE;
105143
}
106144

107145
void pouch_gateway_device_cert_read(struct bt_conn *conn)
108146
{
147+
LOG_INF("Starting device cert read");
148+
109149
struct pouch_gateway_node_info *node = pouch_gateway_get_node_info(conn);
110150

111151
if (node->device_cert_provisioned)
@@ -114,8 +154,12 @@ void pouch_gateway_device_cert_read(struct bt_conn *conn)
114154
return;
115155
}
116156

117-
struct bt_gatt_read_params *read_params = &node->read_params;
118-
memset(read_params, 0, sizeof(*read_params));
157+
if (0 == node->attr_handles[POUCH_GATEWAY_GATT_ATTR_DEVICE_CERT].ccc)
158+
{
159+
LOG_ERR("Did not discover Device Cert CCC");
160+
pouch_gateway_bt_finished(conn);
161+
return;
162+
}
119163

120164
node->device_cert_ctx = pouch_gateway_device_cert_start();
121165
if (node->device_cert_ctx == NULL)
@@ -126,13 +170,32 @@ void pouch_gateway_device_cert_read(struct bt_conn *conn)
126170
return;
127171
}
128172

129-
read_params->func = device_cert_read_cb;
130-
read_params->handle_count = 1;
131-
read_params->single.handle = node->attr_handles[POUCH_GATEWAY_GATT_ATTR_DEVICE_CERT].value;
132-
int err = bt_gatt_read(conn, read_params);
173+
node->device_cert_receiver =
174+
pouch_gatt_receiver_create(send_ack_cb,
175+
conn,
176+
device_cert_data_received_cb,
177+
conn,
178+
CONFIG_POUCH_GATT_DEVICE_CERT_WINDOW_SIZE);
179+
if (NULL == node->device_cert_receiver)
180+
{
181+
LOG_ERR("Failed to create receiver");
182+
device_cert_cleanup(conn);
183+
pouch_gateway_bt_finished(conn);
184+
return;
185+
}
186+
187+
struct bt_gatt_subscribe_params *subscribe_params = &node->device_cert_subscribe_params;
188+
memset(subscribe_params, 0, sizeof(*subscribe_params));
189+
190+
subscribe_params->notify = device_cert_notify_cb;
191+
subscribe_params->value = BT_GATT_CCC_NOTIFY;
192+
subscribe_params->value_handle = node->attr_handles[POUCH_GATEWAY_GATT_ATTR_DEVICE_CERT].value;
193+
subscribe_params->ccc_handle = node->attr_handles[POUCH_GATEWAY_GATT_ATTR_DEVICE_CERT].ccc;
194+
atomic_set_bit(subscribe_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
195+
int err = bt_gatt_subscribe(conn, subscribe_params);
133196
if (err)
134197
{
135-
LOG_ERR("BT read request failed: %d", err);
198+
LOG_ERR("BT subscribe request failed: %d", err);
136199
device_cert_cleanup(conn);
137200
pouch_gateway_bt_finished(conn);
138201
}

0 commit comments

Comments
 (0)