12
12
#include <zephyr/device.h>
13
13
#include <zephyr/init.h>
14
14
#include <zephyr/sys/byteorder.h>
15
+ #include <zephyr/sys/check.h>
15
16
16
17
#include <zephyr/bluetooth/bluetooth.h>
17
18
#include <zephyr/bluetooth/conn.h>
@@ -109,6 +110,7 @@ struct bt_otc_internal_instance_t {
109
110
uint8_t metadata_read ;
110
111
int metadata_err ;
111
112
uint32_t rcvd_size ;
113
+ uint32_t sent_size ;
112
114
};
113
115
114
116
/* The profile clients that uses the OTS are responsible for discovery and
@@ -120,11 +122,14 @@ static struct bt_otc_internal_instance_t *cur_inst;
120
122
121
123
static int oacp_read (struct bt_conn * conn ,
122
124
struct bt_otc_internal_instance_t * inst );
125
+ static int oacp_write (struct bt_conn * conn , struct bt_otc_internal_instance_t * inst ,
126
+ const void * buf , uint32_t len , uint32_t offset ,
127
+ enum bt_ots_oacp_write_op_mode mode );
123
128
static void read_next_metadata (struct bt_conn * conn ,
124
129
struct bt_otc_internal_instance_t * inst );
125
130
static int read_attr (struct bt_conn * conn ,
126
- struct bt_otc_internal_instance_t * inst ,
127
- uint16_t handle , bt_gatt_read_func_t cb );
131
+ struct bt_otc_internal_instance_t * inst ,
132
+ uint16_t handle , bt_gatt_read_func_t cb );
128
133
129
134
/* L2CAP callbacks */
130
135
static void tx_done (struct bt_gatt_ots_l2cap * l2cap_ctx ,
@@ -134,6 +139,35 @@ static void tx_done(struct bt_gatt_ots_l2cap *l2cap_ctx,
134
139
BT_ERR ("Unexpected call, context: %p, conn: %p" , l2cap_ctx , (void * )conn );
135
140
}
136
141
142
+ static void write_obj_tx_done (struct bt_gatt_ots_l2cap * l2cap_ctx ,
143
+ struct bt_conn * conn )
144
+ {
145
+ int err ;
146
+ size_t written ;
147
+
148
+ if (cur_inst == NULL ) {
149
+ BT_ERR ("OTS instance invalid\n" );
150
+ return ;
151
+ }
152
+
153
+ written = cur_inst -> sent_size ;
154
+ BT_DBG ("ctx: %p, conn: %p, written: %d" ,
155
+ l2cap_ctx , (void * )conn , written );
156
+
157
+ err = bt_gatt_ots_l2cap_disconnect (l2cap_ctx );
158
+ if (err < 0 ) {
159
+ BT_WARN ("Disconnecting L2CAP returned error %d" , err );
160
+ }
161
+
162
+ if ((cur_inst -> otc_inst != NULL ) && (cur_inst -> otc_inst -> cb != NULL )) {
163
+ if (cur_inst -> otc_inst -> cb -> obj_data_written ) {
164
+ cur_inst -> otc_inst -> cb -> obj_data_written (0 , conn , written );
165
+ }
166
+ }
167
+
168
+ cur_inst = NULL ;
169
+ }
170
+
137
171
static ssize_t rx_done (struct bt_gatt_ots_l2cap * l2cap_ctx ,
138
172
struct bt_conn * conn , struct net_buf * buf )
139
173
{
@@ -192,7 +226,7 @@ static ssize_t rx_done(struct bt_gatt_ots_l2cap *l2cap_ctx,
192
226
}
193
227
194
228
static void chan_closed (struct bt_gatt_ots_l2cap * l2cap_ctx ,
195
- struct bt_conn * conn )
229
+ struct bt_conn * conn )
196
230
{
197
231
BT_DBG ("L2CAP closed, context: %p, conn: %p" , l2cap_ctx , (void * )conn );
198
232
}
@@ -508,6 +542,7 @@ static void write_olcp_cb(struct bt_conn *conn, uint8_t err,
508
542
BT_ERR ("Instance not found" );
509
543
return ;
510
544
}
545
+
511
546
inst -> busy = false;
512
547
}
513
548
@@ -1008,8 +1043,8 @@ static uint8_t read_obj_modified_cb(struct bt_conn *conn, uint8_t err,
1008
1043
}
1009
1044
1010
1045
static int read_attr (struct bt_conn * conn ,
1011
- struct bt_otc_internal_instance_t * inst ,
1012
- uint16_t handle , bt_gatt_read_func_t cb )
1046
+ struct bt_otc_internal_instance_t * inst ,
1047
+ uint16_t handle , bt_gatt_read_func_t cb )
1013
1048
{
1014
1049
if (!handle ) {
1015
1050
BT_DBG ("Handle not set" );
@@ -1096,6 +1131,30 @@ static void write_oacp_cp_cb(struct bt_conn *conn, uint8_t err,
1096
1131
inst -> busy = false;
1097
1132
}
1098
1133
1134
+ static void write_oacp_cp_write_req_cb (struct bt_conn * conn , uint8_t err ,
1135
+ struct bt_gatt_write_params * params )
1136
+ {
1137
+ struct bt_otc_internal_instance_t * inst =
1138
+ lookup_inst_by_handle (params -> handle );
1139
+ uint32_t len ;
1140
+
1141
+ BT_DBG ("Write Object request %s (0x%02X)" , err ? "failed" : "successful" , err );
1142
+ if (!inst ) {
1143
+ BT_ERR ("Instance not found" );
1144
+ return ;
1145
+ }
1146
+
1147
+ len = inst -> l2cap_ctx .tx .len ;
1148
+ inst -> l2cap_ctx .tx .len = 0 ;
1149
+ err = bt_gatt_ots_l2cap_send (& inst -> l2cap_ctx , inst -> l2cap_ctx .tx .data , len );
1150
+ if (err ) {
1151
+ BT_WARN ("L2CAP CoC error: %d while trying to execute OACP "
1152
+ "Read procedure" , err );
1153
+ }
1154
+
1155
+ inst -> busy = false;
1156
+ }
1157
+
1099
1158
static int oacp_read (struct bt_conn * conn ,
1100
1159
struct bt_otc_internal_instance_t * inst )
1101
1160
{
@@ -1157,6 +1216,64 @@ static int oacp_read(struct bt_conn *conn,
1157
1216
return err ;
1158
1217
}
1159
1218
1219
+ static int oacp_write (struct bt_conn * conn , struct bt_otc_internal_instance_t * inst ,
1220
+ const void * buf , uint32_t len , uint32_t offset ,
1221
+ enum bt_ots_oacp_write_op_mode mode )
1222
+ {
1223
+ int err ;
1224
+ struct bt_gatt_ots_l2cap * l2cap ;
1225
+
1226
+ if (!inst -> otc_inst -> oacp_handle ) {
1227
+ BT_DBG ("Handle not set" );
1228
+ return - EINVAL ;
1229
+ } else if (inst -> busy ) {
1230
+ return - EBUSY ;
1231
+ } else if (cur_inst ) {
1232
+ return - EBUSY ;
1233
+ }
1234
+
1235
+ err = bt_gatt_ots_l2cap_connect (conn , & l2cap );
1236
+ if (err ) {
1237
+ BT_DBG ("Could not connect l2cap: %d" , err );
1238
+ return err ;
1239
+ }
1240
+
1241
+ l2cap -> tx_done = write_obj_tx_done ;
1242
+ l2cap -> rx_done = rx_done ;
1243
+ l2cap -> closed = chan_closed ;
1244
+ l2cap -> tx .data = (uint8_t * )buf ;
1245
+ l2cap -> tx .len = len ;
1246
+ net_buf_simple_reset (& otc_tx_buf );
1247
+
1248
+ /* OP Code */
1249
+ net_buf_simple_add_u8 (& otc_tx_buf , BT_GATT_OTS_OACP_PROC_WRITE );
1250
+
1251
+ /* Offset */
1252
+ net_buf_simple_add_le32 (& otc_tx_buf , offset );
1253
+
1254
+ /* Len */
1255
+ net_buf_simple_add_le32 (& otc_tx_buf , len );
1256
+
1257
+ /* Mode, truncate or not */
1258
+ net_buf_simple_add_u8 (& otc_tx_buf , mode );
1259
+
1260
+ inst -> otc_inst -> write_params .offset = 0 ;
1261
+ inst -> otc_inst -> write_params .data = otc_tx_buf .data ;
1262
+ inst -> otc_inst -> write_params .length = otc_tx_buf .len ;
1263
+ inst -> otc_inst -> write_params .handle = inst -> otc_inst -> oacp_handle ;
1264
+ inst -> otc_inst -> write_params .func = write_oacp_cp_write_req_cb ;
1265
+ inst -> sent_size = len ;
1266
+ err = bt_gatt_write (conn , & inst -> otc_inst -> write_params );
1267
+
1268
+ if (!err ) {
1269
+ inst -> busy = true;
1270
+ cur_inst = inst ;
1271
+ }
1272
+
1273
+ inst -> rcvd_size = 0 ;
1274
+
1275
+ return err ;
1276
+ }
1160
1277
int bt_ots_client_read_object_data (struct bt_ots_client * otc_inst ,
1161
1278
struct bt_conn * conn )
1162
1279
{
@@ -1185,6 +1302,57 @@ int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst,
1185
1302
return oacp_read (conn , inst );
1186
1303
}
1187
1304
1305
+ int bt_ots_client_write_object_data (struct bt_ots_client * otc_inst ,
1306
+ struct bt_conn * conn , const void * buf , size_t len ,
1307
+ off_t offset , enum bt_ots_oacp_write_op_mode mode )
1308
+ {
1309
+ struct bt_otc_internal_instance_t * inst ;
1310
+
1311
+ CHECKIF (!conn ) {
1312
+ BT_WARN ("Invalid Connection" );
1313
+ return - ENOTCONN ;
1314
+ }
1315
+
1316
+ CHECKIF (!otc_inst ) {
1317
+ BT_ERR ("Invalid OTC instance" );
1318
+ return - EINVAL ;
1319
+ }
1320
+
1321
+ CHECKIF ((mode != BT_OTS_OACP_WRITE_OP_MODE_NONE ) &&
1322
+ (mode != BT_OTS_OACP_WRITE_OP_MODE_TRUNCATE )) {
1323
+ BT_ERR ("Invalid write object mode parameter %d" , mode );
1324
+ return - EINVAL ;
1325
+ }
1326
+
1327
+ /* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements
1328
+ * Offset and Length field are UINT32 Length
1329
+ */
1330
+ CHECKIF (len > UINT32_MAX ) {
1331
+ BT_ERR ("length exceed UINT32" );
1332
+ return - EINVAL ;
1333
+ }
1334
+
1335
+ CHECKIF ((offset > UINT32_MAX ) || (offset < 0 )) {
1336
+ BT_ERR ("offset exceeds UINT32" );
1337
+ return - EINVAL ;
1338
+ }
1339
+
1340
+ inst = lookup_inst_by_handle (otc_inst -> start_handle );
1341
+
1342
+ if (!inst ) {
1343
+ BT_ERR ("Invalid OTC instance" );
1344
+ return - EINVAL ;
1345
+ }
1346
+
1347
+ if ((len > (otc_inst -> cur_object .size .alloc - otc_inst -> cur_object .size .cur )) ||
1348
+ len == 0 ) {
1349
+ BT_ERR ("Invalid write len: %zu" , len );
1350
+ return - EINVAL ;
1351
+ }
1352
+
1353
+ return oacp_write (conn , inst , buf , (uint32_t )len , (uint32_t )offset , mode );
1354
+ }
1355
+
1188
1356
static void read_next_metadata (struct bt_conn * conn ,
1189
1357
struct bt_otc_internal_instance_t * inst )
1190
1358
{
0 commit comments