-
Notifications
You must be signed in to change notification settings - Fork 1.9k
hotfix - miximum 50 files for each syncing time #7163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -37,6 +37,9 @@ static uint32_t current_read_offset = 0; | |||||||||
| #define INVALID_COMMAND 6 | ||||||||||
| #define FILE_NOT_FOUND 7 | ||||||||||
| #define FILE_INDEX_OUT_OF_RANGE 8 | ||||||||||
| #define STORAGE_NOT_READY 9 | ||||||||||
| #define STORAGE_LIST_MAX_FILES_PER_RESPONSE 50 | ||||||||||
| #define STORAGE_FILE_LIST_ENTRY_SIZE 8 | ||||||||||
|
|
||||||||||
| #define MAX_HEARTBEAT_FRAMES 100 | ||||||||||
| #define HEARTBEAT 50 | ||||||||||
|
|
@@ -48,6 +51,7 @@ static int sync_file_count = 0; | |||||||||
| static int current_sync_file_index = -1; | ||||||||||
| static uint8_t list_files_requested = 0; /* Deferred to storage thread */ | ||||||||||
| static int8_t delete_file_index = -1; /* -1 = no delete, >=0 = file index to delete */ | ||||||||||
| static uint8_t transfer_end_status = 0; | ||||||||||
|
|
||||||||||
| static void storage_config_changed_handler(const struct bt_gatt_attr *attr, uint16_t value); | ||||||||||
| static ssize_t storage_write_handler(struct bt_conn *conn, | ||||||||||
|
|
@@ -214,6 +218,19 @@ static void sync_speed_add_bytes(uint32_t bytes) | |||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| static uint8_t storage_status_from_error(int err, uint8_t fallback_status) | ||||||||||
| { | ||||||||||
| switch (err) { | ||||||||||
| case -ETIMEDOUT: | ||||||||||
| case -EBUSY: | ||||||||||
| case -ECANCELED: | ||||||||||
| case -EAGAIN: | ||||||||||
| return STORAGE_NOT_READY; | ||||||||||
| default: | ||||||||||
| return fallback_status; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| static uint16_t get_ble_chunk_size(struct bt_conn *conn, uint8_t include_timestamp) | ||||||||||
| { | ||||||||||
| if (!conn) { | ||||||||||
|
|
@@ -265,19 +282,44 @@ static int refresh_file_list_cache(void) | |||||||||
| */ | ||||||||||
| static int send_file_list_response(struct bt_conn *conn) | ||||||||||
| { | ||||||||||
| if (sync_file_count == 0 && refresh_file_list_cache() < 0) { | ||||||||||
| uint8_t error_resp[1] = {0xFF}; | ||||||||||
| storage_notify(conn, error_resp, 1); | ||||||||||
| return -1; | ||||||||||
| if (sync_file_count == 0) { | ||||||||||
| int ret = refresh_file_list_cache(); | ||||||||||
| if (ret < 0) { | ||||||||||
| uint8_t error_resp[1] = {storage_status_from_error(ret, STORAGE_NOT_READY)}; | ||||||||||
| storage_notify(conn, error_resp, 1); | ||||||||||
| return ret; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (sync_file_count == 0) { | ||||||||||
| uint8_t empty_resp[1] = {0}; | ||||||||||
| storage_notify(conn, empty_resp, 1); | ||||||||||
| return 0; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| uint16_t att_payload = 20; | ||||||||||
| if (conn) { | ||||||||||
| uint16_t mtu = bt_gatt_get_mtu(conn); | ||||||||||
| if (mtu > 3U) { | ||||||||||
| att_payload = mtu - 3U; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| int max_files_by_payload = (att_payload > 1U) ? ((att_payload - 1U) / STORAGE_FILE_LIST_ENTRY_SIZE) : 0; | ||||||||||
| int response_file_count = MIN(sync_file_count, STORAGE_LIST_MAX_FILES_PER_RESPONSE); | ||||||||||
| response_file_count = MIN(response_file_count, max_files_by_payload); | ||||||||||
|
|
||||||||||
| if (response_file_count < 0) { | ||||||||||
| response_file_count = 0; | ||||||||||
| } | ||||||||||
|
Comment on lines
+312
to
+314
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
|
||||||||||
| /* Use storage_buffer to build response (max 4440 bytes) */ | ||||||||||
| /* Each file: ts(4) + size(4) = 8 bytes, max ~550 files */ | ||||||||||
| int resp_len = 0; | ||||||||||
|
|
||||||||||
| storage_buffer[resp_len++] = (uint8_t)sync_file_count; | ||||||||||
| storage_buffer[resp_len++] = (uint8_t)response_file_count; | ||||||||||
|
|
||||||||||
| for (int i = 0; i < sync_file_count && resp_len + 8 <= STORAGE_BUFFER_SIZE; i++) { | ||||||||||
| for (int i = 0; i < response_file_count && resp_len + STORAGE_FILE_LIST_ENTRY_SIZE <= STORAGE_BUFFER_SIZE; i++) { | ||||||||||
| uint32_t timestamp = (uint32_t)strtoul(sync_file_list[i], NULL, 16); | ||||||||||
| uint32_t size = sync_file_sizes[i]; | ||||||||||
|
|
||||||||||
|
|
@@ -292,7 +334,11 @@ static int send_file_list_response(struct bt_conn *conn) | |||||||||
| storage_buffer[resp_len++] = size & 0xFF; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| LOG_INF("Sending file list: %d files, %d bytes", sync_file_count, resp_len); | ||||||||||
| LOG_INF("Sending file list: %d/%d files, %d bytes (att_payload=%u)", | ||||||||||
| response_file_count, | ||||||||||
| sync_file_count, | ||||||||||
| resp_len, | ||||||||||
| att_payload); | ||||||||||
| return storage_notify(conn, storage_buffer, resp_len); | ||||||||||
| } | ||||||||||
|
|
||||||||||
|
|
@@ -309,6 +355,7 @@ static int setup_file_transfer(int file_index, uint32_t start_offset) | |||||||||
| strncpy(current_read_filename, sync_file_list[file_index], MAX_FILENAME_LEN - 1); | ||||||||||
| current_read_offset = start_offset; | ||||||||||
| current_sync_file_index = file_index; | ||||||||||
| transfer_end_status = 0; | ||||||||||
|
|
||||||||||
| if (current_read_offset < sync_file_sizes[file_index]) { | ||||||||||
| remaining_length = sync_file_sizes[file_index] - current_read_offset; | ||||||||||
|
|
@@ -372,7 +419,12 @@ static uint8_t parse_storage_command(void *buf, uint16_t len, struct bt_conn *co | |||||||||
| ((uint8_t *) buf)[4] << 8 | ((uint8_t *) buf)[5]; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (sync_file_count == 0) refresh_file_list_cache(); | ||||||||||
| if (sync_file_count == 0) { | ||||||||||
| int ret = refresh_file_list_cache(); | ||||||||||
| if (ret < 0) { | ||||||||||
| return storage_status_from_error(ret, STORAGE_NOT_READY); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (file_index >= sync_file_count) { | ||||||||||
| return FILE_INDEX_OUT_OF_RANGE; | ||||||||||
|
|
@@ -498,6 +550,7 @@ static void write_to_gatt(struct bt_conn *conn) | |||||||||
| int r = read_audio_data(current_read_filename, storage_buffer, batch_audio_size, current_read_offset); | ||||||||||
| if (r <= 0) { | ||||||||||
| LOG_ERR("Failed to read audio data: %d", r); | ||||||||||
| transfer_end_status = storage_status_from_error(r, FILE_NOT_FOUND); | ||||||||||
| remaining_length = 0; | ||||||||||
| return; | ||||||||||
| } | ||||||||||
|
|
@@ -572,25 +625,36 @@ void storage_write(void) | |||||||||
| list_files_requested = 0; | ||||||||||
| /* Always refresh cache so the response is up-to-date, then send. | ||||||||||
| * send_file_list_response() will not re-refresh if count > 0. */ | ||||||||||
| refresh_file_list_cache(); | ||||||||||
| if (conn) { | ||||||||||
| send_file_list_response(conn); | ||||||||||
| int ret = refresh_file_list_cache(); | ||||||||||
| if (ret < 0) { | ||||||||||
| uint8_t result = storage_status_from_error(ret, STORAGE_NOT_READY); | ||||||||||
| storage_notify(conn, &result, 1); | ||||||||||
| } else { | ||||||||||
| send_file_list_response(conn); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| if (delete_file_index >= 0) { | ||||||||||
| int8_t idx = delete_file_index; | ||||||||||
| delete_file_index = -1; | ||||||||||
| uint8_t result = 0; | ||||||||||
|
|
||||||||||
| /* Ensure file list is cached */ | ||||||||||
| if (sync_file_count == 0) { | ||||||||||
| refresh_file_list_cache(); | ||||||||||
| int ret = refresh_file_list_cache(); | ||||||||||
| if (ret < 0) { | ||||||||||
| result = storage_status_from_error(ret, STORAGE_NOT_READY); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| uint8_t result = 0; | ||||||||||
| if (idx >= sync_file_count) { | ||||||||||
| if (result == 0 && idx >= sync_file_count) { | ||||||||||
| result = FILE_INDEX_OUT_OF_RANGE; | ||||||||||
| } else if (delete_file_by_index(idx) < 0) { | ||||||||||
| result = FILE_NOT_FOUND; | ||||||||||
| } else if (result == 0) { | ||||||||||
| int delete_ret = delete_file_by_index(idx); | ||||||||||
| if (delete_ret < 0) { | ||||||||||
| result = storage_status_from_error(delete_ret, FILE_NOT_FOUND); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (conn) { | ||||||||||
|
|
@@ -627,6 +691,17 @@ void storage_write(void) | |||||||||
| if (remaining_length == 0) { | ||||||||||
| if (stop_started) { | ||||||||||
| stop_started = 0; | ||||||||||
| transfer_end_status = 0; | ||||||||||
| current_sync_file_index = -1; | ||||||||||
| } else if (transfer_end_status != 0) { | ||||||||||
| uint8_t result = transfer_end_status; | ||||||||||
| save_offset(current_read_filename, current_read_offset); | ||||||||||
| LOG_WRN("Transfer aborted for %s with status %u", current_read_filename, result); | ||||||||||
| transfer_end_status = 0; | ||||||||||
| current_sync_file_index = -1; | ||||||||||
| if (conn) { | ||||||||||
| (void)storage_notify(conn, &result, 1); | ||||||||||
| } | ||||||||||
| } else { | ||||||||||
| save_offset(current_read_filename, current_read_offset); | ||||||||||
| LOG_INF("File done: %s", current_read_filename); | ||||||||||
|
|
@@ -655,6 +730,7 @@ void storage_write(void) | |||||||||
| LOG_PRINTK("done. attempting to download more files\n"); | ||||||||||
| uint8_t stop_result[1] = {100}; | ||||||||||
| (void)storage_notify(get_current_connection(), &stop_result, 1); | ||||||||||
| current_sync_file_index = -1; | ||||||||||
| k_msleep(10); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
max_files_by_payloadis used as a hard upper bound onresponse_file_count, but the app's "request more" trigger is exactlyresponse_file_count == STORAGE_LIST_MAX_FILES_PER_RESPONSE (50). If the negotiated MTU yields a payload wheremax_files_by_payload < 50(any MTU below ~404 bytes, i.e., att_payload < 401), the device will send fewer than 50 entries even when 50+ files exist. The app treats anything less than 50 as "done" and stops requesting, leaving remaining files stranded on the device.For example: MTU = 350 → att_payload = 347 →
max_files_by_payload = (347-1)/8 = 43. With 60 files on disk,response_file_count = min(60, 50, 43) = 43. The app receives 43, concludes syncing is complete, and never retrieves the remaining 17 files.The 50-file cap alone already guarantees the payload stays within 1 + 50×8 = 401 bytes (plus ATT overhead of 3), fitting any MTU ≥ 404. The
max_files_by_payloadsecondary cap is redundant in the common case and silently breaks pagination in the edge case. Consider removing it, or adding a "more files available" flag so the app can continue paginating regardless of batch size.