Lines Matching +full:block +full:- +full:count

4  * SPDX-License-Identifier: Apache-2.0
19 #define MTU_SIZE_MAX (BT_MESH_RX_SDU_MAX - BT_MESH_MIC_SHORT)
22 #define SERVER_TIMEOUT_SECS(srv) (10 * (1 + (srv)->state.timeout_base))
23 /* The initial timer value used by an instance of the Pull BLOB State machine - T_BPI */
28 "max block size that is the power of two.");
37 "The BLOB Partial Block Report message does not fit into the maximum outgoing SDU "
42 "The BLOB Block Status message does not fit into the maximum outgoing SDU size.");
49 return DIV_ROUND_UP(srv->state.xfer.size, in block_count_get()
50 (1U << srv->state.xfer.block_size_log)); in block_count_get()
55 return MIN((srv->state.mtu_size - 2 - BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK)), in max_chunk_size()
61 return MIN(8 * (srv->state.mtu_size - 6), in max_chunk_count()
65 static inline uint32_t missing_chunks(const struct bt_mesh_blob_block *block) in missing_chunks() argument
68 uint32_t count = 0; in missing_chunks() local
70 for (i = 0; i < ARRAY_SIZE(block->missing); ++i) { in missing_chunks()
71 count += POPCOUNT(block->missing[i]); in missing_chunks()
74 return count; in missing_chunks()
83 /* Convert bit count to byte count: */ in store_state()
87 srv->mod, false, NULL, &srv->state, in store_state()
97 bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); in erase_state()
102 if (!srv->io->open) { in io_open()
106 return srv->io->open(srv->io, &srv->state.xfer, BT_MESH_BLOB_WRITE); in io_open()
111 if (!srv->io->close) { in io_close()
115 srv->io->close(srv->io, &srv->state.xfer); in io_close()
121 srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL ? in reset_timer()
125 k_work_reschedule(&srv->rx_timeout, K_SECONDS(timeout_secs)); in reset_timer()
130 /* utf-8 encoded: */ in buf_chunk_index_add()
145 int count = CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT; in pull_req_max() local
151 BLOB_CHUNK_SDU_LEN(srv->state.xfer.chunk_size), in pull_req_max()
154 count = MIN(CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT, in pull_req_max()
159 return MIN(count, missing_chunks(&srv->block)); in pull_req_max()
172 if (k_work_delayable_is_pending(&srv->rx_timeout)) { in report_sent()
173 k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); in report_sent()
181 .app_idx = srv->state.app_idx, in block_report()
182 .send_ttl = srv->state.ttl, in block_report()
183 .addr = srv->state.cli, in block_report()
185 int count; in block_report() local
188 LOG_DBG("rx BLOB Timeout Timer: %i", k_work_delayable_is_pending(&srv->rx_timeout)); in block_report()
194 count = pull_req_max(srv); in block_report()
196 for (i = 0; i < srv->block.chunk_count && count; ++i) { in block_report()
197 if (blob_chunk_missing_get(srv->block.missing, i)) { in block_report()
199 count--; in block_report()
203 (void)bt_mesh_model_send(srv->mod, &ctx, &buf, &report_cb, srv); in block_report()
209 srv->phase = phase; in phase_set()
219 srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; in cancel()
220 srv->state.ttl = BT_MESH_TTL_DEFAULT; in cancel()
221 srv->block.number = 0xffff; in cancel()
222 memset(srv->block.missing, 0, sizeof(srv->block.missing)); in cancel()
223 srv->state.xfer.chunk_size = 0xffff; in cancel()
224 k_work_cancel_delayable(&srv->rx_timeout); in cancel()
225 k_work_cancel_delayable(&srv->pull.report); in cancel()
229 if (srv->cb && srv->cb->end) { in cancel()
230 srv->cb->end(srv, srv->state.xfer.id, false); in cancel()
237 k_work_cancel_delayable(&srv->rx_timeout); in suspend()
238 k_work_cancel_delayable(&srv->pull.report); in suspend()
240 if (srv->cb && srv->cb->suspended) { in suspend()
241 srv->cb->suspended(srv); in suspend()
256 k_work_cancel_delayable(&srv->rx_timeout); in end()
257 k_work_cancel_delayable(&srv->pull.report); in end()
261 if (srv->cb && srv->cb->end) { in end()
262 srv->cb->end(srv, srv->state.xfer.id, true); in end()
268 for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) { in all_blocks_received()
269 if (srv->state.blocks[i]) { in all_blocks_received()
279 return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL && in pull_mode_xfer_complete()
280 srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && in pull_mode_xfer_complete()
291 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { in timeout()
307 if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK && in report_timeout()
308 srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { in report_timeout()
328 (srv->state.xfer.mode << 6))); in xfer_status_rsp()
329 net_buf_simple_add_u8(&buf, srv->phase); in xfer_status_rsp()
331 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in xfer_status_rsp()
335 net_buf_simple_add_le64(&buf, srv->state.xfer.id); in xfer_status_rsp()
337 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { in xfer_status_rsp()
341 net_buf_simple_add_le32(&buf, srv->state.xfer.size); in xfer_status_rsp()
342 net_buf_simple_add_u8(&buf, srv->state.xfer.block_size_log); in xfer_status_rsp()
343 net_buf_simple_add_le16(&buf, srv->state.mtu_size); in xfer_status_rsp()
344 net_buf_simple_add_mem(&buf, srv->state.blocks, in xfer_status_rsp()
348 ctx->send_ttl = srv->state.ttl; in xfer_status_rsp()
349 (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); in xfer_status_rsp()
364 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || in block_status_rsp()
365 srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { in block_status_rsp()
366 missing = srv->block.chunk_count; in block_status_rsp()
367 } else if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { in block_status_rsp()
370 missing = missing_chunks(&srv->block); in block_status_rsp()
373 if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { in block_status_rsp()
375 } else if (missing == srv->block.chunk_count) { in block_status_rsp()
383 LOG_DBG("Status: %u, missing: %u/%u", status, missing, srv->block.chunk_count); in block_status_rsp()
386 net_buf_simple_add_le16(&buf, srv->block.number); in block_status_rsp()
387 net_buf_simple_add_le16(&buf, srv->state.xfer.chunk_size); in block_status_rsp()
390 net_buf_simple_add_mem(&buf, srv->block.missing, in block_status_rsp()
391 DIV_ROUND_UP(srv->block.chunk_count, in block_status_rsp()
395 bt_hex(srv->block.missing, in block_status_rsp()
396 DIV_ROUND_UP(srv->block.chunk_count, 8))); in block_status_rsp()
399 int count = pull_req_max(srv); in block_status_rsp() local
401 for (i = 0; (i < srv->block.chunk_count) && count; ++i) { in block_status_rsp()
402 if (blob_chunk_missing_get(srv->block.missing, i)) { in block_status_rsp()
405 count--; in block_status_rsp()
410 if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in block_status_rsp()
411 ctx->send_ttl = srv->state.ttl; in block_status_rsp()
414 (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); in block_status_rsp()
420 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_xfer_get()
440 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_xfer_start()
456 LOG_DBG("\n\tsize: %u block size: %u\n\tmtu_size: %u\n\tmode: %s", in handle_xfer_start()
463 return -EINVAL; in handle_xfer_start()
466 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in handle_xfer_start()
472 if (srv->state.xfer.id != id) { in handle_xfer_start()
478 LOG_WRN("Expected ID: %s", bt_hex(&srv->state.xfer.id, sizeof(uint64_t))); in handle_xfer_start()
482 if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { in handle_xfer_start()
483 if (srv->state.xfer.mode != mode || in handle_xfer_start()
484 srv->state.xfer.size != size || in handle_xfer_start()
485 srv->state.xfer.block_size_log != block_size_log || in handle_xfer_start()
486 srv->state.mtu_size > mtu_size) { in handle_xfer_start()
492 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { in handle_xfer_start()
511 LOG_WRN("Invalid block size: %u", block_size_log); in handle_xfer_start()
516 srv->state.cli = ctx->addr; in handle_xfer_start()
517 srv->state.app_idx = ctx->app_idx; in handle_xfer_start()
518 srv->state.mtu_size = MIN(mtu_size, MTU_SIZE_MAX); in handle_xfer_start()
519 srv->state.xfer.id = id; in handle_xfer_start()
520 srv->state.xfer.size = size; in handle_xfer_start()
521 srv->state.xfer.mode = mode; in handle_xfer_start()
522 srv->state.xfer.block_size_log = block_size_log; in handle_xfer_start()
523 srv->state.xfer.chunk_size = 0xffff; in handle_xfer_start()
524 srv->block.number = 0xffff; in handle_xfer_start()
528 LOG_WRN("Invalid block count (%u)", block_count); in handle_xfer_start()
534 memset(srv->state.blocks, 0, sizeof(srv->state.blocks)); in handle_xfer_start()
536 atomic_set_bit(srv->state.blocks, i); in handle_xfer_start()
547 if (srv->cb && srv->cb->start) { in handle_xfer_start()
548 err = srv->cb->start(srv, ctx, &srv->state.xfer); in handle_xfer_start()
572 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_xfer_cancel()
579 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in handle_xfer_cancel()
583 if (srv->state.xfer.id != id) { in handle_xfer_cancel()
600 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_block_get()
602 switch (srv->phase) { in handle_block_get()
630 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_block_start()
638 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START || in handle_block_start()
639 srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in handle_block_start()
646 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { in handle_block_start()
647 if (block_number != srv->block.number || in handle_block_start()
648 chunk_size != srv->state.xfer.chunk_size) { in handle_block_start()
663 (DIV_ROUND_UP((1 << srv->state.xfer.block_size_log), chunk_size) > in handle_block_start()
665 LOG_WRN("Invalid chunk size: (chunk size: %u, max: %u, block log: %u, count: %u)", in handle_block_start()
667 srv->state.xfer.block_size_log, in handle_block_start()
673 srv->block.size = blob_block_size( in handle_block_start()
674 srv->state.xfer.size, srv->state.xfer.block_size_log, block_number); in handle_block_start()
675 srv->block.number = block_number; in handle_block_start()
676 srv->block.chunk_count = DIV_ROUND_UP(srv->block.size, chunk_size); in handle_block_start()
677 srv->state.xfer.chunk_size = chunk_size; in handle_block_start()
678 srv->block.offset = block_number * (1UL << srv->state.xfer.block_size_log); in handle_block_start()
680 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE || in handle_block_start()
681 !atomic_test_bit(srv->state.blocks, block_number)) { in handle_block_start()
682 memset(srv->block.missing, 0, sizeof(srv->block.missing)); in handle_block_start()
687 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED && srv->cb && in handle_block_start()
688 srv->cb->resume) { in handle_block_start()
689 srv->cb->resume(srv); in handle_block_start()
693 blob_chunk_missing_set_all(&srv->block); in handle_block_start()
695 LOG_DBG("%u: (%u/%u)\n\tsize: %u\n\tchunk size: %u\n\tchunk count: %u", in handle_block_start()
696 srv->block.number, srv->block.number + 1, block_count_get(srv), in handle_block_start()
697 srv->block.size, chunk_size, srv->block.chunk_count); in handle_block_start()
699 if (srv->io->block_start) { in handle_block_start()
700 err = srv->io->block_start(srv->io, &srv->state.xfer, in handle_block_start()
701 &srv->block); in handle_block_start()
709 if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { in handle_block_start()
711 k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); in handle_block_start()
725 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_chunk()
732 chunk.size = buf->len; in handle_chunk()
734 chunk.offset = idx * srv->state.xfer.chunk_size; in handle_chunk()
736 if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK || in handle_chunk()
737 idx >= srv->block.chunk_count) { in handle_chunk()
738 LOG_ERR("Invalid phase or index (%u %u)", srv->phase, in handle_chunk()
740 return -EINVAL; in handle_chunk()
743 if (idx == srv->block.chunk_count - 1) { in handle_chunk()
744 expected_size = srv->block.size % srv->state.xfer.chunk_size; in handle_chunk()
748 expected_size = srv->state.xfer.chunk_size; in handle_chunk()
753 return -EINVAL; in handle_chunk()
756 LOG_DBG("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count, in handle_chunk()
760 if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { in handle_chunk()
761 k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); in handle_chunk()
764 if (!blob_chunk_missing_get(srv->block.missing, idx)) { in handle_chunk()
766 return -EALREADY; in handle_chunk()
769 err = srv->io->wr(srv->io, &srv->state.xfer, &srv->block, &chunk); in handle_chunk()
774 blob_chunk_missing_set(srv->block.missing, idx, false); in handle_chunk()
775 if (missing_chunks(&srv->block)) { in handle_chunk()
779 if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { in handle_chunk()
783 if (srv->io->block_end) { in handle_chunk()
784 srv->io->block_end(srv->io, &srv->state.xfer, &srv->block); in handle_chunk()
787 atomic_clear_bit(srv->state.blocks, srv->block.number); in handle_chunk()
795 if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { in handle_chunk()
796 /* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report in handle_chunk()
797 * messages "If the current block is the last block, then the server determines that in handle_chunk()
798 * the client knows the transfer is complete. For example, a higher-layer model may in handle_chunk()
801 * We don't have any way for higher-layer model to indicate that the transfer is in handle_chunk()
802 * complete. Therefore we need to keep sending Partial Block Report messages until in handle_chunk()
803 * the client sends BLOB Transfer Get message or the Block Timer expires. in handle_chunk()
815 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in handle_info_get()
829 if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in handle_info_get()
830 ctx->send_ttl = srv->state.ttl; in handle_info_get()
833 (void)bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); in handle_info_get()
851 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in blob_srv_init()
853 srv->mod = mod; in blob_srv_init()
854 srv->state.ttl = BT_MESH_TTL_DEFAULT; in blob_srv_init()
855 srv->block.number = 0xffff; in blob_srv_init()
856 srv->state.xfer.chunk_size = 0xffff; in blob_srv_init()
857 k_work_init_delayable(&srv->rx_timeout, timeout); in blob_srv_init()
858 k_work_init_delayable(&srv->pull.report, report_timeout); in blob_srv_init()
867 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in blob_srv_settings_set()
871 return -EINVAL; in blob_srv_settings_set()
874 len = read_cb(cb_arg, &srv->state, sizeof(srv->state)); in blob_srv_settings_set()
879 srv->block.number = 0xffff; in blob_srv_settings_set()
880 srv->state.xfer.chunk_size = 0xffff; in blob_srv_settings_set()
883 LOG_WRN("Loaded block count too high (%u, max: %u)", in blob_srv_settings_set()
892 if (srv->state.cli == BT_MESH_ADDR_UNASSIGNED) { in blob_srv_settings_set()
893 LOG_DBG("Transfer (id=%llu) waiting for start", srv->state.xfer.id); in blob_srv_settings_set()
898 LOG_DBG("Recovered transfer from 0x%04x (%llu)", srv->state.cli, in blob_srv_settings_set()
899 srv->state.xfer.id); in blob_srv_settings_set()
907 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in blob_srv_start()
908 int err = -ENOTSUP; in blob_srv_start()
910 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { in blob_srv_start()
914 if (srv->cb && srv->cb->recover) { in blob_srv_start()
915 srv->io = NULL; in blob_srv_start()
916 err = srv->cb->recover(srv, &srv->state.xfer, &srv->io); in blob_srv_start()
917 if (!err && srv->io) { in blob_srv_start()
922 if (err || !srv->io) { in blob_srv_start()
925 srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; in blob_srv_start()
926 srv->state.ttl = BT_MESH_TTL_DEFAULT; in blob_srv_start()
935 struct bt_mesh_blob_srv *srv = mod->rt->user_data; in blob_srv_reset()
938 srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; in blob_srv_reset()
939 k_work_cancel_delayable(&srv->rx_timeout); in blob_srv_reset()
940 k_work_cancel_delayable(&srv->pull.report); in blob_srv_reset()
956 return -EBUSY; in bt_mesh_blob_srv_recv()
959 if (!io || !io->wr) { in bt_mesh_blob_srv_recv()
960 return -EINVAL; in bt_mesh_blob_srv_recv()
963 srv->state.xfer.id = id; in bt_mesh_blob_srv_recv()
964 srv->state.ttl = ttl; in bt_mesh_blob_srv_recv()
965 srv->state.timeout_base = timeout_base; in bt_mesh_blob_srv_recv()
966 srv->io = io; in bt_mesh_blob_srv_recv()
967 srv->block.number = 0xffff; in bt_mesh_blob_srv_recv()
968 srv->state.xfer.chunk_size = 0xffff; in bt_mesh_blob_srv_recv()
978 return -EALREADY; in bt_mesh_blob_srv_cancel()
988 return srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && in bt_mesh_blob_srv_is_busy()
989 srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED && in bt_mesh_blob_srv_is_busy()
990 srv->phase != BT_MESH_BLOB_XFER_PHASE_COMPLETE; in bt_mesh_blob_srv_is_busy()
998 if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || in bt_mesh_blob_srv_progress()
999 srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { in bt_mesh_blob_srv_progress()
1007 if (!atomic_test_bit(srv->state.blocks, i)) { in bt_mesh_blob_srv_progress()