1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_
8 #define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_
9 
10 #include <sys/types.h>
11 
12 #include <zephyr/bluetooth/mesh/access.h>
13 #include <zephyr/bluetooth/mesh/blob.h>
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /**
20  * @defgroup bt_mesh_blob_cli Bluetooth Mesh BLOB Transfer Client model API
21  * @ingroup bt_mesh
22  * @{
23  */
24 
25 struct bt_mesh_blob_cli;
26 
27 /**
28  *
29  * @brief BLOB Transfer Client model Composition Data entry.
30  *
31  * @param _cli Pointer to a @ref bt_mesh_blob_cli instance.
32  */
33 #define BT_MESH_MODEL_BLOB_CLI(_cli)                                           \
34 	BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_BLOB_CLI, _bt_mesh_blob_cli_op,      \
35 			 NULL, _cli, &_bt_mesh_blob_cli_cb)
36 
37 /** Target node's Pull mode (Pull BLOB Transfer Mode) context used
38  *  while sending chunks to the Target node.
39  */
40 struct bt_mesh_blob_target_pull {
41 	/** Timestamp when the Block Report Timeout Timer expires for this Target node. */
42 	int64_t block_report_timestamp;
43 
44 	/** Missing chunks reported by this Target node. */
45 	uint8_t missing[DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX, 8)];
46 };
47 
48 /** BLOB Transfer Client Target node. */
49 struct bt_mesh_blob_target {
50 	/** Linked list node */
51 	sys_snode_t n;
52 
53 	/** Target node address. */
54 	uint16_t addr;
55 
56     /** Target node's Pull mode context.
57      *  Needs to be initialized when sending a BLOB in Pull mode.
58      */
59 	struct bt_mesh_blob_target_pull *pull;
60 
61 	/** BLOB transfer status, see @ref bt_mesh_blob_status. */
62 	uint8_t status;
63 
64 	uint8_t procedure_complete:1, /* Procedure has been completed. */
65 		acked:1,              /* Message has been acknowledged. Not used when sending. */
66 		timedout:1,           /* Target node didn't respond after specified timeout. */
67 		skip:1;               /* Skip Target node from broadcast. */
68 };
69 
70 /** BLOB transfer information.
71  *
72  * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_INACTIVE,
73  * the fields below @c phase are not initialized.
74  * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START,
75  * the fields below @c id are not initialized.
76  */
77 struct bt_mesh_blob_xfer_info {
78 	/** BLOB transfer status. */
79 	enum bt_mesh_blob_status status;
80 
81 	/** BLOB transfer mode. */
82 	enum bt_mesh_blob_xfer_mode mode;
83 
84 	/** BLOB transfer phase. */
85 	enum bt_mesh_blob_xfer_phase phase;
86 
87 	/** BLOB ID. */
88 	uint64_t id;
89 
90 	/** BLOB size in octets. */
91 	uint32_t size;
92 
93 	/** Logarithmic representation of the block size. */
94 	uint8_t block_size_log;
95 
96 	/** MTU size in octets. */
97 	uint16_t mtu_size;
98 
99 	/** Bit field indicating blocks that were not received.  */
100 	const uint8_t *missing_blocks;
101 };
102 
103 /** BLOB Transfer Client transfer inputs. */
104 struct bt_mesh_blob_cli_inputs {
105 	/** Linked list of Target nodes. Each node should point to @ref
106 	 *  bt_mesh_blob_target::n.
107 	 */
108 	sys_slist_t targets;
109 
110 	/** AppKey index to send with. */
111 	uint16_t app_idx;
112 
113 	/** Group address destination for the BLOB transfer, or @ref
114 	 *  BT_MESH_ADDR_UNASSIGNED to send every message to each Target
115 	 *  node individually.
116 	 */
117 	uint16_t group;
118 
119 	/** Time to live value of BLOB transfer messages. */
120 	uint8_t ttl;
121 
122 	/** Additional response time for the Target nodes, in 10-second increments.
123 	 *
124 	 *  The extra time can be used to give the Target nodes more time to respond
125 	 *  to messages from the Client. The actual timeout will be calculated
126 	 *  according to the following formula:
127 	 *
128 	 *  @verbatim
129 	 *  timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL)
130 	 *  @endverbatim
131 	 *
132 	 *  If a Target node fails to respond to a message from the Client within the
133 	 *  configured transfer timeout, the Target node is dropped.
134 	 */
135 	uint16_t timeout_base;
136 };
137 
138 /** Transfer capabilities of a Target node. */
139 struct bt_mesh_blob_cli_caps {
140 	/** Max BLOB size. */
141 	size_t max_size;
142 
143 	/** Logarithmic representation of the minimum block size. */
144 	uint8_t min_block_size_log;
145 
146 	/** Logarithmic representation of the maximum block size. */
147 	uint8_t max_block_size_log;
148 
149 	/** Max number of chunks per block. */
150 	uint16_t max_chunks;
151 
152 	/** Max chunk size. */
153 	uint16_t max_chunk_size;
154 
155 	/** Max MTU size. */
156 	uint16_t mtu_size;
157 
158 	/** Supported transfer modes. */
159 	enum bt_mesh_blob_xfer_mode modes;
160 };
161 
162 /** BLOB Transfer Client state. */
163 enum bt_mesh_blob_cli_state {
164 	/** No transfer is active. */
165 	BT_MESH_BLOB_CLI_STATE_NONE,
166 	/** Retrieving transfer capabilities. */
167 	BT_MESH_BLOB_CLI_STATE_CAPS_GET,
168 	/** Sending transfer start. */
169 	BT_MESH_BLOB_CLI_STATE_START,
170 	/** Sending block start. */
171 	BT_MESH_BLOB_CLI_STATE_BLOCK_START,
172 	/** Sending block chunks. */
173 	BT_MESH_BLOB_CLI_STATE_BLOCK_SEND,
174 	/** Checking block status. */
175 	BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK,
176 	/** Checking transfer status. */
177 	BT_MESH_BLOB_CLI_STATE_XFER_CHECK,
178 	/** Cancelling transfer. */
179 	BT_MESH_BLOB_CLI_STATE_CANCEL,
180 	/** Transfer is suspended. */
181 	BT_MESH_BLOB_CLI_STATE_SUSPENDED,
182 	/** Checking transfer progress. */
183 	BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET,
184 };
185 
186 /** Event handler callbacks for the BLOB Transfer Client model.
187  *
188  *  All handlers are optional.
189  */
190 struct bt_mesh_blob_cli_cb {
191 	/** @brief Capabilities retrieval completion callback.
192 	 *
193 	 *  Called when the capabilities retrieval procedure completes, indicating that
194 	 *  a common set of acceptable transfer parameters have been established
195 	 *  for the given list of Target nodes. All compatible Target nodes have
196 	 *  status code @ref BT_MESH_BLOB_SUCCESS.
197 	 *
198 	 *  @param cli     BLOB Transfer Client instance.
199 	 *  @param caps    Safe transfer capabilities if the transfer capabilities
200 	 *                 of at least one Target node has satisfied the Client, or NULL otherwise.
201 	 */
202 	void (*caps)(struct bt_mesh_blob_cli *cli,
203 		     const struct bt_mesh_blob_cli_caps *caps);
204 
205 	/** @brief Target node loss callback.
206 	 *
207 	 *  Called whenever a Target node has been lost due to some error in the
208 	 *  transfer. Losing a Target node is not considered a fatal error for
209 	 *  the Client until all Target nodes have been lost.
210 	 *
211 	 *  @param cli    BLOB Transfer Client instance.
212 	 *  @param target Target node that was lost.
213 	 *  @param reason Reason for the Target node loss.
214 	 */
215 	void (*lost_target)(struct bt_mesh_blob_cli *cli,
216 			    struct bt_mesh_blob_target *target,
217 			    enum bt_mesh_blob_status reason);
218 
219 	/** @brief Transfer is suspended.
220 	 *
221 	 * Called when the transfer is suspended due to response timeout from all Target nodes.
222 	 *
223 	 * @param cli    BLOB Transfer Client instance.
224 	 */
225 	void (*suspended)(struct bt_mesh_blob_cli *cli);
226 
227 	/** @brief Transfer end callback.
228 	 *
229 	 *  Called when the transfer ends.
230 	 *
231 	 *  @param cli     BLOB Transfer Client instance.
232 	 *  @param xfer    Completed transfer.
233 	 *  @param success Status of the transfer.
234 	 *                 Is @c true if at least one Target
235 	 *                 node received the whole transfer.
236 	 */
237 	void (*end)(struct bt_mesh_blob_cli *cli,
238 		    const struct bt_mesh_blob_xfer *xfer, bool success);
239 
240 	/** @brief Transfer progress callback
241 	 *
242 	 * The content of @c info is invalidated upon exit from the callback.
243 	 * Therefore it needs to be copied if it is planned to be used later.
244 	 *
245 	 *  @param cli      BLOB Transfer Client instance.
246 	 *  @param target   Target node that responded to the request.
247 	 *  @param info     BLOB transfer information.
248 	 */
249 	void (*xfer_progress)(struct bt_mesh_blob_cli *cli,
250 			      struct bt_mesh_blob_target *target,
251 			      const struct bt_mesh_blob_xfer_info *info);
252 
253 	/** @brief End of Get Transfer Progress procedure.
254 	 *
255 	 * Called when all Target nodes have responded or the procedure timed-out.
256 	 *
257 	 *  @param cli     BLOB Transfer Client instance.
258 	 */
259 	void (*xfer_progress_complete)(struct bt_mesh_blob_cli *cli);
260 };
261 
262 /** @cond INTERNAL_HIDDEN */
263 struct blob_cli_broadcast_ctx {
264 	/** Called for every Target node in unicast mode, or once in case of multicast mode. */
265 	void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst);
266 	/** Called after every @ref blob_cli_broadcast_ctx::send callback. */
267 	void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst);
268 	/** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes
269 	 *  have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called
270 	 *  after transmission has been completed.
271 	 */
272 	void (*next)(struct bt_mesh_blob_cli *cli);
273 	/** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before
274 	 * @ref blob_cli_broadcast_ctx::next is called.
275 	 */
276 	bool acked;
277 	/** If true, the message is always sent in a unicast way. */
278 	bool force_unicast;
279 	/** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */
280 	bool optional;
281 	/** Set to true by the BLOB Transfer Client between blob_cli_broadcast
282 	 *  and broadcast_complete calls.
283 	 */
284 	bool is_inited;
285 };
286 /** INTERNAL_HIDDEN @endcond */
287 
288 /** BLOB Transfer Client model instance. */
289 struct bt_mesh_blob_cli {
290 	/** Event handler callbacks */
291 	const struct bt_mesh_blob_cli_cb *cb;
292 
293 	/* Runtime state */
294 	const struct bt_mesh_model *mod;
295 
296 	struct {
297 		struct bt_mesh_blob_target *target;
298 		struct blob_cli_broadcast_ctx ctx;
299 		struct k_work_delayable retry;
300 		/* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */
301 		int64_t cli_timestamp;
302 		struct k_work complete;
303 		uint16_t pending;
304 		uint8_t retries;
305 		uint8_t sending : 1,
306 			cancelled : 1;
307 	} tx;
308 
309 	const struct bt_mesh_blob_io *io;
310 	const struct bt_mesh_blob_cli_inputs *inputs;
311 	const struct bt_mesh_blob_xfer *xfer;
312 	uint16_t block_count;
313 	uint16_t chunk_idx;
314 	uint16_t mtu_size;
315 	enum bt_mesh_blob_cli_state state;
316 	struct bt_mesh_blob_block block;
317 	struct bt_mesh_blob_cli_caps caps;
318 };
319 
320 /** @brief Retrieve transfer capabilities for a list of Target nodes.
321  *
322  *  Queries the availability and capabilities of all Target nodes, producing a
323  *  cumulative set of transfer capabilities for the Target nodes, and returning
324  *  it through the @ref bt_mesh_blob_cli_cb::caps callback.
325  *
326  *  Retrieving the capabilities may take several seconds, depending on the
327  *  number of Target nodes and mesh network performance. The end of the procedure
328  *  is indicated through the @ref bt_mesh_blob_cli_cb::caps callback.
329  *
330  *  This procedure is not required, but strongly recommended as a
331  *  preparation for a transfer to maximize performance and the chances of
332  *  success.
333  *
334  *  @param cli     BLOB Transfer Client instance.
335  *  @param inputs  Statically allocated BLOB Transfer Client transfer inputs.
336  *
337  *  @return 0 on success, or (negative) error code otherwise.
338  */
339 int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli,
340 			      const struct bt_mesh_blob_cli_inputs *inputs);
341 
342 /** @brief Perform a BLOB transfer.
343  *
344  *  Starts sending the transfer to the Target nodes. Only Target nodes with a
345  *  @c status of @ref BT_MESH_BLOB_SUCCESS will be considered.
346  *
347  *  The transfer will keep going either until all Target nodes have been dropped, or
348  *  the full BLOB has been sent.
349  *
350  *  The BLOB transfer may take several minutes, depending on the number of
351  *  Target nodes, size of the BLOB and mesh network performance. The end of the
352  *  transfer is indicated through the @ref bt_mesh_blob_cli_cb::end callback.
353  *
354  *  A Client only supports one transfer at the time.
355  *
356  *  @param cli    BLOB Transfer Client instance.
357  *  @param inputs Statically allocated BLOB Transfer Client transfer inputs.
358  *  @param xfer   Statically allocated transfer parameters.
359  *  @param io     BLOB stream to read the transfer from.
360  *
361  *  @return 0 on success, or (negative) error code otherwise.
362  */
363 int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli,
364 			  const struct bt_mesh_blob_cli_inputs *inputs,
365 			  const struct bt_mesh_blob_xfer *xfer,
366 			  const struct bt_mesh_blob_io *io);
367 
368 /** @brief Suspend the active transfer.
369  *
370  *  @param cli BLOB Transfer Client instance.
371  *
372  *  @return 0 on success, or (negative) error code otherwise.
373  */
374 int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli);
375 
376 /** @brief Resume the suspended transfer.
377  *
378  *  @param cli BLOB Transfer Client instance.
379  *
380  *  @return 0 on success, or (negative) error code otherwise.
381  */
382 int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli);
383 
384 /** @brief Cancel an ongoing transfer.
385  *
386  *  @param cli BLOB Transfer Client instance.
387  */
388 void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli);
389 
390 /** @brief Get the progress of BLOB transfer.
391  *
392  *  This function can only be used if the BLOB Transfer Client is currently
393  *  not performing a BLOB transfer.
394  *  To get progress of the active BLOB transfer, use the
395  *  @ref bt_mesh_blob_cli_xfer_progress_active_get function.
396  *
397  *  @param cli BLOB Transfer Client instance.
398  *  @param inputs Statically allocated BLOB Transfer Client transfer inputs.
399  *
400  *  @return 0 on success, or (negative) error code otherwise.
401  */
402 int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli,
403 				       const struct bt_mesh_blob_cli_inputs *inputs);
404 
405 /** @brief Get the current progress of the active transfer in percent.
406  *
407  *  @param cli BLOB Transfer Client instance.
408  *
409  *  @return The current transfer progress, or 0 if no transfer is active.
410  */
411 uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli);
412 
413 /** @brief Get the current state of the BLOB Transfer Client.
414  *
415  *  @param cli BLOB Transfer Client instance.
416  *
417  *  @return true if the BLOB Transfer Client is currently participating in a transfer or
418  *          retrieving the capabilities and false otherwise.
419  */
420 bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli);
421 
422 /** @cond INTERNAL_HIDDEN */
423 extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[];
424 extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb;
425 /** @endcond */
426 
427 /** @} */
428 
429 #ifdef __cplusplus
430 }
431 #endif
432 
433 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ */
434