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 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