1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model
10  * @ingroup bt_mesh_dfu
11  * @{
12  * @brief API for the Bluetooth mesh Firmware Update Client model
13  */
14 
15 #ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__
16 #define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__
17 
18 #include <zephyr/bluetooth/mesh/access.h>
19 #include <zephyr/bluetooth/mesh/blob_cli.h>
20 #include <zephyr/bluetooth/mesh/dfu.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 struct bt_mesh_dfu_cli;
27 
28 /**
29  *
30  *  @brief Initialization parameters for the @ref bt_mesh_dfu_cli.
31  *
32  *  @sa bt_mesh_dfu_cli_cb.
33  *
34  *  @param _handlers Handler callback structure.
35  */
36 #define BT_MESH_DFU_CLI_INIT(_handlers)                                        \
37 	{                                                                      \
38 		.cb = _handlers,                                               \
39 		.blob = { .cb = &_bt_mesh_dfu_cli_blob_handlers },             \
40 	}
41 
42 /**
43  *
44  *  @brief Firmware Update Client model Composition Data entry.
45  *
46  *  @param _cli Pointer to a @ref bt_mesh_dfu_cli instance.
47  */
48 #define BT_MESH_MODEL_DFU_CLI(_cli)                                            \
49 	BT_MESH_MODEL_BLOB_CLI(&(_cli)->blob),                                 \
50 	BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFU_CLI, _bt_mesh_dfu_cli_op, NULL,  \
51 			 _cli, &_bt_mesh_dfu_cli_cb)
52 
53 /** DFU Target node. */
54 struct bt_mesh_dfu_target {
55 	/** BLOB Target node */
56 	struct bt_mesh_blob_target blob;
57 	/** Image index on the Target node */
58 	uint8_t img_idx;
59 	/** Expected DFU effect, see @ref bt_mesh_dfu_effect. */
60 	uint8_t effect;
61 	/** Current DFU status, see @ref bt_mesh_dfu_status. */
62 	uint8_t status;
63 	/** Current DFU phase, see @ref bt_mesh_dfu_phase. */
64 	uint8_t phase;
65 };
66 
67 /** Metadata status response. */
68 struct bt_mesh_dfu_metadata_status {
69 	/** Image index. */
70 	uint8_t idx;
71 	/** Status code. */
72 	enum bt_mesh_dfu_status status;
73 	/** Effect of transfer. */
74 	enum bt_mesh_dfu_effect effect;
75 };
76 
77 /** DFU Target node status parameters. */
78 struct bt_mesh_dfu_target_status {
79 	/** Status of the previous operation. */
80 	enum bt_mesh_dfu_status status;
81 	/** Phase of the current DFU transfer. */
82 	enum bt_mesh_dfu_phase phase;
83 	/** The effect the update will have on the Target device's state. */
84 	enum bt_mesh_dfu_effect effect;
85 	/** BLOB ID used in the transfer. */
86 	uint64_t blob_id;
87 	/** Image index to transfer. */
88 	uint8_t img_idx;
89 	/** TTL used in the transfer. */
90 	uint8_t ttl;
91 
92 	/** Additional response time for the Target nodes, in 10-second increments.
93 	 *
94 	 *  The extra time can be used to give the Target nodes more time to respond
95 	 *  to messages from the Client. The actual timeout will be calculated
96 	 *  according to the following formula:
97 	 *
98 	 *  @verbatim
99 	 *  timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL)
100 	 *  @endverbatim
101 	 *
102 	 *  If a Target node fails to respond to a message from the Client within the
103 	 *  configured transfer timeout, the Target node is dropped.
104 	 */
105 	uint16_t timeout_base;
106 };
107 
108 /** @brief DFU image callback.
109  *
110  *  The image callback is called for every DFU image on the Target node when
111  *  calling @ref bt_mesh_dfu_cli_imgs_get.
112  *
113  *  @param cli     Firmware Update Client model instance.
114  *  @param ctx     Message context of the received message.
115  *  @param idx     Image index.
116  *  @param total   Total number of images on the Target node.
117  *  @param img     Image information for the given image index.
118  *  @param cb_data Callback data.
119  *
120  *  @retval BT_MESH_DFU_ITER_STOP     Stop iterating through the image list and
121  *                                    return from @ref bt_mesh_dfu_cli_imgs_get.
122  *  @retval BT_MESH_DFU_ITER_CONTINUE Continue iterating through the image list
123  *                                    if any images remain.
124  */
125 typedef enum bt_mesh_dfu_iter (*bt_mesh_dfu_img_cb_t)(
126 	struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, uint8_t idx,
127 	uint8_t total, const struct bt_mesh_dfu_img *img, void *cb_data);
128 
129 /** Firmware Update Client event callbacks. */
130 struct bt_mesh_dfu_cli_cb {
131 	/** @brief BLOB transfer is suspended.
132 	 *
133 	 * Called when the BLOB transfer is suspended due to response timeout from all Target nodes.
134 	 *
135 	 * @param cli    Firmware Update Client model instance.
136 	 */
137 	void (*suspended)(struct bt_mesh_dfu_cli *cli);
138 
139 	/** @brief DFU ended.
140 	 *
141 	 *  Called when the DFU transfer ends, either because all Target nodes were
142 	 *  lost or because the transfer was completed successfully.
143 	 *
144 	 *  @param cli    Firmware Update Client model instance.
145 	 *  @param reason Reason for ending.
146 	 */
147 	void (*ended)(struct bt_mesh_dfu_cli *cli,
148 		      enum bt_mesh_dfu_status reason);
149 
150 	/** @brief DFU transfer applied on all active Target nodes.
151 	 *
152 	 *  Called at the end of the apply procedure started by @ref
153 	 *  bt_mesh_dfu_cli_apply.
154 	 *
155 	 *  @param cli Firmware Update Client model instance.
156 	 */
157 	void (*applied)(struct bt_mesh_dfu_cli *cli);
158 
159 	/** @brief DFU transfer confirmed on all active Target nodes.
160 	 *
161 	 *  Called at the end of the apply procedure started by @ref
162 	 *  bt_mesh_dfu_cli_confirm.
163 	 *
164 	 *  @param cli Firmware Update Client model instance.
165 	 */
166 	void (*confirmed)(struct bt_mesh_dfu_cli *cli);
167 
168 	/** @brief DFU Target node was lost.
169 	 *
170 	 *  A DFU Target node was dropped from the receivers list. The Target node's
171 	 *  @c status is set to reflect the reason for the failure.
172 	 *
173 	 *  @param cli    Firmware Update Client model instance.
174 	 *  @param target DFU Target node that was lost.
175 	 */
176 	void (*lost_target)(struct bt_mesh_dfu_cli *cli,
177 			    struct bt_mesh_dfu_target *target);
178 };
179 
180 /** Firmware Update Client model instance.
181  *
182  *  Should be initialized with @ref BT_MESH_DFU_CLI_INIT.
183  */
184 struct bt_mesh_dfu_cli {
185 	/** Callback structure. */
186 	const struct bt_mesh_dfu_cli_cb *cb;
187 	/** Underlying BLOB Transfer Client. */
188 	struct bt_mesh_blob_cli blob;
189 
190 	/* runtime state */
191 
192 	uint32_t op;
193 	struct bt_mesh_model *mod;
194 
195 	struct {
196 		const struct bt_mesh_dfu_slot *slot;
197 		const struct bt_mesh_blob_io *io;
198 		struct bt_mesh_blob_xfer blob;
199 		uint8_t state;
200 		uint8_t flags;
201 	} xfer;
202 
203 	struct {
204 		uint8_t ttl;
205 		uint8_t type;
206 		uint8_t img_cnt;
207 		uint16_t addr;
208 		struct k_sem sem;
209 		void *params;
210 		bt_mesh_dfu_img_cb_t img_cb;
211 	} req;
212 };
213 
214 /** BLOB parameters for Firmware Update Client transfer: */
215 struct bt_mesh_dfu_cli_xfer_blob_params {
216 	/* Logarithmic representation of the block size. */
217 	uint8_t block_size_log;
218 	/** Base chunk size. May be smaller for the last chunk. */
219 	uint16_t chunk_size;
220 };
221 
222 /** Firmware Update Client transfer parameters: */
223 struct bt_mesh_dfu_cli_xfer {
224 	/** BLOB ID to use for this transfer, or 0 to set it randomly. */
225 	uint64_t blob_id;
226 	/** DFU image slot to transfer. */
227 	const struct bt_mesh_dfu_slot *slot;
228 	/**  Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */
229 	enum bt_mesh_blob_xfer_mode mode;
230 	/** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes'
231 	 *  capabilities before sending a firmware.
232 	 */
233 	const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params;
234 };
235 
236 /** @brief Start distributing a DFU.
237  *
238  *  Starts distribution of the firmware in the given slot to the list of DFU
239  *  Target nodes in @c ctx. The transfer runs in the background, and its end is
240  *  signalled through the @ref bt_mesh_dfu_cli_cb::ended callback.
241  *
242  *  @note The BLOB Transfer Client transfer inputs @c targets list must point to a list of @ref
243  *  bt_mesh_dfu_target nodes.
244  *
245  *  @param cli    Firmware Update Client model instance.
246  *  @param inputs BLOB Transfer Client transfer inputs.
247  *  @param io     BLOB stream to read BLOB from.
248  *  @param xfer   Firmware Update Client transfer parameters.
249  *
250  *  @return 0 on success, or (negative) error code otherwise.
251  */
252 int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli,
253 			 const struct bt_mesh_blob_cli_inputs *inputs,
254 			 const struct bt_mesh_blob_io *io,
255 			 const struct bt_mesh_dfu_cli_xfer *xfer);
256 
257 /** @brief Suspend a DFU transfer.
258  *
259  *  @param cli Firmware Update Client instance.
260  *
261  *  @return 0 on success, or (negative) error code otherwise.
262  */
263 int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli);
264 
265 /** @brief Resume the suspended transfer.
266  *
267  *  @param cli Firmware Update Client instance.
268  *
269  *  @return 0 on success, or (negative) error code otherwise.
270  */
271 int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli);
272 
273 /** @brief Cancel a DFU transfer.
274  *
275  *  Will cancel the ongoing DFU transfer, or the transfer on a specific Target
276  *  node if @c ctx is valid.
277  *
278  *  @param cli Firmware Update Client model instance.
279  *  @param ctx Message context, or NULL to cancel the ongoing DFU transfer.
280  *
281  *  @return 0 on success, or (negative) error code otherwise.
282  */
283 int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli,
284 			   struct bt_mesh_msg_ctx *ctx);
285 
286 /** @brief Apply the completed DFU transfer.
287  *
288  *  A transfer can only be applied after it has ended successfully. The Firmware
289  *  Update Client's @c applied callback is called at the end of the apply procedure.
290  *
291  *  @param cli Firmware Update Client model instance.
292  *
293  *  @return 0 on success, or (negative) error code otherwise.
294  */
295 int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli);
296 
297 /** @brief Confirm that the active transfer has been applied on the Target nodes.
298  *
299  *  A transfer can only be confirmed after it has been applied. The Firmware Update
300  *  Client's @c confirmed callback is called at the end of the confirm
301  *  procedure.
302  *
303  *  Target nodes that have reported the effect as @ref BT_MESH_DFU_EFFECT_UNPROV
304  *  are expected to not respond to the query, and will fail if they do.
305  *
306  *  @param cli Firmware Update Client model instance.
307  *
308  *  @return 0 on success, or (negative) error code otherwise.
309  */
310 int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli);
311 
312 /** @brief Get progress as a percentage of completion.
313  *
314  *  @param cli Firmware Update Client model instance.
315  *
316  *  @return The progress of the current transfer in percent, or 0 if no
317  *          transfer is active.
318  */
319 uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli);
320 
321 /** @brief Check whether a DFU transfer is in progress.
322  *
323  *  @param cli Firmware Update Client model instance.
324  *
325  *  @return true if the BLOB Transfer Client is currently participating in a transfer,
326  *          false otherwise.
327  */
328 bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli);
329 
330 /** @brief Perform a DFU image list request.
331  *
332  *  Requests the full list of DFU images on a Target node, and iterates through
333  *  them, calling the @c cb for every image.
334  *
335  *  The DFU image list request can be used to determine which image index the
336  *  Target node holds its different firmwares in.
337  *
338  *  Waits for a response until the procedure timeout expires.
339  *
340  *  @param cli       Firmware Update Client model instance.
341  *  @param ctx       Message context.
342  *  @param cb        Callback to call for each image index.
343  *  @param cb_data   Callback data to pass to @c cb.
344  *  @param max_count Max number of images to return.
345  *
346  *  @return 0 on success, or (negative) error code otherwise.
347  */
348 int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli,
349 			     struct bt_mesh_msg_ctx *ctx,
350 			     bt_mesh_dfu_img_cb_t cb, void *cb_data,
351 			     uint8_t max_count);
352 
353 /** @brief Perform a metadata check for the given DFU image slot.
354  *
355  *  The metadata check procedure allows the Firmware Update Client to check if a Target
356  *  node will accept a transfer of this DFU image slot, and what the effect would be.
357  *
358  *  Waits for a response until the procedure timeout expires.
359  *
360  *  @param cli     Firmware Update Client model instance.
361  *  @param ctx     Message context.
362  *  @param img_idx Target node's image index to check.
363  *  @param slot    DFU image slot to check for.
364  *  @param rsp     Metadata status response buffer.
365  *
366  *  @return 0 on success, or (negative) error code otherwise.
367  */
368 int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli,
369 				   struct bt_mesh_msg_ctx *ctx, uint8_t img_idx,
370 				   const struct bt_mesh_dfu_slot *slot,
371 				   struct bt_mesh_dfu_metadata_status *rsp);
372 
373 /** @brief Get the status of a Target node.
374  *
375  *  @param cli Firmware Update Client model instance.
376  *  @param ctx Message context.
377  *  @param rsp Response data buffer.
378  *
379  *  @return 0 on success, or (negative) error code otherwise.
380  */
381 int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli,
382 			       struct bt_mesh_msg_ctx *ctx,
383 			       struct bt_mesh_dfu_target_status *rsp);
384 
385 /** @brief Get the current procedure timeout value.
386  *
387  *  @return The configured procedure timeout.
388  */
389 int32_t bt_mesh_dfu_cli_timeout_get(void);
390 
391 /** @brief Set the procedure timeout value.
392  *
393  *  @param timeout The new procedure timeout.
394  */
395 void bt_mesh_dfu_cli_timeout_set(int32_t timeout);
396 
397 /** @cond INTERNAL_HIDDEN */
398 extern const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers;
399 extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb;
400 extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[];
401 /** @endcond */
402 
403 #ifdef __cplusplus
404 }
405 #endif
406 
407 #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ */
408 
409 /** @} */
410