1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/conn.h>
12 #include <zephyr/bluetooth/gatt.h>
13 #include <zephyr/bluetooth/hci.h>
14 
15 /* Count down number of write commands after all PHY and connection updates */
16 #define COUNT_THROUGHPUT 1000U
17 
18 /* Count down number of metrics intervals before performing a PHY update */
19 #define PHY_UPDATE_COUNTDOWN 5U
20 static uint32_t phy_update_countdown;
21 
22 /* Current index of the parameters array to initiate PHY Update */
23 static uint8_t phy_param_idx;
24 
25 /* Count down number of metrics intervals before performing a param update */
26 #define PARAM_UPDATE_COUNTDOWN     PHY_UPDATE_COUNTDOWN
27 static uint32_t param_update_countdown;
28 
29 /* Current index of the parameters array to initiate Connection Update */
30 static uint8_t param_update_idx;
31 
32 /* If testing PHY Update then perform one iteration of Connection Updates otherwise when testing
33  * Connection Updates perform 20 iterations.
34  */
35 #define PARAM_UPDATE_ITERATION_MAX COND_CODE_1(CONFIG_USE_PHY_UPDATE_ITERATION_ONCE, (1U), (20U))
36 static uint32_t param_update_iteration;
37 
38 /* Total number of Connection Updates performed
39  *
40  * Used for logging purposes only
41  */
42 static uint32_t param_update_count;
43 
44 /* Calculate the Supervision Timeout to a Rounded up 10 ms unit
45  *
46  * Conform to required BT Specifiction defined minimum Supervision Timeout of 100 ms
47  */
48 #define CONN_TIMEOUT(_timeout) \
49 	BT_GAP_US_TO_CONN_TIMEOUT(DIV_ROUND_UP(MAX(100U * USEC_PER_MSEC, (_timeout)), \
50 					       10U * USEC_PER_MSEC) * 10U * USEC_PER_MSEC)
51 
52 /* Relaxed number of Connection Interval to set the Supervision Timeout.
53  * Shall be >= 2U.
54  *
55  * Refer to BT Spec v6.1, Vol 6, Part B, Section 4.5.2 Supervision timeout
56  *
57  * `(1 + connPeripheralLatency) × connSubrateFactor × connInterval × 2`
58  */
59 #define CONN_INTERVAL_MULTIPLIER (6U)
60 
phy_update_iterate(struct bt_conn * conn)61 static void phy_update_iterate(struct bt_conn *conn)
62 {
63 	const struct bt_conn_le_phy_param phy_param[] = {
64 		/* List of 1M Tx with Rx on other PHYs */
65 		{
66 			.options = BT_CONN_LE_PHY_OPT_NONE,
67 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
68 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
69 		}, {
70 			.options = BT_CONN_LE_PHY_OPT_NONE,
71 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
72 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
73 		}, {
74 			.options = BT_CONN_LE_PHY_OPT_NONE,
75 			.pref_tx_phy = BT_GAP_LE_PHY_1M,
76 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
77 		},
78 
79 		/* List of 2M Tx with Rx on other PHYs */
80 		{
81 			.options = BT_CONN_LE_PHY_OPT_NONE,
82 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
83 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
84 		}, {
85 			.options = BT_CONN_LE_PHY_OPT_NONE,
86 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
87 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
88 		}, {
89 			.options = BT_CONN_LE_PHY_OPT_NONE,
90 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
91 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
92 		},
93 
94 		/* List of Coded PHY S8 Tx with Rx on other PHYs */
95 		{
96 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
97 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
98 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
99 		}, {
100 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
101 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
102 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
103 		}, {
104 			.options = BT_CONN_LE_PHY_OPT_CODED_S8,
105 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
106 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
107 		},
108 
109 		/* List of Coded PHY S2 Tx with Rx on other PHYs */
110 		{
111 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
112 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
113 			.pref_rx_phy = BT_GAP_LE_PHY_1M,
114 		}, {
115 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
116 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
117 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
118 		}, {
119 			.options = BT_CONN_LE_PHY_OPT_CODED_S2,
120 			.pref_tx_phy = BT_GAP_LE_PHY_CODED,
121 			.pref_rx_phy = BT_GAP_LE_PHY_CODED,
122 		},
123 
124 		/* Finally stop at 2M Tx with Rx on 2M */
125 		{
126 			.options = BT_CONN_LE_PHY_OPT_NONE,
127 			.pref_tx_phy = BT_GAP_LE_PHY_2M,
128 			.pref_rx_phy = BT_GAP_LE_PHY_2M,
129 		},
130 	};
131 	int err;
132 
133 	if (phy_update_countdown--) {
134 		return;
135 	}
136 
137 	phy_update_countdown = PHY_UPDATE_COUNTDOWN;
138 
139 	if (phy_param_idx >= ARRAY_SIZE(phy_param)) {
140 		if (IS_ENABLED(CONFIG_USE_PHY_UPDATE_ITERATION_ONCE)) {
141 			/* No more PHY updates, stay at the last index */
142 			return;
143 		}
144 
145 		/* Test PHY Update not enabled, lets continue with connection update iterations
146 		 * forever.
147 		 */
148 		phy_param_idx = 0U;
149 	}
150 
151 	struct bt_conn_info conn_info;
152 
153 	err = bt_conn_get_info(conn, &conn_info);
154 	if (err) {
155 		printk("Failed to get connection info (%d).\n", err);
156 		return;
157 	}
158 
159 	struct bt_conn_le_phy_param conn_phy_param;
160 
161 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
162 		conn_phy_param.options = phy_param[phy_param_idx].options;
163 		conn_phy_param.pref_tx_phy = phy_param[phy_param_idx].pref_tx_phy;
164 		conn_phy_param.pref_rx_phy = phy_param[phy_param_idx].pref_rx_phy;
165 	} else {
166 		conn_phy_param.options = phy_param[phy_param_idx].options;
167 		conn_phy_param.pref_tx_phy = phy_param[phy_param_idx].pref_rx_phy;
168 		conn_phy_param.pref_rx_phy = phy_param[phy_param_idx].pref_tx_phy;
169 	}
170 
171 	printk("%s: PHY Update requested %u %u (%u)\n", __func__,
172 	       conn_phy_param.pref_tx_phy,
173 	       conn_phy_param.pref_rx_phy,
174 	       conn_phy_param.options);
175 
176 	err = bt_conn_le_phy_update(conn, &conn_phy_param);
177 	if (err) {
178 		printk("Failed to update PHY (%d).\n", err);
179 		return;
180 	}
181 
182 	phy_param_idx++;
183 }
184 
185 /* Interval between storing the measured write rate */
186 #define METRICS_INTERVAL 1U /* seconds */
187 
188 static struct bt_gatt_exchange_params mtu_exchange_params;
189 static uint32_t write_count;
190 static uint32_t write_len;
191 static uint32_t write_rate;
192 
193 /* Globals, reused by central_gatt_write and peripheral_gatt_write samples */
194 /* Connection context used by the Write Cmd calls */
195 struct bt_conn *conn_connected;
196 /* Stores the latest calculated write rate, bits per second */
197 uint32_t last_write_rate;
198 /* Number of Write Commands used to record the latest write rate.
199  * Has to be large enough to be transmitting packets for METRICS_INTERVAL duration.
200  * Assign 0 to continue calculating latest write rate, forever or until disconnection.
201  */
202 uint32_t *write_countdown;
203 /* Function pointer used to restart scanning on ACL disconnect */
204 void (*start_scan_func)(void);
205 
write_cmd_cb(struct bt_conn * conn,void * user_data)206 static void write_cmd_cb(struct bt_conn *conn, void *user_data)
207 {
208 	static uint32_t cycle_stamp;
209 	uint64_t delta;
210 
211 	delta = k_cycle_get_32() - cycle_stamp;
212 	delta = k_cyc_to_ns_floor64(delta);
213 
214 	if (delta == 0) {
215 		/* Skip division by zero */
216 		return;
217 	}
218 
219 	/* if last data rx-ed was greater than 1 second in the past,
220 	 * reset the metrics.
221 	 */
222 	if (delta > (METRICS_INTERVAL * NSEC_PER_SEC)) {
223 		printk("%s: count= %u, len= %u, rate= %u bps.\n", __func__,
224 		       write_count, write_len, write_rate);
225 
226 		last_write_rate = write_rate;
227 
228 		write_count = 0U;
229 		write_len = 0U;
230 		write_rate = 0U;
231 		cycle_stamp = k_cycle_get_32();
232 
233 		if (IS_ENABLED(CONFIG_BT_USER_PHY_UPDATE)) {
234 			phy_update_iterate(conn);
235 		}
236 
237 		/* NOTE: Though minimum connection timeout permitted is 100 ms, to avoid supervision
238 		 *       timeout when observer role is enabled in the sample, keep the timeout for
239 		 *       smaller connection interval be large enough due to repeated overlaps by the
240 		 *       scan window.
241 		 */
242 		const struct bt_le_conn_param update_params[] = {{
243 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(51250U),
244 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(51250U),
245 				.latency = 0,
246 				.timeout = CONN_TIMEOUT(51250U * CONN_INTERVAL_MULTIPLIER),
247 			}, {
248 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(50000U),
249 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(50000U),
250 				.latency = 0,
251 				.timeout = CONN_TIMEOUT(50000U * CONN_INTERVAL_MULTIPLIER),
252 			}, {
253 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(8750U),
254 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(8750U),
255 				.latency = 0,
256 				.timeout = CONN_TIMEOUT(720000U),
257 			}, {
258 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(7500U),
259 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(7500U),
260 				.latency = 0,
261 				.timeout = CONN_TIMEOUT(720000U),
262 			}, {
263 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(50000U),
264 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(50000U),
265 				.latency = 0,
266 				.timeout = CONN_TIMEOUT(50000U * CONN_INTERVAL_MULTIPLIER),
267 			}, {
268 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(51250U),
269 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(51250U),
270 				.latency = 0,
271 				.timeout = CONN_TIMEOUT(51250U * CONN_INTERVAL_MULTIPLIER),
272 			}, {
273 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(7500U),
274 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(7500U),
275 				.latency = 0,
276 				.timeout = CONN_TIMEOUT(720000U),
277 			}, {
278 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(8750U),
279 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(8750U),
280 				.latency = 0,
281 				.timeout = CONN_TIMEOUT(720000U),
282 			}, {
283 				.interval_min = BT_GAP_US_TO_CONN_INTERVAL(50000U),
284 				.interval_max = BT_GAP_US_TO_CONN_INTERVAL(50000U),
285 				.latency = 0,
286 				.timeout = CONN_TIMEOUT(50000U * CONN_INTERVAL_MULTIPLIER),
287 			},
288 		};
289 		int err;
290 
291 		if ((param_update_countdown--) != 0U) {
292 			return;
293 		}
294 
295 		param_update_countdown = PARAM_UPDATE_COUNTDOWN;
296 
297 		if (param_update_idx >= ARRAY_SIZE(update_params)) {
298 			if (IS_ENABLED(CONFIG_USE_CONN_UPDATE_ITERATION_ONCE) &&
299 			    (--param_update_iteration == 0U)) {
300 				/* No more conn updates, stay at the last index */
301 				param_update_iteration = 1U;
302 
303 				/* As this function is re-used by the peripheral; on target, users
304 				 * can enable simultaneous (background) scanning but by default do
305 				 * not have the scanning enabled.
306 				 * If both Central plus Peripheral role is built together then
307 				 * Peripheral is scanning (on 1M and Coded PHY windows) while there
308 				 * is simultaneous Write Commands.
309 				 *
310 				 * We stop scanning if we are stopping after one iteration of
311 				 * Connection Updates.
312 				 */
313 				if (IS_ENABLED(CONFIG_BT_OBSERVER) &&
314 				    !IS_ENABLED(CONFIG_USE_PHY_UPDATE_ITERATION_ONCE)) {
315 					/* Stop scanning. We will keep calling on every complete
316 					 * countdown. This is ok, for implementation simplicity,
317 					 * i.e. not adding addition design.
318 					 */
319 					err = bt_le_scan_stop();
320 					if (err != 0) {
321 						printk("Failed to stop scanning (%d).\n", err);
322 					}
323 
324 					printk("Scanning stopped.\n");
325 
326 					*write_countdown = COUNT_THROUGHPUT;
327 				}
328 
329 				return;
330 			}
331 
332 			/* Test Connection Update not enabled, lets continue with connection update
333 			 * iterations forever.
334 			 */
335 			param_update_idx = 0U;
336 		}
337 
338 		param_update_count++;
339 
340 		printk("Parameter Update Count: %u. %u: 0x%x 0x%x %u %u\n", param_update_count,
341 		       param_update_idx,
342 		       update_params[param_update_idx].interval_min,
343 		       update_params[param_update_idx].interval_max,
344 		       update_params[param_update_idx].latency,
345 		       update_params[param_update_idx].timeout);
346 		err = bt_conn_le_param_update(conn, &update_params[param_update_idx]);
347 		if (err != 0) {
348 			printk("Parameter update failed (err %d)\n", err);
349 		}
350 
351 		param_update_idx++;
352 
353 	} else {
354 		uint16_t len;
355 
356 		write_count++;
357 
358 		/* Extract the 16-bit data length stored in user_data */
359 		len = (uint32_t)user_data & 0xFFFF;
360 
361 		write_len += len;
362 		write_rate = ((uint64_t)write_len << 3) * (METRICS_INTERVAL * NSEC_PER_SEC) /
363 			     delta;
364 	}
365 }
366 
mtu_exchange_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_exchange_params * params)367 static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
368 			    struct bt_gatt_exchange_params *params)
369 {
370 	printk("%s: MTU exchange %s (%u)\n", __func__,
371 	       err == 0U ? "successful" : "failed",
372 	       bt_gatt_get_mtu(conn));
373 }
374 
mtu_exchange(struct bt_conn * conn)375 static int mtu_exchange(struct bt_conn *conn)
376 {
377 	int err;
378 
379 	printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
380 
381 	mtu_exchange_params.func = mtu_exchange_cb;
382 
383 	printk("%s: Exchange MTU...\n", __func__);
384 	err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
385 	if (err) {
386 		printk("%s: MTU exchange failed (err %d)", __func__, err);
387 	}
388 
389 	return err;
390 }
391 
connected(struct bt_conn * conn,uint8_t conn_err)392 static void connected(struct bt_conn *conn, uint8_t conn_err)
393 {
394 	struct bt_conn_info conn_info;
395 	char addr[BT_ADDR_LE_STR_LEN];
396 	int err;
397 
398 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
399 
400 	if (conn_err) {
401 		printk("%s: Failed to connect to %s (0x%02x)\n", __func__, addr,
402 		       conn_err);
403 		return;
404 	}
405 
406 	err = bt_conn_get_info(conn, &conn_info);
407 	if (err) {
408 		printk("Failed to get connection info (%d).\n", err);
409 		return;
410 	}
411 
412 	printk("%s: %s role %u\n", __func__, addr, conn_info.role);
413 
414 	conn_connected = bt_conn_ref(conn);
415 
416 	(void)mtu_exchange(conn);
417 
418 #if defined(CONFIG_BT_SMP)
419 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
420 		err = bt_conn_set_security(conn, BT_SECURITY_L2);
421 		if (err) {
422 			printk("Failed to set security (%d).\n", err);
423 		}
424 	}
425 #endif
426 
427 	if (IS_ENABLED(CONFIG_BT_USER_PHY_UPDATE)) {
428 		phy_update_countdown = PHY_UPDATE_COUNTDOWN;
429 		phy_param_idx = 0U;
430 	}
431 
432 	/* Every 1 second the acknowledged total GATT Write without Response data size is used for
433 	 * the throughput calculation.
434 	 * PHY update is performed in reference to this calculation interval, and connection update
435 	 * is offset by 1 of this interval so that connection update is initiated one such interval
436 	 * after PHY update was requested.
437 	 */
438 	param_update_countdown = PARAM_UPDATE_COUNTDOWN + 1U;
439 	param_update_iteration = PARAM_UPDATE_ITERATION_MAX;
440 	param_update_count = 0U;
441 	param_update_idx = 0U;
442 }
443 
disconnected(struct bt_conn * conn,uint8_t reason)444 static void disconnected(struct bt_conn *conn, uint8_t reason)
445 {
446 	struct bt_conn_info conn_info;
447 	char addr[BT_ADDR_LE_STR_LEN];
448 	int err;
449 
450 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
451 
452 	err = bt_conn_get_info(conn, &conn_info);
453 	if (err) {
454 		printk("Failed to get connection info (%d).\n", err);
455 		return;
456 	}
457 
458 	printk("%s: %s role %u, reason 0x%02x %s\n", __func__, addr, conn_info.role,
459 	       reason, bt_hci_err_to_str(reason));
460 
461 	conn_connected = NULL;
462 
463 	bt_conn_unref(conn);
464 
465 	if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
466 		start_scan_func();
467 	}
468 }
469 
le_param_req(struct bt_conn * conn,struct bt_le_conn_param * param)470 static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
471 {
472 	printk("%s: int (0x%04x, 0x%04x) lat %u to %u\n", __func__,
473 	       param->interval_min, param->interval_max, param->latency,
474 	       param->timeout);
475 
476 	return true;
477 }
478 
le_param_updated(struct bt_conn * conn,uint16_t interval,uint16_t latency,uint16_t timeout)479 static void le_param_updated(struct bt_conn *conn, uint16_t interval,
480 			     uint16_t latency, uint16_t timeout)
481 {
482 	printk("%s: int 0x%04x lat %u to %u\n", __func__, interval,
483 	       latency, timeout);
484 }
485 
486 #if defined(CONFIG_BT_SMP)
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)487 static void security_changed(struct bt_conn *conn, bt_security_t level,
488 			     enum bt_security_err err)
489 {
490 	printk("%s: to level %u, err %s(%u)\n", __func__, level, bt_security_err_to_str(err), err);
491 }
492 #endif
493 
494 #if defined(CONFIG_BT_USER_PHY_UPDATE)
le_phy_updated(struct bt_conn * conn,struct bt_conn_le_phy_info * param)495 static void le_phy_updated(struct bt_conn *conn,
496 			   struct bt_conn_le_phy_info *param)
497 {
498 	char addr[BT_ADDR_LE_STR_LEN];
499 
500 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
501 
502 	printk("LE PHY Updated: %s Tx 0x%x, Rx 0x%x\n", addr, param->tx_phy,
503 	       param->rx_phy);
504 }
505 #endif /* CONFIG_BT_USER_PHY_UPDATE */
506 
507 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
le_data_len_updated(struct bt_conn * conn,struct bt_conn_le_data_len_info * info)508 static void le_data_len_updated(struct bt_conn *conn,
509 				struct bt_conn_le_data_len_info *info)
510 {
511 	char addr[BT_ADDR_LE_STR_LEN];
512 
513 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
514 
515 	printk("Data length updated: %s max tx %u (%u us) max rx %u (%u us)\n",
516 	       addr, info->tx_max_len, info->tx_max_time, info->rx_max_len,
517 	       info->rx_max_time);
518 }
519 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
520 
521 BT_CONN_CB_DEFINE(conn_callbacks) = {
522 	.connected = connected,
523 	.disconnected = disconnected,
524 	.le_param_req = le_param_req,
525 	.le_param_updated = le_param_updated,
526 
527 #if defined(CONFIG_BT_SMP)
528 	.security_changed = security_changed,
529 #endif
530 
531 #if defined(CONFIG_BT_USER_PHY_UPDATE)
532 	.le_phy_updated = le_phy_updated,
533 #endif /* CONFIG_BT_USER_PHY_UPDATE */
534 
535 #if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
536 	.le_data_len_updated = le_data_len_updated,
537 #endif /* CONFIG_BT_USER_DATA_LEN_UPDATE */
538 };
539 
write_cmd(struct bt_conn * conn)540 int write_cmd(struct bt_conn *conn)
541 {
542 	static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {0, };
543 	static uint16_t data_len;
544 	uint16_t data_len_max;
545 	int err;
546 
547 	data_len_max = bt_gatt_get_mtu(conn) - 3;
548 	if (data_len_max > BT_ATT_MAX_ATTRIBUTE_LEN) {
549 		data_len_max = BT_ATT_MAX_ATTRIBUTE_LEN;
550 	}
551 
552 	if (IS_ENABLED(CONFIG_USE_VARIABLE_LENGTH_DATA)) {
553 		/* Use incremental length data for every write command */
554 		/* TODO: Include test case in BabbleSim tests */
555 		static bool decrement;
556 
557 		if (decrement) {
558 			data_len--;
559 			if (data_len <= 1) {
560 				data_len = 1;
561 				decrement = false;
562 			}
563 		} else {
564 			data_len++;
565 			if (data_len >= data_len_max) {
566 				data_len = data_len_max;
567 				decrement = true;
568 			}
569 		}
570 	} else {
571 		/* Use fixed length data for every write command */
572 		data_len = data_len_max;
573 	}
574 
575 	/* Pass the 16-bit data length value (instead of reference) in
576 	 * user_data so that unique value is pass for each write callback.
577 	 * Using handle 0x0001, we do not care if it is writable, we just want
578 	 * to transmit the data across.
579 	 */
580 	err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len,
581 						false, write_cmd_cb,
582 						(void *)((uint32_t)data_len));
583 	if (err) {
584 		printk("%s: Write cmd failed (%d).\n", __func__, err);
585 	}
586 
587 	return err;
588 }
589