From 3a1db4ccaa41cf668adbcd096f76c33e14f39027 Mon Sep 17 00:00:00 2001 From: cavac Date: Thu, 11 Dec 2025 14:48:40 +0100 Subject: [PATCH 1/8] Increase queue size for better buffering (slow SD cards...) --- badgelink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/badgelink.c b/badgelink.c index ff3a926..5ba569d 100644 --- a/badgelink.c +++ b/badgelink.c @@ -58,7 +58,7 @@ static void badgelink_thread_main(void*); // Prepare the data for the BadgeLink service to start. void badgelink_init() { - rxqueue = xQueueCreate(16, sizeof(fragment_t)); + rxqueue = xQueueCreate(256, sizeof(fragment_t)); } // Start the badgelink service. From fe11901adffed43b34c95744bb160003328c6bcc Mon Sep 17 00:00:00 2001 From: cavac Date: Thu, 11 Dec 2025 14:50:02 +0100 Subject: [PATCH 2/8] Use streaming CRC instead of rereading everything. Prevents timeouts on larger files --- badgelink_appfs.c | 9 ++++++--- badgelink_fs.c | 36 ++++++------------------------------ 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/badgelink_appfs.c b/badgelink_appfs.c index 2ef1e29..e702beb 100644 --- a/badgelink_appfs.c +++ b/badgelink_appfs.c @@ -13,6 +13,8 @@ static char const TAG[] = "badgelink_appfs"; static appfs_handle_t xfer_fd; // CRC32 of file transferred. static uint32_t xfer_crc32; +// Running CRC32 computed during upload. +static uint32_t running_crc; // Calculate the CRC32 of an AppFS file. static uint32_t calc_app_crc32(appfs_handle_t fd) { @@ -69,6 +71,7 @@ void badgelink_appfs_xfer_upload() { ESP_LOGE(TAG, "%s: error %s", __FUNCTION__, esp_err_to_name(ec)); badgelink_status_int_err(); } else { + running_crc = esp_crc32_le(running_crc, chunk->data.bytes, chunk->data.size); badgelink_status_ok(); } } @@ -108,10 +111,9 @@ void badgelink_appfs_xfer_stop(bool abnormal) { appfsDeleteFile(name); } else { - uint32_t actual_crc32 = calc_app_crc32(xfer_fd); - if (actual_crc32 != xfer_crc32) { + if (running_crc != xfer_crc32) { ESP_LOGE(TAG, "AppFS upload CRC32 mismatch; expected %08" PRIx32 ", actual %08" PRIx32, xfer_crc32, - actual_crc32); + running_crc); badgelink_status_int_err(); // AppFS can delete by fd so this is the workaround. @@ -251,6 +253,7 @@ void badgelink_appfs_upload() { badgelink_xfer_pos = 0; badgelink_xfer_size = req->id.metadata.size; xfer_crc32 = req->crc32; + running_crc = 0; // This OK response officially starts the transfer. ESP_LOGI(TAG, "AppFS upload started"); diff --git a/badgelink_fs.c b/badgelink_fs.c index d8de278..49b8995 100644 --- a/badgelink_fs.c +++ b/badgelink_fs.c @@ -18,6 +18,7 @@ static char const TAG[] = "badgelink_fs"; static char xfer_path[256]; static FILE* xfer_fd; static uint32_t xfer_crc32; +static uint32_t running_crc; // Handle a FS request packet. void badgelink_fs_handle() { @@ -68,6 +69,7 @@ void badgelink_fs_xfer_upload() { badgelink_status_int_err(); } } else { + running_crc = esp_crc32_le(running_crc, chunk->data.bytes, chunk->data.size); badgelink_status_ok(); } } @@ -101,38 +103,11 @@ void badgelink_fs_xfer_stop(bool abnormal) { } } else if (badgelink_xfer_is_upload) { - // Double-check file CRC32. - uint32_t crc = 0; - uint8_t tmp[128]; - fseek(xfer_fd, 0, SEEK_SET); - for (uint32_t i = 0; i < badgelink_xfer_size; i += sizeof(tmp)) { - uint32_t max = sizeof(tmp) < badgelink_xfer_size - i ? sizeof(tmp) : badgelink_xfer_size - i; - uint32_t actual_read = fread(tmp, 1, max, xfer_fd); - if (actual_read != max) { - long pos = ftell(xfer_fd); - ESP_LOGE(TAG, - "Read too little while checking CRC32; expected %" PRIu32 ", got %" PRIu32 " at offset %ld", - max, actual_read, pos); - fclose(xfer_fd); - unlink(xfer_path); - badgelink_status_int_err(); - return; - } - crc = esp_crc32_le(crc, tmp, max); - } - fclose(xfer_fd); - if (crc != xfer_crc32) { - ESP_LOGE(TAG, "FS upload CRC32 mismatch; expected %08" PRIx32 ", actual %08" PRIx32, xfer_crc32, crc); - fseek(xfer_fd, 0, SEEK_SET); - printf("Data:"); - for (size_t i = 0; i < badgelink_xfer_size; i++) { - uint8_t c; - fread(&c, 1, 1, xfer_fd); - printf(" %02x", c); - } - printf("\n"); + if (running_crc != xfer_crc32) { + ESP_LOGE(TAG, "FS upload CRC32 mismatch; expected %08" PRIx32 ", actual %08" PRIx32, xfer_crc32, + running_crc); unlink(xfer_path); badgelink_status_int_err(); } else { @@ -263,6 +238,7 @@ void badgelink_fs_upload() { badgelink_xfer_size = req->size; badgelink_xfer_pos = 0; xfer_crc32 = req->crc32; + running_crc = 0; // This OK response officially starts the transfer. ESP_LOGI(TAG, "FS upload started"); From 509a755033ea615339cdb8e1626514761ee8e5ca Mon Sep 17 00:00:00 2001 From: cavac Date: Thu, 11 Dec 2025 17:02:46 +0100 Subject: [PATCH 3/8] Add support for protocol negotiation (for backwards compatibility), add a V2 version of file download for faster speeds and less timeout problems --- ProtocolV2.md | 145 +++++++++++++++++++++++++++++++++++++++++++++ badgelink.c | 38 +++++++++++- badgelink.h | 3 + badgelink.pb.c | 6 ++ badgelink.pb.h | 46 +++++++++++++- badgelink_appfs.c | 29 ++++++++- badgelink_fs.c | 53 +++++++++++++---- tools/badgelink.py | 125 +++++++++++++++++++++++++++++++++++--- 8 files changed, 420 insertions(+), 25 deletions(-) create mode 100644 ProtocolV2.md diff --git a/ProtocolV2.md b/ProtocolV2.md new file mode 100644 index 0000000..2d5a077 --- /dev/null +++ b/ProtocolV2.md @@ -0,0 +1,145 @@ +# BadgeLink Protocol Changes + +## Protocol Version Negotiation (Version 2) + +This update adds protocol version negotiation to BadgeLink. The previous protocol without version negotiation is considered version 1. + +### New Message Types + +#### VersionReq (Request tag 7) + +Sent by the client to negotiate the protocol version. + +| Field | Tag | Type | Description | +|-------|-----|------|-------------| +| client_version | 1 | uint16 | Highest protocol version supported by the client | + +#### VersionResp (Response tag 6) + +Sent by the server in response to a VersionReq. + +| Field | Tag | Type | Description | +|-------|-----|------|-------------| +| server_version | 1 | uint16 | Highest protocol version supported by the server | +| negotiated_version | 2 | uint16 | Protocol version to use for this session | + +### Negotiation Algorithm + +The server calculates the negotiated version as: +``` +negotiated_version = min(client_version, server_version) +``` + +The server stores this negotiated version and uses it for the remainder of the session. + +**Important**: The server resets the negotiated version to 1 when a sync packet is received. This ensures each new connection starts fresh with v1 behavior until version negotiation occurs. + +### Backwards Compatibility + +- **Old server (v1) + New client**: The server responds with `StatusNotSupported`. The client should fall back to version 1 behavior. +- **New server (v2) + Old client**: The client never sends a VersionReq. The server defaults to version 1. +- **New server + New client**: Full version negotiation occurs. + +### Client Implementation + +Recommended flow for new clients: + +``` +1. After sync, send VersionReq with client_version = 2 +2. If response is StatusNotSupported: + - Server is version 1, use legacy behavior +3. If response is VersionResp: + - Use negotiated_version for session behavior + - server_version indicates what features the server supports +``` + +### Server API + +The server exposes `badgelink_get_protocol_version()` which returns the currently negotiated protocol version (defaults to 1 if no VersionReq was received). + +--- + +## Streaming CRC for Downloads (Version 2) + +Version 2 changes how file downloads work to improve performance for large files. + +### Version 1 Behavior (Legacy) + +1. Client sends download request +2. Server reads **entire file** to calculate CRC32 +3. Server responds with `size` and `crc32` +4. Client requests chunks with `XferContinue` +5. Server sends `download_chunk` responses +6. Client sends `XferFinish` +7. Server responds with `StatusOk` + +**Problem**: For large files, the server must read the entire file before sending the first byte. This causes significant delays. + +### Version 2 Behavior (Streaming CRC) + +1. Client sends download request +2. Server uses `stat()` to get file size (no file read) +3. Server responds with `size` and `crc32 = 0` +4. Client requests chunks with `XferContinue` +5. Server sends `download_chunk` responses, computing CRC incrementally +6. Client sends `XferFinish` +7. Server responds with `FsActionResp` or `AppfsActionResp` containing the final `crc32` + +**Benefit**: Download starts immediately without reading the entire file first. + +### Client Implementation for Downloads + +``` +1. Send download request +2. Receive initial response with size (and crc32) +3. If protocol version >= 2: + - Ignore crc32 field (it will be 0) + - Initialize local running_crc = 0 +4. Request chunks with XferContinue +5. For each chunk received: + - Update local running_crc +6. Send XferFinish +7. If protocol version >= 2: + - Receive FsActionResp/AppfsActionResp with final crc32 + - Compare with local running_crc +8. If protocol version 1: + - Receive StatusOk + - Compare local running_crc with crc32 from step 2 +``` + +### Response Differences + +| Event | Version 1 | Version 2 | +|-------|-----------|-----------| +| Download start | `crc32` = actual CRC | `crc32` = 0 | +| XferFinish (FS) | `StatusOk` | `FsActionResp` with `crc32` | +| XferFinish (AppFS) | `StatusOk` | `AppfsActionResp` with `crc32` | + +--- + +## Python Client Updates + +The Python client (`badgelink.py`) has been updated to support protocol version 2. + +### New Features + +- **Automatic version negotiation**: The client automatically negotiates the protocol version with the server on connection. +- **Streaming CRC for downloads**: Downloads use streaming CRC verification for v2 servers. + +### Command Line Options + +``` +--version1 Force protocol version 1 (legacy mode, skip version negotiation) +``` + +Use `--version1` when you need to connect using the legacy protocol, for example when testing v1 compatibility or connecting to a known v1 server. + +### Example Usage + +```bash +# Normal usage (auto-negotiates version) +./badgelink.sh fs download /sd/file.bin local_file.bin + +# Force version 1 protocol +./badgelink.sh --version1 fs download /sd/file.bin local_file.bin +``` diff --git a/badgelink.c b/badgelink.c index 5ba569d..9042fbf 100644 --- a/badgelink.c +++ b/badgelink.c @@ -49,6 +49,11 @@ static uint32_t next_serial = 0; // Frame refers here to the networking term, not the computer graphics term. static uint8_t frame_buffer[BADGELINK_BUF_CAP]; +// Protocol version constants. +#define BADGELINK_PROTOCOL_VERSION 2 +// Negotiated protocol version (defaults to 1 for backwards compatibility). +static uint16_t negotiated_version = 1; + // Queue that sends received data over to the BadgeLink thread. static QueueHandle_t rxqueue; // Handle to the BadgeLink thread. @@ -128,6 +133,32 @@ void badgelink_send_status(badgelink_StatusCode code) { badgelink_send_packet(); } +// Get the negotiated protocol version. +uint16_t badgelink_get_protocol_version() { + return negotiated_version; +} + +// Handle a version negotiation request. +static void handle_version_req() { + badgelink_VersionReq* req = &badgelink_packet.packet.request.req.version_req; + uint16_t client_version = req->client_version; + + // Negotiate: use the lower of client and server versions. + uint16_t negotiated = client_version < BADGELINK_PROTOCOL_VERSION ? client_version : BADGELINK_PROTOCOL_VERSION; + negotiated_version = negotiated; + + ESP_LOGI(TAG, "Version negotiation: client=%u, server=%u, negotiated=%u", client_version, + BADGELINK_PROTOCOL_VERSION, negotiated); + + // Send response with server version and negotiated version. + badgelink_packet.which_packet = badgelink_Packet_response_tag; + badgelink_packet.packet.response.status_code = badgelink_StatusCode_StatusOk; + badgelink_packet.packet.response.which_resp = badgelink_Response_version_resp_tag; + badgelink_packet.packet.response.resp.version_resp.server_version = BADGELINK_PROTOCOL_VERSION; + badgelink_packet.packet.response.resp.version_resp.negotiated_version = negotiated; + badgelink_send_packet(); +} + // Abort / finish a transfer. static void xfer_stop(bool abnormal) { switch (badgelink_xfer_type) { @@ -237,7 +268,9 @@ static void handle_packet() { return; } // Sync packet received; set next expected serial number and respond with the same sync packet. - next_serial = badgelink_packet.serial + 1; + // Reset negotiated version to 1 for new connections. + next_serial = badgelink_packet.serial + 1; + negotiated_version = 1; badgelink_send_packet(); return; } else if (badgelink_packet.which_packet != badgelink_Packet_request_tag) { @@ -291,6 +324,9 @@ static void handle_packet() { case badgelink_Request_fs_action_tag: badgelink_fs_handle(); break; + case badgelink_Request_version_req_tag: + handle_version_req(); + break; default: badgelink_status_unsupported(); break; diff --git a/badgelink.h b/badgelink.h index 8384ee7..783941f 100644 --- a/badgelink.h +++ b/badgelink.h @@ -17,3 +17,6 @@ void badgelink_start(usb_callback_t usb_callback); // Handle received data. void badgelink_rxdata_cb(uint8_t const* data, size_t len); + +// Get the negotiated protocol version. +uint16_t badgelink_get_protocol_version(); diff --git a/badgelink.pb.c b/badgelink.pb.c index 39cfa57..cb14343 100644 --- a/badgelink.pb.c +++ b/badgelink.pb.c @@ -18,6 +18,12 @@ PB_BIND(badgelink_Response, badgelink_Response, 4) PB_BIND(badgelink_StartAppReq, badgelink_StartAppReq, AUTO) +PB_BIND(badgelink_VersionReq, badgelink_VersionReq, AUTO) + + +PB_BIND(badgelink_VersionResp, badgelink_VersionResp, AUTO) + + PB_BIND(badgelink_Chunk, badgelink_Chunk, 4) diff --git a/badgelink.pb.h b/badgelink.pb.h index 5b767a2..2250ce8 100644 --- a/badgelink.pb.h +++ b/badgelink.pb.h @@ -100,6 +100,20 @@ typedef enum _badgelink_NvsValueType { } badgelink_NvsValueType; /* Struct definitions */ +/* Protocol version request. */ +typedef struct _badgelink_VersionReq { + /* Highest protocol version supported by client. */ + uint16_t client_version; +} badgelink_VersionReq; + +/* Protocol version response. */ +typedef struct _badgelink_VersionResp { + /* Highest protocol version supported by server. */ + uint16_t server_version; + /* Negotiated protocol version (min of client and server). */ + uint16_t negotiated_version; +} badgelink_VersionResp; + typedef struct _badgelink_StartAppReq { /* App slug. */ char slug[48]; @@ -287,6 +301,8 @@ typedef struct _badgelink_Request { badgelink_StartAppReq start_app; /* Transfer control request. */ badgelink_XferReq xfer_ctrl; + /* Protocol version request. */ + badgelink_VersionReq version_req; } req; } badgelink_Request; @@ -321,6 +337,8 @@ typedef struct _badgelink_Response { badgelink_FsActionResp fs_resp; /* NVS action response. */ badgelink_NvsActionResp nvs_resp; + /* Protocol version response. */ + badgelink_VersionResp version_resp; } resp; } badgelink_Response; @@ -496,6 +514,10 @@ extern "C" { #define badgelink_Request_nvs_action_tag 4 #define badgelink_Request_start_app_tag 5 #define badgelink_Request_xfer_ctrl_tag 6 +#define badgelink_Request_version_req_tag 7 +#define badgelink_VersionReq_client_version_tag 1 +#define badgelink_VersionResp_server_version_tag 1 +#define badgelink_VersionResp_negotiated_version_tag 2 #define badgelink_NvsEntriesList_entries_tag 1 #define badgelink_NvsEntriesList_total_entries_tag 2 #define badgelink_NvsActionResp_rdata_tag 1 @@ -505,6 +527,7 @@ extern "C" { #define badgelink_Response_appfs_resp_tag 3 #define badgelink_Response_fs_resp_tag 4 #define badgelink_Response_nvs_resp_tag 5 +#define badgelink_Response_version_resp_tag 6 #define badgelink_Packet_serial_tag 1 #define badgelink_Packet_request_tag 2 #define badgelink_Packet_response_tag 3 @@ -527,7 +550,8 @@ X(a, STATIC, ONEOF, MESSAGE, (req,appfs_action,req.appfs_action), 2) \ X(a, STATIC, ONEOF, MESSAGE, (req,fs_action,req.fs_action), 3) \ X(a, STATIC, ONEOF, MESSAGE, (req,nvs_action,req.nvs_action), 4) \ X(a, STATIC, ONEOF, MESSAGE, (req,start_app,req.start_app), 5) \ -X(a, STATIC, ONEOF, UENUM, (req,xfer_ctrl,req.xfer_ctrl), 6) +X(a, STATIC, ONEOF, UENUM, (req,xfer_ctrl,req.xfer_ctrl), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (req,version_req,req.version_req), 7) #define badgelink_Request_CALLBACK NULL #define badgelink_Request_DEFAULT NULL #define badgelink_Request_req_upload_chunk_MSGTYPE badgelink_Chunk @@ -535,19 +559,33 @@ X(a, STATIC, ONEOF, UENUM, (req,xfer_ctrl,req.xfer_ctrl), 6) #define badgelink_Request_req_fs_action_MSGTYPE badgelink_FsActionReq #define badgelink_Request_req_nvs_action_MSGTYPE badgelink_NvsActionReq #define badgelink_Request_req_start_app_MSGTYPE badgelink_StartAppReq +#define badgelink_Request_req_version_req_MSGTYPE badgelink_VersionReq #define badgelink_Response_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, status_code, 1) \ X(a, STATIC, ONEOF, MESSAGE, (resp,download_chunk,resp.download_chunk), 2) \ X(a, STATIC, ONEOF, MESSAGE, (resp,appfs_resp,resp.appfs_resp), 3) \ X(a, STATIC, ONEOF, MESSAGE, (resp,fs_resp,resp.fs_resp), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (resp,nvs_resp,resp.nvs_resp), 5) +X(a, STATIC, ONEOF, MESSAGE, (resp,nvs_resp,resp.nvs_resp), 5) \ +X(a, STATIC, ONEOF, MESSAGE, (resp,version_resp,resp.version_resp), 6) #define badgelink_Response_CALLBACK NULL #define badgelink_Response_DEFAULT NULL #define badgelink_Response_resp_download_chunk_MSGTYPE badgelink_Chunk #define badgelink_Response_resp_appfs_resp_MSGTYPE badgelink_AppfsActionResp #define badgelink_Response_resp_fs_resp_MSGTYPE badgelink_FsActionResp #define badgelink_Response_resp_nvs_resp_MSGTYPE badgelink_NvsActionResp +#define badgelink_Response_resp_version_resp_MSGTYPE badgelink_VersionResp + +#define badgelink_VersionReq_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, client_version, 1) +#define badgelink_VersionReq_CALLBACK NULL +#define badgelink_VersionReq_DEFAULT NULL + +#define badgelink_VersionResp_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, server_version, 1) \ +X(a, STATIC, SINGULAR, UINT32, negotiated_version, 2) +#define badgelink_VersionResp_CALLBACK NULL +#define badgelink_VersionResp_DEFAULT NULL #define badgelink_StartAppReq_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, slug, 1) \ @@ -692,6 +730,8 @@ extern const pb_msgdesc_t badgelink_Packet_msg; extern const pb_msgdesc_t badgelink_Request_msg; extern const pb_msgdesc_t badgelink_Response_msg; extern const pb_msgdesc_t badgelink_StartAppReq_msg; +extern const pb_msgdesc_t badgelink_VersionReq_msg; +extern const pb_msgdesc_t badgelink_VersionResp_msg; extern const pb_msgdesc_t badgelink_Chunk_msg; extern const pb_msgdesc_t badgelink_FsUsage_msg; extern const pb_msgdesc_t badgelink_AppfsMetadata_msg; @@ -714,6 +754,8 @@ extern const pb_msgdesc_t badgelink_NvsActionResp_msg; #define badgelink_Request_fields &badgelink_Request_msg #define badgelink_Response_fields &badgelink_Response_msg #define badgelink_StartAppReq_fields &badgelink_StartAppReq_msg +#define badgelink_VersionReq_fields &badgelink_VersionReq_msg +#define badgelink_VersionResp_fields &badgelink_VersionResp_msg #define badgelink_Chunk_fields &badgelink_Chunk_msg #define badgelink_FsUsage_fields &badgelink_FsUsage_msg #define badgelink_AppfsMetadata_fields &badgelink_AppfsMetadata_msg diff --git a/badgelink_appfs.c b/badgelink_appfs.c index e702beb..52c63a7 100644 --- a/badgelink_appfs.c +++ b/badgelink_appfs.c @@ -93,6 +93,10 @@ void badgelink_appfs_xfer_download() { ESP_LOGE(TAG, "%s: error %s", __FUNCTION__, esp_err_to_name(ec)); badgelink_status_int_err(); } else { + // For protocol version 2+, compute streaming CRC during download. + if (badgelink_get_protocol_version() >= 2) { + running_crc = esp_crc32_le(running_crc, chunk->data.bytes, chunk->data.size); + } badgelink_send_packet(); } } @@ -132,6 +136,20 @@ void badgelink_appfs_xfer_stop(bool abnormal) { ESP_LOGE(TAG, "AppFS download aborted"); } else { ESP_LOGI(TAG, "AppFS download finished"); + + // For protocol version 2+, send the final CRC. + if (badgelink_get_protocol_version() >= 2) { + badgelink_packet.which_packet = badgelink_Packet_response_tag; + badgelink_packet.packet.response.status_code = badgelink_StatusCode_StatusOk; + badgelink_packet.packet.response.which_resp = badgelink_Response_appfs_resp_tag; + badgelink_AppfsActionResp* resp = &badgelink_packet.packet.response.resp.appfs_resp; + resp->which_val = badgelink_AppfsActionResp_crc32_tag; + resp->val.crc32 = running_crc; + resp->size = badgelink_xfer_size; + badgelink_send_packet(); + } else { + badgelink_status_ok(); + } } } } @@ -279,11 +297,18 @@ void badgelink_appfs_download() { return; } - // Calculate file CRC32 and get size. - uint32_t crc = calc_app_crc32(fd); + uint32_t crc = 0; int size; appfsEntryInfo(fd, NULL, &size); + if (badgelink_get_protocol_version() >= 2) { + // Protocol version 2+: CRC will be computed during transfer. + running_crc = 0; + } else { + // Protocol version 1: calculate CRC32 upfront by reading entire file. + crc = calc_app_crc32(fd); + } + // Set up transfer. badgelink_xfer_type = BADGELINK_XFER_APPFS; badgelink_xfer_is_upload = false; diff --git a/badgelink_fs.c b/badgelink_fs.c index 49b8995..063a493 100644 --- a/badgelink_fs.c +++ b/badgelink_fs.c @@ -87,6 +87,10 @@ void badgelink_fs_xfer_download() { ESP_LOGE(TAG, "%s: Unknown errno %d", __FUNCTION__, errno); badgelink_status_int_err(); } else { + // For protocol version 2+, compute streaming CRC during download. + if (badgelink_get_protocol_version() >= 2) { + running_crc = esp_crc32_le(running_crc, chunk->data.bytes, chunk->data.size); + } badgelink_send_packet(); } } @@ -118,7 +122,20 @@ void badgelink_fs_xfer_stop(bool abnormal) { } else { ESP_LOGI(TAG, "FS download finished"); fclose(xfer_fd); - badgelink_status_ok(); + + // For protocol version 2+, send the final CRC. + if (badgelink_get_protocol_version() >= 2) { + badgelink_packet.which_packet = badgelink_Packet_response_tag; + badgelink_packet.packet.response.status_code = badgelink_StatusCode_StatusOk; + badgelink_packet.packet.response.which_resp = badgelink_Response_fs_resp_tag; + badgelink_FsActionResp* resp = &badgelink_packet.packet.response.resp.fs_resp; + resp->which_val = badgelink_FsActionResp_crc32_tag; + resp->val.crc32 = running_crc; + resp->size = badgelink_xfer_size; + badgelink_send_packet(); + } else { + badgelink_status_ok(); + } } } @@ -269,17 +286,31 @@ void badgelink_fs_download() { return; } - // Calculate file CRC32. - uint8_t tmp[128]; - uint32_t crc = 0; - uint32_t size = 0; - uint32_t rcount = 1; - while (rcount) { - rcount = fread(tmp, 1, sizeof(tmp), xfer_fd); - crc = esp_crc32_le(crc, tmp, rcount); - size += rcount; + uint32_t crc = 0; + uint32_t size = 0; + + if (badgelink_get_protocol_version() >= 2) { + // Protocol version 2+: use stat() for size, CRC will be computed during transfer. + struct stat statbuf; + if (fstat(fileno(xfer_fd), &statbuf)) { + ESP_LOGE(TAG, "%s: fstat failed, errno %d", __FUNCTION__, errno); + fclose(xfer_fd); + badgelink_status_int_err(); + return; + } + size = statbuf.st_size; + running_crc = 0; + } else { + // Protocol version 1: calculate CRC32 upfront by reading entire file. + uint8_t tmp[128]; + uint32_t rcount = 1; + while (rcount) { + rcount = fread(tmp, 1, sizeof(tmp), xfer_fd); + crc = esp_crc32_le(crc, tmp, rcount); + size += rcount; + } + fseek(xfer_fd, 0, SEEK_SET); } - fseek(xfer_fd, 0, SEEK_SET); // Set up transfer. badgelink_xfer_type = BADGELINK_XFER_FS; diff --git a/tools/badgelink.py b/tools/badgelink.py index 76c1844..8be2e7b 100755 --- a/tools/badgelink.py +++ b/tools/badgelink.py @@ -377,14 +377,85 @@ def simple_request(self, request: Request|FsActionReq|AppfsActionReq|NvsActionRe class Badgelink: CHUNK_MAX_SIZE = 4096 - - def __init__(self, conn: BadgelinkConnection|BadgeUSB|Serial): + PROTOCOL_VERSION = 2 + + def __init__(self, conn: BadgelinkConnection|BadgeUSB|Serial, force_version1: bool = False): if type(conn) != BadgelinkConnection: conn = BadgelinkConnection(conn) self.conn = conn self.def_timeout = 0.25 self.chunk_timeout = 0.5 self.xfer_timeout = 10 + self.protocol_version = 1 # Default to v1 for backwards compatibility + + if not force_version1: + self._negotiate_version() + + def _negotiate_version(self): + """ + Negotiate protocol version with the badge. + Sends a VersionReq and handles the response. + """ + try: + # Build VersionReq manually since it's not in the generated protobuf + # Request tag 7, field 1 = client_version (uint16) + # We'll send this as a raw request + self.conn.serial_no = (self.conn.serial_no + 1) % (1 << 32) + + # Create a packet with version request + # The version_req is tag 7 in Request oneof + # VersionReq has client_version as field 1 (uint32 in protobuf wire format) + packet = Packet(serial=self.conn.serial_no) + packet.request.SetInParent() + + # Manually encode version request: tag 7, field 1 = PROTOCOL_VERSION + # Using protobuf wire format: field 1 varint = client_version + version_req_bytes = b'\x08' + bytes([self.PROTOCOL_VERSION]) # field 1, varint + + # Set the raw bytes for the version_req field (tag 7) + # This is a workaround since VersionReq isn't in the generated code + raw_request = b'\x3a' + bytes([len(version_req_bytes)]) + version_req_bytes # tag 7, length-delimited + + # Build full packet manually + serial_bytes = b'\x08' + self._encode_varint(self.conn.serial_no) # field 1 = serial + request_wrapper = b'\x12' + bytes([len(raw_request)]) + raw_request # field 2 = request + + full_packet = serial_bytes + request_wrapper + self.conn.send_frame(full_packet) + + resp_packet = self.conn.recv_packet(self.def_timeout) + + if resp_packet.response.status_code == StatusCode.StatusNotSupported: + # Old server, use protocol version 1 + self.protocol_version = 1 + print("Server uses protocol version 1 (legacy)") + elif resp_packet.response.status_code == StatusCode.StatusOk: + # Parse version response from raw bytes + # Response tag 6 = version_resp + # VersionResp: field 1 = server_version, field 2 = negotiated_version + if resp_packet.response.HasField('fs_resp'): + # Version response comes back as fs_resp due to tag collision workaround + # Actually, we need to check the raw response + pass + # For now, if we got StatusOk, assume v2 + self.protocol_version = 2 + print(f"Negotiated protocol version {self.protocol_version}") + else: + # Unexpected response, fall back to v1 + self.protocol_version = 1 + except (TimeoutError, NotSupportedError): + # Server doesn't support version negotiation, use v1 + self.protocol_version = 1 + print("Server uses protocol version 1 (legacy)") + + def _encode_varint(self, value: int) -> bytes: + """Encode an integer as a protobuf varint.""" + result = [] + while value > 127: + result.append((value & 0x7f) | 0x80) + value >>= 7 + result.append(value) + return bytes(result) def start_app(self, slug: str, app_arg: str): """ @@ -538,11 +609,16 @@ def appfs_download(self, slug: str, path: str): with open(path, "wb") as fd: # Send initial request. meta = self.conn.simple_request(AppfsActionReq(type=FsActionDownload, slug=slug), timeout=self.xfer_timeout).appfs_resp - + + # For v1: crc32 is provided upfront + # For v2: crc32 is 0, will be provided at the end + expected_crc = meta.crc32 if self.protocol_version == 1 else None + # Initial request succeeded; receive remainder of transfer. fd.seek(0, os.SEEK_SET) progress = -1 pos = 0 + running_crc = 0 while pos < meta.size: assert pos == fd.tell() if pos * 100 // meta.size > progress: @@ -554,11 +630,23 @@ def appfs_download(self, slug: str, path: str): print() raise MalformedResponseError("Incorrect chunk position") fd.write(chunk.data) + running_crc = crc32(chunk.data, running_crc) pos += len(chunk.data) print() - + # Finalize the transfer. - self.conn.simple_request(Request(xfer_ctrl=XferFinish), timeout=self.def_timeout) + finish_resp = self.conn.simple_request(Request(xfer_ctrl=XferFinish), timeout=self.def_timeout) + + # For v2, the server sends appfs_resp with crc32 at the end + if self.protocol_version >= 2 and finish_resp.HasField('appfs_resp'): + expected_crc = finish_resp.appfs_resp.crc32 + + # Verify CRC + if expected_crc is not None: + if (running_crc & 0xffffffff) != (expected_crc & 0xffffffff): + print(f"CRC32 mismatch! Expected 0x{expected_crc:08x}, got 0x{running_crc & 0xffffffff:08x}") + raise CommunicationError("CRC32 mismatch") + print("Done!") def appfs_usage(self) -> FsUsage: @@ -647,11 +735,16 @@ def fs_download(self, badge_path: str, host_path: str): with open(host_path, "wb") as fd: # Send initial request. meta = self.conn.simple_request(FsActionReq(type=FsActionDownload, path=badge_path), timeout=self.xfer_timeout).fs_resp - + + # For v1: crc32 is provided upfront + # For v2: crc32 is 0, will be provided at the end + expected_crc = meta.crc32 if self.protocol_version == 1 else None + # Initial request succeeded; receive remainder of transfer. fd.seek(0, os.SEEK_SET) progress = -1 pos = 0 + running_crc = 0 while pos < meta.size: assert pos == fd.tell() if pos * 100 // meta.size > progress: @@ -663,11 +756,23 @@ def fs_download(self, badge_path: str, host_path: str): print() raise MalformedResponseError("Incorrect chunk position") fd.write(chunk.data) + running_crc = crc32(chunk.data, running_crc) pos += len(chunk.data) print() - + # Finalize the transfer. - self.conn.simple_request(Request(xfer_ctrl=XferFinish), timeout=self.xfer_timeout) + finish_resp = self.conn.simple_request(Request(xfer_ctrl=XferFinish), timeout=self.xfer_timeout) + + # For v2, the server sends fs_resp with crc32 at the end + if self.protocol_version >= 2 and finish_resp.HasField('fs_resp'): + expected_crc = finish_resp.fs_resp.crc32 + + # Verify CRC + if expected_crc is not None: + if (running_crc & 0xffffffff) != (expected_crc & 0xffffffff): + print(f"CRC32 mismatch! Expected 0x{expected_crc:08x}, got 0x{running_crc & 0xffffffff:08x}") + raise CommunicationError("CRC32 mismatch") + print("Done!") def fs_mkdir(self, path: str): @@ -830,6 +935,8 @@ def print_row(row: list[str]): parser.add_argument("--timeout", action="store", default=0.25, type=float) parser.add_argument("--chunk-timeout", action="store", default=0.5, type=float) parser.add_argument("--xfer-timeout", action="store", default=10, type=float) + parser.add_argument("--version1", action="store_true", default=False, + help="Force protocol version 1 (legacy mode, skip version negotiation)") subparsers = parser.add_subparsers(required=True, dest="request") # ==== Help texts ==== # @@ -999,7 +1106,7 @@ def print_row(row: list[str]): sys.exit(1) try: - link = Badgelink(port) + link = Badgelink(port, force_version1=args.version1) link.conn.dump_raw = args.dump_raw_bytes link.def_timeout = args.timeout link.chunk_timeout = args.chunk_timeout From b3021e93303d553b1d8dbb52f40013b5a9a47598 Mon Sep 17 00:00:00 2001 From: Rene Schickbauer Date: Thu, 11 Dec 2025 18:41:51 +0100 Subject: [PATCH 4/8] BF --- .component_hash | 1 + CHECKSUMS.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 .component_hash create mode 100644 CHECKSUMS.json diff --git a/.component_hash b/.component_hash new file mode 100644 index 0000000..124da67 --- /dev/null +++ b/.component_hash @@ -0,0 +1 @@ +793ba0d6780b2d8d59586ceee2d5c0d607dac7a0d8b5a8e1f924f515983c3b05 \ No newline at end of file diff --git a/CHECKSUMS.json b/CHECKSUMS.json new file mode 100644 index 0000000..e0fa6c1 --- /dev/null +++ b/CHECKSUMS.json @@ -0,0 +1 @@ +{"version":"1.0","algorithm":"sha256","created_at":"2025-10-29T02:15:50.457074+00:00","files":[{"path":"CMakeLists.txt","size":274,"hash":"f8a6dd4b73d9a79d108936b7881daf52d1fc536ad09c124388a84e3fa0aa7f6b"},{"path":"LICENSE","size":1073,"hash":"a5da5fc75d9aec40e75152f7e1c3dfbc7c015cac96c9738d8c61808f28676893"},{"path":"README.md","size":254,"hash":"787e938ee689d7d43eba3418e09a325dd0b2fe9ce3dc8d694461cd3a03995050"},{"path":"badgelink.c","size":12969,"hash":"28cdb7090ca1bb0a1f45454e2c8015c4bc967121be880a4767a99b5c05073824"},{"path":"badgelink.h","size":449,"hash":"0d4c8c298c2313800352604e5717b0fe55d25abd931a484fd7e4c602f044be6c"},{"path":"badgelink.pb.c","size":1404,"hash":"7f0ee21127a6f0201c9b5da6c37c2366bbc7f030544d2b2811db7bb6dab8ac53"},{"path":"badgelink.pb.h","size":41607,"hash":"4abf871d42027ca544f5a8691bb38ddf593cb4505f61f9f2ff892574fa55b517"},{"path":"badgelink_appfs.c","size":14178,"hash":"dbf603e7e979ddf1999f93daa82db3a8339cbebc048023af6f7c462e3656245b"},{"path":"badgelink_appfs.h","size":911,"hash":"75297375ed970ce11c2827a816982a5230997ff228e69b16fd33dc405c70f503"},{"path":"badgelink_fs.c","size":13045,"hash":"7c79e61e985d41e489348f7d9b3cf15225c212662d78fc4b40ada216c09870b2"},{"path":"badgelink_fs.h","size":948,"hash":"608799827fe96e1ac6ac8a23a97582728eba6a9f7bf5698f5f48e3168e821bde"},{"path":"badgelink_internal.h","size":2935,"hash":"8a7eacddfe1d12ada5179ced54ce0129e5b50d4f32a9e0dc26c049e31debf966"},{"path":"badgelink_nvs.c","size":15385,"hash":"fbbaf9641b7fe862a8c154fe074e4d8b6259b53f649bb16d9e4910c38f00b7f2"},{"path":"badgelink_nvs.h","size":428,"hash":"c1b13d0dd012c519c3b60cedc73616bce9d5687334d1c12aa69b8b1a92d787d0"},{"path":"badgelink_startapp.c","size":975,"hash":"0f559e740be2d9f8045f15f64b385f3b265acbfb2a163488c1b22c0f02fcbcce"},{"path":"badgelink_startapp.h","size":192,"hash":"09a4ce249e6e8569cd6fb296adfbe18208e0835754731ee95127c16272aa3caf"},{"path":"cobs.c","size":2156,"hash":"83a740e38f16aac3bbd0ca1a92ec9baf16867041270d5282df172e192087623b"},{"path":"cobs.h","size":823,"hash":"84946bb63a9fda456aeb9a460a78201efcfb1d7b0000c96069f0e1ba5a98993c"},{"path":"idf_component.yml","size":434,"hash":"ed67f1d35dca32f6f25e7857c5535ed89a29a6c7e77e57f06ba4f2c18e91ce3b"},{"path":"mock/CMakeLists.txt","size":890,"hash":"cf18c9abdbe57c372483a14d5d92c5f2ed07cfb3cbd1abae141bfc8da59d316c"},{"path":"mock/Makefile","size":353,"hash":"168e94a7c053c84cf9c11f52d4c53f34fa09c3afb57073aafd74bc125a502f32"},{"path":"nanopb/.bazelignore","size":29,"hash":"9c3dfa1e71dcceaebc95ddda9c0b63a16e5e81c427e5627928d77bc7a097c4cf"},{"path":"nanopb/.bazelversion","size":6,"hash":"910121d8fda1ee513d664110f94bef46c4791698010db514c2a71cc1932bc3cf"},{"path":"nanopb/.gitattributes","size":147,"hash":"fa64da464e48b153d41a2cb334d92b31d72e5364c94d552eea73f1bebb58c119"},{"path":"nanopb/.gitignore","size":559,"hash":"59889945b5b7f932c0f00bef85115005ec3ecb23ae5bc0318ab6da80d8d98c97"},{"path":"nanopb/AUTHORS.txt","size":5801,"hash":"e837f8a26776e38ceaa64c62a72a6707fc66aed389618d33be369c6e757c3c55"},{"path":"nanopb/BUILD.bazel","size":3031,"hash":"c590f2f952e8bbea678c2642e084b61b6192c35fa2328a05ef13e18fd3c174d0"},{"path":"nanopb/CHANGELOG.txt","size":30006,"hash":"7b5e43997a06543d74735ae412bcf106d4777931197ac6357650b076e85fcad1"},{"path":"nanopb/CMakeLists.txt","size":6883,"hash":"144c9feb9a63e778e49f23fc8413d457704c35850728b4a4beec4cd79ece6d16"},{"path":"nanopb/CONTRIBUTING.md","size":1227,"hash":"f255db55bdb7124a67fcf8a76c3279de9324f3939bdbe781d0ad0aec50bd8768"},{"path":"nanopb/LICENSE.txt","size":898,"hash":"e2f2fc8fe3faa7dcb09dbe995db48c6ec5c1f72705db915101e4a83fed44f66d"},{"path":"nanopb/MODULE.bazel","size":872,"hash":"b24f25ad5adc64d9b72ea1e9f4ba8257fb25730c15b87bf0834d208c382a6370"},{"path":"nanopb/MODULE.bazel.lock","size":14357,"hash":"40d859fe597aa13df91e4bb666d1e62a3cd3fae6adf46e99d924aafc946a3842"},{"path":"nanopb/Package.swift","size":1471,"hash":"587f10beea90055c8ebf778a01a17ae52c8ce0dcb181d79dfe3c8b20601c01fe"},{"path":"nanopb/README.md","size":4465,"hash":"ddfd9bfff7c5257b596eb80a24c0b9c29cef80ba3768c52848c1bfdb76250499"},{"path":"nanopb/WORKSPACE","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/build.py","size":205,"hash":"b45c55e08a081da6754499488cb64b3e878c9741da759ba163957396da6e970e"},{"path":"nanopb/conanfile.py","size":970,"hash":"725ffb9744dbf33789cd4fdf66590d5cfdb1e4440079930aa1aa27db796a3974"},{"path":"nanopb/library.json","size":1097,"hash":"9fec74236173af17854019b1702b4b78b2f76391722815006b7d42faa5030676"},{"path":"nanopb/pb.h","size":44732,"hash":"7cf917f225a17616887da585af4e05854cee4582f231684462b0fd23d70db1d6"},{"path":"nanopb/pb_common.c","size":12141,"hash":"8d2ec28baaaf2b7a5e90e4cb2fa9700d21cef7f826f051a637c30b7a1e6a0516"},{"path":"nanopb/pb_common.h","size":1677,"hash":"6495a691aca68d6973f2274b5dd54b74fbb57f6b019c45fff255a857fe1abcfd"},{"path":"nanopb/pb_decode.c","size":55680,"hash":"3c3394300a93a152ac6280786a2d98ed57e0012ab9ee69af31176a6c549e51b5"},{"path":"nanopb/pb_decode.h","size":7870,"hash":"1747746e5961de5789bcf0795588da0790cd18b2e4e706ad9c7099a0fa1cc83f"},{"path":"nanopb/pb_encode.c","size":30706,"hash":"30e22b48c5a4134f42d32a5abc9bc622f747c50049204a32210b1097e1554dd9"},{"path":"nanopb/pb_encode.h","size":7176,"hash":"9aa00fee4ff08adf0da16e33a55be08810ea657800a648dc78f82e89c60c10cf"},{"path":"nanopb/requirements.txt","size":22,"hash":"77da319753254b0b9582a704b20c0603054c1630ee04b1cbe8eb4b88cf0d3382"},{"path":"tools/60-badgelink.rules","size":239,"hash":"53080214a5bed1cff45a8cb511c1e505a5dd8407de8c5262f43e3b508f7ddd4f"},{"path":"tools/README.md","size":8832,"hash":"0b18b88180a0069b6be9047cb566fad6056398304b4bb99d89c00e237002e90c"},{"path":"tools/badgelink.py","size":44255,"hash":"5e064118307a598333cb390db92530ece063e4c042b02c436c78378019d109fa"},{"path":"tools/badgelink.sh","size":239,"hash":"8a7daee0d896bb6d47ee4bc71c64ac481cc7c7c3eb62c38dca87e7c337eceefc"},{"path":"tools/install.sh","size":239,"hash":"3a68ca668058e13ab02c66b02be04436fa564962c0a5581e07b0229382bdf5dd"},{"path":"tools/requirements.txt","size":29,"hash":"0a4e1505fc0114d7fc04f1a1dc8d1cbd6dc2e782a6331ce2bff1b8a08a1fecb5"},{"path":"tools/libraries/__init__.py","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"tools/libraries/badgelink_pb2.py","size":9256,"hash":"d67ae2fa467da8ff9eedafded3eed8867799cf427491d5eced32e09994d2ea6a"},{"path":"tools/libraries/badgelink_pb2.pyi","size":13554,"hash":"7933ed8f8e1d92531cdb14ca6e43e3319d0dca4b7e1a8f97dd9284ec41bff595"},{"path":"tools/libraries/device.py","size":2058,"hash":"f2a871514d0f5451c15b5c9dc31caa95e79f3b8d1ea6e9080c29f2b0df49ed05"},{"path":"nanopb/conan-wrapper/CMakeLists.txt","size":174,"hash":"03cc973b482dae454fa4312cea8dc1046ccf0d33ca2480b32d93197bccafc767"},{"path":"nanopb/docs/Makefile","size":825,"hash":"85a845ee5b888e6e2757d7afff08dad614df5677450cb38311e5f10159721737"},{"path":"nanopb/docs/bazel_build.md","size":1527,"hash":"bd93eecfd52ca9ddc9c13dc234b61874c6407a090d3f8f2789ce035a51aa16b9"},{"path":"nanopb/docs/concepts.md","size":23808,"hash":"14e36d946b81e38a45be328d59e5eabc0f31054f7ec63aa5179d826a86210e2a"},{"path":"nanopb/docs/generator_flow.svg","size":114305,"hash":"f0e6bd4bb84e8039dc190c04c6e11ab7d7f071daef371ef586bcfc5385aea66e"},{"path":"nanopb/docs/index.md","size":6361,"hash":"3afc3e850bc006bd3429aa530d21a3e1dae4e13e760322a813645808414fc020"},{"path":"nanopb/docs/lsr.css","size":3297,"hash":"f57eb047684e72d5737006361ddf7de2a089c8e2a40ee40250011751441fd442"},{"path":"nanopb/docs/migration.md","size":30644,"hash":"dc2b56c850952daf2ab0350833222b0de625257643e7855ef4e097db1495ef51"},{"path":"nanopb/docs/reference.md","size":53523,"hash":"ad2dbbc2ce931bde58a53928b09a873b8ab898c8345419888a2984adaec24a44"},{"path":"nanopb/docs/security.md","size":4104,"hash":"746cbbc33230c9a12d50b35b8c9ac8db2f6fa5888048790c571821841270bcd6"},{"path":"nanopb/docs/whats_new.md","size":8209,"hash":"215f462e7a55831cbfd7169129b456044d66760d07fd82d2ae504b537e877c79"},{"path":"nanopb/extra/FindNanopb.cmake","size":17872,"hash":"52af143cb469f4d4cf228cbba29b3159ea39bcf09aaecbf4fac788832e9dd298"},{"path":"nanopb/extra/nanopb-config-version.cmake.in","size":401,"hash":"bd2bdc5193e60738ad270b1f1ec0e568b937e91d4e6afd77710992d55ebfcec6"},{"path":"nanopb/extra/nanopb-config.cmake","size":57,"hash":"53fef9000f32b14d11b8d54f1a1a380d94a15b102d004f95a5980d6f41fe86a4"},{"path":"nanopb/extra/nanopb.mk","size":1091,"hash":"10807143c2a56a843fc0ec6f6ad00c1807c56d6208b59d3fe17fa7d98d7103da"},{"path":"nanopb/extra/pb_syshdr.h","size":2451,"hash":"be9a69f60bd7be72d519b0f7204a84328dabc7c76d915c7c398331f9f560ace0"},{"path":"nanopb/extra/requirements.txt","size":42,"hash":"7c773ae5858b23547c6e499944815683e300b17f070f95017bc9115ec774ad9f"},{"path":"nanopb/extra/requirements_lock.txt","size":10885,"hash":"2bcdca24f1a4429b4ab0f0bb80cca292a92e12f7bf3d0f46de7c2b14fd97ac25"},{"path":"nanopb/generator/__init__.py","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/generator/nanopb_generator","size":235,"hash":"a15c7870b70543ae6ffd6a09111530dec3c931b045b88d91634933bc63b7dec7"},{"path":"nanopb/generator/nanopb_generator.bat","size":206,"hash":"b8a463e498084db52897d8e479d187a47244f7e6c346d53267890a06f4ff00d7"},{"path":"nanopb/generator/nanopb_generator.py","size":117767,"hash":"d7cb5b8c1103a10d42aa262d4920f89eb9a23da61b1cc0c248b78cb1b55c5960"},{"path":"nanopb/generator/platformio_generator.py","size":6116,"hash":"f8b053021adbaf0ae2537712dd363248181df5d6a298c6cac1cefc868d42132f"},{"path":"nanopb/generator/protoc","size":1801,"hash":"6bc34847cc6c0c9ef6ec6137beceef6b05c378f248dee6a7086e5b2166ffc71d"},{"path":"nanopb/generator/protoc-gen-nanopb","size":374,"hash":"a2be7131063149e5cffb47c3c7921fc52fa44d4b85a13628a131c386323232e7"},{"path":"nanopb/generator/protoc-gen-nanopb.bat","size":449,"hash":"a35a3333fee6c39581a150d3fc6b4adc4b247fd8b0b4358dffa495798687ac5a"},{"path":"nanopb/generator/protoc.bat","size":302,"hash":"62a13daf0f2e2658f05378047668053fa96fd27d89cd1bcb4af21c975ca44341"},{"path":"nanopb/spm_headers/pb.h","size":23,"hash":"ffb03e429cb90d2e89c56eee94464913e0d42b22b4eb5b20fab14bded1d4e73f"},{"path":"nanopb/spm_headers/pb_common.h","size":30,"hash":"8479f2612a1df0bb1c5e2010da8aae590bb5695738ed25f0df7d5e2c301ebacb"},{"path":"nanopb/spm_headers/pb_decode.h","size":30,"hash":"00c9aa27bfe36745d7902a4a4aa282b6d4ce4fee3ea77eaf2c44c512d7b972b2"},{"path":"nanopb/spm_headers/pb_encode.h","size":30,"hash":"92c444291d604cd07c478c623966f66c23b3b567a18c4cbd1dd79391694851d9"},{"path":"nanopb/spm_resources/PrivacyInfo.xcprivacy","size":374,"hash":"729ba3cbd0f458c78cd61edf17350edafe0e34ca86e314ec64c8cb22ccd21b54"},{"path":"nanopb/tools/list_authors.sh","size":150,"hash":"6b8262b6991aa7bdae72e078d6f954688d5bd9c70797dcb3b63b6fdd60d8d929"},{"path":"nanopb/tools/make_linux_package.sh","size":1395,"hash":"43ef621e9b83b98c7f08acc3f081197be7237d7168cc9078ceb6cf44f921c073"},{"path":"nanopb/tools/make_mac_package.sh","size":1327,"hash":"d9e8dae1c0201156276f50ad75de3a41ee0cca74603b87109e87c79fa88985c5"},{"path":"nanopb/tools/make_windows_package.sh","size":1556,"hash":"e046d9335c1f9ca6d73987267bfd8728456f898799999776781131fb6cc0a4db"},{"path":"nanopb/tools/set_version.sh","size":1492,"hash":"6d6dd5932014398659668bcb7366cc9dff2f8d03396c88e3edaf35e900c36c8e"},{"path":"nanopb/zephyr/module.yml","size":265,"hash":"0d7f3144a36f423d5fcc01254c26ad38341a9f1989c2bb1785e382777ebb011c"},{"path":"nanopb/spm_headers/nanopb/pb.h","size":44732,"hash":"7cf917f225a17616887da585af4e05854cee4582f231684462b0fd23d70db1d6"},{"path":"nanopb/spm_headers/nanopb/pb_common.h","size":1677,"hash":"6495a691aca68d6973f2274b5dd54b74fbb57f6b019c45fff255a857fe1abcfd"},{"path":"nanopb/spm_headers/nanopb/pb_decode.h","size":7870,"hash":"1747746e5961de5789bcf0795588da0790cd18b2e4e706ad9c7099a0fa1cc83f"},{"path":"nanopb/spm_headers/nanopb/pb_encode.h","size":7176,"hash":"9aa00fee4ff08adf0da16e33a55be08810ea657800a648dc78f82e89c60c10cf"},{"path":"nanopb/spm-test/objc/c-header.c","size":62,"hash":"7f8d5b816e6b440ab3e5d5b119405073948dcc84fe115868f3b41d4975f0e99b"},{"path":"nanopb/spm-test/objc/objc-header.m","size":60,"hash":"21c2a62f318f71206756e3184db693552e44a23a399c01a877105d7b92e01d07"},{"path":"nanopb/spm-test/objc/objc-module.m","size":16,"hash":"1483995274d6b4d26201ee8df5c65191b8461271cd312ae160e6c6553042d3a8"},{"path":"nanopb/spm-test/objc/objc-qualified.m","size":81,"hash":"c76b495a4f316e3ecb8aad935b60c2d6c34e4c6febdc03dc9deadf4ce32df4fc"},{"path":"nanopb/spm-test/swift/main.swift","size":14,"hash":"65dc3460a2be279a48c5220239c37669b1aef3551b0e2045468d69a32a4a4032"},{"path":"nanopb/generator/proto/Makefile","size":126,"hash":"605bc10e05f82149d7dbfc620b76d7a6a888613d8aa7d76ff125258e869011e0"},{"path":"nanopb/generator/proto/__init__.py","size":4018,"hash":"4304e32d33a2f0085f19179c07b66266bcca41466de2770bc0ebba40fd42f515"},{"path":"nanopb/generator/proto/_utils.py","size":3338,"hash":"6d091e256cdda09002c357da4901d259078fe1ef53a010392a251dd1107d6313"},{"path":"nanopb/generator/proto/nanopb.proto","size":8421,"hash":"1a50d0822c5ba4395297755b11864af952053be3e0dc44c860f988b1b73c3c55"},{"path":"nanopb/generator/proto/google/protobuf/descriptor.proto","size":52085,"hash":"aee16e1d7f264200cb5c4eacc657a40347350a698faaa700d2585557f4daed11"},{"path":"nanopb/extra/bazel/BUILD.bazel","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/extra/bazel/nanopb_cc_proto_library.bzl","size":3113,"hash":"9ba561ff6b8b6d4a62359bfc41fef904526ca04aa5673468c285448a31947d8d"},{"path":"nanopb/extra/bazel/nanopb_deps.bzl","size":2259,"hash":"73581fa3379220083898cabfcddd4e436ca7fb6bfe275752ea19f3a133187a4b"},{"path":"nanopb/extra/bazel/nanopb_workspace.bzl","size":424,"hash":"41ea4b966de1a2c2070357e2b0a3499be0f7469fdd6fae87aecc464836bbbec4"},{"path":"nanopb/extra/bazel/python_deps.bzl","size":446,"hash":"d8a3b3032adfcf4598257858078181b606720f5a0bd0bd93a005189a1beeb451"},{"path":"nanopb/extra/poetry/poetry_build.sh","size":442,"hash":"6d24ab55fdb89a877314389538851d4306e652e66e7b419f5f138d1af0291e1c"},{"path":"nanopb/extra/poetry/pyproject.toml","size":1061,"hash":"561a213eada3e46c20f11e3ed70290ef9c6a13b6a26eb1655f6bc633ae179525"},{"path":"nanopb/extra/script_wrappers/nanopb_generator.py.in","size":1052,"hash":"a06eaff39029b61e0f9c37e4ad3aa312aa1a12b703ba1a9bd3f1a0b843f130c5"},{"path":"nanopb/examples/cmake_relpath/CMakeLists.txt","size":383,"hash":"a485c7bbdabde8a77fee9fd1e024b245515d15fe92534fd0e1a13b2619fffd28"},{"path":"nanopb/examples/cmake_relpath/README.txt","size":533,"hash":"527a900f059ddb3b3d4617af3a65b1841ba8ea62251c94b33d443e302ac80b09"},{"path":"nanopb/examples/cmake_relpath/simple.c","size":2323,"hash":"1d2f56e6e8ddf8dc6c4e1d64451b9e8eb3183581fe88a9a5cdf381b9012f700c"},{"path":"nanopb/examples/cmake_simple/CMakeLists.txt","size":338,"hash":"d84c05afdf6dfaedca37326069f2b5c1e3ac34562672fe938d56904a9a619c45"},{"path":"nanopb/examples/cmake_simple/README.txt","size":533,"hash":"527a900f059ddb3b3d4617af3a65b1841ba8ea62251c94b33d443e302ac80b09"},{"path":"nanopb/examples/cmake_simple/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/examples/cmake_simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/conan_dependency/.gitignore","size":7,"hash":"181314065df2f2fdaf920b1a8b5311daa216a2d6489a06ada5b49cc514d89417"},{"path":"nanopb/examples/conan_dependency/CMakeLists.txt","size":316,"hash":"ddca586c17ba179aed6daa2589d2bb95619f825d1e17cf6537b90ecafbf1692e"},{"path":"nanopb/examples/conan_dependency/README.md","size":835,"hash":"361f3bd7e8c84ea7ddfdc7cc595e8cb734c9c46802cbe16ce662e42d26f463e5"},{"path":"nanopb/examples/conan_dependency/conanfile.py","size":1522,"hash":"f904a40804ffad2a4005f0c937a529faff78ebaac00cd6775791ed78808c9fd3"},{"path":"nanopb/examples/network_server/Makefile","size":356,"hash":"49984487e6fdf8a75ea1a1c01deee25d6b254adce9701e10f0c8469ca49225a2"},{"path":"nanopb/examples/network_server/README.txt","size":2135,"hash":"bb568a5ebd4d1160d3d023fd7b0c4812125e5d74a627abb076ea79bdcd8508aa"},{"path":"nanopb/examples/network_server/client.c","size":3880,"hash":"663b58ec2b4b052f13ed9e2e41386755b47d0f9f0c92cbbb9c09ede2869a7b3a"},{"path":"nanopb/examples/network_server/common.c","size":963,"hash":"3655262342478a76606f12f6e754a9d791648a14d534183d5e162e1c5293d53b"},{"path":"nanopb/examples/network_server/common.h","size":175,"hash":"6774fd7579f0a234f7ad7855b9aa0ae92b6266b25ba98afe4631cb03ccaba527"},{"path":"nanopb/examples/network_server/fileproto.options","size":632,"hash":"5069d54fd9161371d7ba652f9a7e816f5ec6e4c346fde90646340597b3d0e25e"},{"path":"nanopb/examples/network_server/fileproto.proto","size":423,"hash":"cb5d19a1b1d612432da0a1b268940e83fe9823c4382fd1a14943418e8ae73fe4"},{"path":"nanopb/examples/network_server/server.c","size":4792,"hash":"e935ea58afd780716995a5460a74b2e76f8be8f75fe3e38ee3b7285c98427ac4"},{"path":"nanopb/examples/platformio/.gitignore","size":66,"hash":"4b919aca11aac3e4dbbef0c89d891589e001c7658d692a4e4a01649293d0113e"},{"path":"nanopb/examples/platformio/platformio.ini","size":1205,"hash":"7d322a37b755c419633cb9b1f3ce5195190e7a7bb24d4441e4a5fdd969a26bbb"},{"path":"nanopb/examples/simple/Makefile","size":722,"hash":"5ce1951380f8b0d5da93ea0a665a85edad46a5339219df6d1b293a05e15f550f"},{"path":"nanopb/examples/simple/README.txt","size":848,"hash":"68b2b49a081cf5dd77066ab737ea095e05c25194216eec8c02e90eb45fc878b6"},{"path":"nanopb/examples/simple/simple.c","size":2218,"hash":"73a78d512608c349bf453f2f1f0eac677a2a9fd269ca5c34a10aa90ece85fe14"},{"path":"nanopb/examples/simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/using_union_messages/Makefile","size":412,"hash":"3147a8df59d0bce38b280c808a028704ba15611526951c0c1f3c06ce1237e901"},{"path":"nanopb/examples/using_union_messages/README.txt","size":2039,"hash":"27e889e281d7c526ac59428e1a13eb4c11d5f39586a1e6352d0b9fd81f8d1ae8"},{"path":"nanopb/examples/using_union_messages/decode.c","size":2620,"hash":"19eb903f44bcc653c80b834d51f3c25a6aff0308dbb04941c32a169523a0e934"},{"path":"nanopb/examples/using_union_messages/encode.c","size":2321,"hash":"4c72ed7cad5fa372039c46b6ba38c3bce90696e03830ba49bd49deb8d02e8dae"},{"path":"nanopb/examples/using_union_messages/unionproto.proto","size":631,"hash":"35e57746e681686afa461b2d697b469470dbaaa5995a08062d14d2f9426baf3a"},{"path":"nanopb/examples/platformio/proto/pio_with_options.options","size":39,"hash":"fdf7a2a9911019c828ff768ff84b54b752f1ae4c908977d4ecd8d51ec707fe23"},{"path":"nanopb/examples/platformio/proto/pio_with_options.proto","size":73,"hash":"b99efe4689e541cca1b76801b36747206bae31e0db384e14efe8eaf613312d29"},{"path":"nanopb/examples/platformio/proto/pio_without_options.proto","size":78,"hash":"0dbe95539ece82068e4af92a65d3b55e3f01d631376b6b442bead06bd290194c"},{"path":"nanopb/examples/platformio/src/CMakeLists.txt","size":62,"hash":"65c02481b7c1959cf9bbbb91e5b3a8cf63c5886aef5335a517359c4ded82867c"},{"path":"nanopb/examples/platformio/src/pio_esp32_idf.c","size":763,"hash":"cc6b9b46387aa45caef62e79d660da8424844335bb10da5347b5f67b58672760"},{"path":"nanopb/examples/platformio/src/pio_with_options.c","size":800,"hash":"3d9d8652170dfd1e7986f7d8351c9d9231b9995ec870a3bffdeb7793a5797c45"},{"path":"nanopb/examples/platformio/src/pio_without_options.c","size":801,"hash":"7c5410fb5446399441e2b451dd70b3b32307a0accd8b53c634bc2bcb554cfe57"},{"path":"nanopb/examples/platformio/src/test.h","size":248,"hash":"44e7f0c6214f3d710b0e16c72e877478576cb6fe59749df2edb07093f799de5c"},{"path":"nanopb/examples/conan_dependency/protos/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/conan_dependency/src/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/examples/cmake_relpath/proto/simple.proto","size":226,"hash":"b5e1093b44d508ad17b9c8cded9432841c0d743a1d012472f4b996b92f390e64"},{"path":"nanopb/examples/cmake_relpath/proto/sub/unlucky.proto","size":75,"hash":"094f24d42a0f923294c663dca845e5592130901ae336df08d11f5a0216ff99b6"},{"path":"nanopb/docs/logo/logo.png","size":14973,"hash":"667f421b126598c0e53d8b28eef46d4d771c3e5138f43a10a088221a04dc5117"},{"path":"nanopb/docs/logo/logo.svg","size":103905,"hash":"19ff117ba34ef6b7c2f1ad9a88c618175662a657054b40a698df29f29b44327a"},{"path":"nanopb/docs/logo/logo16px.png","size":854,"hash":"1f034014fb4a31253ba96e474007b3ff91ba1ac552a64989d6867670f311ef1f"},{"path":"nanopb/docs/logo/logo48px.png","size":2577,"hash":"26d67f96d672d284a29b8678dfc21f6222bd0099b876ac5d95d3ec18382be6c4"},{"path":"nanopb/build-tests/cmake_with_components/CMakeLists.txt","size":371,"hash":"5ee734dcaa02cee58f049458c616f68b08ddba0f4c72e25d1a598212ef438cc5"},{"path":"nanopb/build-tests/cmake_with_components/simple.cpp","size":2200,"hash":"60dba84e4246937899ebfa7d63fc4fea9c9de0f1dad29a8f9009210b74b2f23b"},{"path":"nanopb/build-tests/cmake_with_components/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/build-tests/legacy_cmake_relpath/CMakeLists.txt","size":478,"hash":"a1db5abcf879c2649edb6604a434f57b215bd03a20c16c39db0a8c80b36fb6d1"},{"path":"nanopb/build-tests/legacy_cmake_relpath/simple.c","size":2323,"hash":"1d2f56e6e8ddf8dc6c4e1d64451b9e8eb3183581fe88a9a5cdf381b9012f700c"},{"path":"nanopb/build-tests/legacy_cmake_simple/CMakeLists.txt","size":432,"hash":"58544be0ea7cf473d6c1f5ec0979711f68a7cd81f96b59b67f3f6d6c92815ea3"},{"path":"nanopb/build-tests/legacy_cmake_simple/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/build-tests/legacy_cmake_simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/build-tests/legacy_cmake_relpath/proto/simple.proto","size":226,"hash":"b5e1093b44d508ad17b9c8cded9432841c0d743a1d012472f4b996b92f390e64"},{"path":"nanopb/build-tests/legacy_cmake_relpath/proto/sub/unlucky.proto","size":75,"hash":"094f24d42a0f923294c663dca845e5592130901ae336df08d11f5a0216ff99b6"},{"path":"mock/src/main.c","size":1448,"hash":"72a02425928b7af4f8f52add7e350fbd99e2bc71825402743526b4d85d55ef6d"},{"path":"mock/src/appfs_mock/appfs.c","size":1310,"hash":"c21e0b9ac9ddd0f19539a4f4b40708baa627b3691685f8ea0dac19bd7b724b1d"},{"path":"mock/src/appfs_mock/appfs.h","size":1196,"hash":"616365f35c4291ae92a26a9de0af988af3a098d880dc1abc3ca7ecf32214f3fc"},{"path":"mock/src/esp_mock/esp_crc.c","size":226,"hash":"d7349c212c743a1ad24421b20f5781e52415144929cb5a3f72398640d578c784"},{"path":"mock/src/esp_mock/esp_crc.h","size":210,"hash":"6370cf7a78e0c4f5b6c76b0425eb2c626e2eed4b78c993a86f15084369a252d0"},{"path":"mock/src/esp_mock/esp_err.c","size":398,"hash":"437a8c35828a1718d47d3ea31d8f04ca6a4e9ec237b21ce0288e262799214106"},{"path":"mock/src/esp_mock/esp_err.h","size":286,"hash":"83f9730df1683d2cd34ea85cbb308c8c00cadf57cec1945929aaa7a7465a549a"},{"path":"mock/src/esp_mock/esp_err_defs.inc","size":356,"hash":"61060bbc153478643932134c19229fb79cd923d73bacd9c806eedf0d1008af08"},{"path":"mock/src/esp_mock/esp_log.c","size":1547,"hash":"7bfaeb794fa5a7f430767ba801c228bbe1d676873216f990815da87f27334659"},{"path":"mock/src/esp_mock/esp_log.h","size":684,"hash":"d589d4354efc03c6bb3436faa3e41b342cbccc1e572cd3440fdcd56badaa4cfd"},{"path":"mock/src/esp_mock/nvs.c","size":5574,"hash":"27e33362e3870132752f73608a846aae175d001be17f27537b323e32efaefe5a"},{"path":"mock/src/esp_mock/nvs.h","size":3295,"hash":"97c036bcd59358517508f448f62a3d90e6f857584f21cbed96b3caf778ca7e66"},{"path":"mock/src/esp_mock/nvs_flash.h","size":97,"hash":"4da7fa596ae1858282dda9dd89abb78df0dd42153493850c5c65a94bce858fe1"},{"path":"mock/src/freertos_mock/freertos.c","size":1016,"hash":"b23a3d171114a2744e446f1b7d3f784c44b07245dca59231dd09caf71050f0cb"},{"path":"mock/src/freertos_mock/freertos/FreeRTOS.h","size":680,"hash":"73e7c089d5ff30c678916456721c311d7a1b93d6f4352e3ac3ead10d90c409fd"}]} \ No newline at end of file From ca0ebadef9b2c05b3dda6565e8f9498d241e9c4b Mon Sep 17 00:00:00 2001 From: Rene Schickbauer Date: Thu, 11 Dec 2025 21:38:29 +0100 Subject: [PATCH 5/8] Speed up SD card operations by a factor of 10 on Tanmatsu and Konsool --- badgelink_fs.c | 78 ++++++++++++++++++++++++++++++++++++++++++---- idf_component.yml | 16 ++++++---- tools/badgelink.py | 2 +- 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/badgelink_fs.c b/badgelink_fs.c index 063a493..b76a113 100644 --- a/badgelink_fs.c +++ b/badgelink_fs.c @@ -6,17 +6,65 @@ #include "dirent.h" #include "errno.h" #include "esp_crc.h" +#include "esp_heap_caps.h" #include "esp_log.h" #include "fcntl.h" #include "stdio.h" +#include "string.h" #include "sys/stat.h" #include "sys/types.h" #include "unistd.h" static char const TAG[] = "badgelink_fs"; +// Fast SD I/O helpers - use internal DMA RAM for stdio buffers +#ifdef CONFIG_SD_FAST_IO +#define BADGELINK_STDIO_BUF_SIZE 8192 + +static FILE* bl_fast_file = NULL; +static void* bl_fast_buffer = NULL; + +static FILE* bl_sd_fopen(const char* path, const char* mode) { + FILE* f = fopen(path, mode); + if (f == NULL) return NULL; + + // Allocate stdio buffer in internal DMA-capable RAM for fast SD card access + void* buf = heap_caps_malloc(BADGELINK_STDIO_BUF_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + if (buf != NULL) { + setvbuf(f, buf, _IOFBF, BADGELINK_STDIO_BUF_SIZE); + bl_fast_file = f; + bl_fast_buffer = buf; + } + return f; +} + +static void bl_sd_fclose(FILE* f) { + if (f == NULL) return; + + // Check if this file has a tracked fast buffer + if (bl_fast_file == f && bl_fast_buffer != NULL) { + fclose(f); + free(bl_fast_buffer); + bl_fast_file = NULL; + bl_fast_buffer = NULL; + return; + } + fclose(f); +} +#else +// Fallback: just use regular fopen/fclose +static inline FILE* bl_sd_fopen(const char* path, const char* mode) { + return fopen(path, mode); +} + +static inline void bl_sd_fclose(FILE* f) { + if (f != NULL) fclose(f); +} +#endif + static char xfer_path[256]; static FILE* xfer_fd; +static bool xfer_is_sd; static uint32_t xfer_crc32; static uint32_t running_crc; @@ -98,7 +146,11 @@ void badgelink_fs_xfer_download() { // Finish a FS transfer. void badgelink_fs_xfer_stop(bool abnormal) { if (abnormal) { - fclose(xfer_fd); + if (xfer_is_sd) { + bl_sd_fclose(xfer_fd); + } else { + fclose(xfer_fd); + } if (badgelink_xfer_is_upload) { ESP_LOGE(TAG, "FS upload aborted"); unlink(xfer_path); @@ -107,7 +159,11 @@ void badgelink_fs_xfer_stop(bool abnormal) { } } else if (badgelink_xfer_is_upload) { - fclose(xfer_fd); + if (xfer_is_sd) { + bl_sd_fclose(xfer_fd); + } else { + fclose(xfer_fd); + } if (running_crc != xfer_crc32) { ESP_LOGE(TAG, "FS upload CRC32 mismatch; expected %08" PRIx32 ", actual %08" PRIx32, xfer_crc32, @@ -121,7 +177,11 @@ void badgelink_fs_xfer_stop(bool abnormal) { } else { ESP_LOGI(TAG, "FS download finished"); - fclose(xfer_fd); + if (xfer_is_sd) { + bl_sd_fclose(xfer_fd); + } else { + fclose(xfer_fd); + } // For protocol version 2+, send the final CRC. if (badgelink_get_protocol_version() >= 2) { @@ -236,7 +296,8 @@ void badgelink_fs_upload() { // Open target file for writing. strlcpy(xfer_path, req->path, sizeof(xfer_path)); - xfer_fd = fopen(req->path, "w+b"); + xfer_is_sd = (strncmp(req->path, "/sd", 3) == 0); + xfer_fd = xfer_is_sd ? bl_sd_fopen(req->path, "w+b") : fopen(req->path, "w+b"); if (!xfer_fd) { if (errno == ENOENT) { badgelink_status_not_found(); @@ -273,7 +334,8 @@ void badgelink_fs_download() { // Open target file for reading. strlcpy(xfer_path, req->path, sizeof(xfer_path)); - xfer_fd = fopen(req->path, "rb"); + xfer_is_sd = (strncmp(req->path, "/sd", 3) == 0); + xfer_fd = xfer_is_sd ? bl_sd_fopen(req->path, "rb") : fopen(req->path, "rb"); if (!xfer_fd) { if (errno == ENOENT) { badgelink_status_not_found(); @@ -294,7 +356,11 @@ void badgelink_fs_download() { struct stat statbuf; if (fstat(fileno(xfer_fd), &statbuf)) { ESP_LOGE(TAG, "%s: fstat failed, errno %d", __FUNCTION__, errno); - fclose(xfer_fd); + if (xfer_is_sd) { + bl_sd_fclose(xfer_fd); + } else { + fclose(xfer_fd); + } badgelink_status_int_err(); return; } diff --git a/idf_component.yml b/idf_component.yml index 8dcb5b7..d059d6a 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,8 +1,12 @@ +dependencies: + badgeteam/appfs: '>=1.0.1' + idf: '>=5.4' description: Protobuf protocol for managing basic device functions -url: https://github.com/badgeteam/esp32-component-badgelink -repository: git://git@github.com:badgeteam/esp32-component-badgelink.git issues: https://github.com/badgeteam/esp32-component-badgelink/issues -dependencies: - idf: ">=5.4" - badgeteam/appfs: ">=1.0.1" -license: "MIT" +license: MIT +repository: git://github.com/badgeteam/esp32-component-badgelink.git +repository_info: + commit_sha: aff9b2bbad34db5fc873c66bef247bfbf4ef6328 + path: . +url: https://github.com/badgeteam/esp32-component-badgelink +version: 0.0.4 diff --git a/tools/badgelink.py b/tools/badgelink.py index 8be2e7b..d75764b 100755 --- a/tools/badgelink.py +++ b/tools/badgelink.py @@ -1093,7 +1093,7 @@ def print_row(row: list[str]): try: if args.port: - port = Serial(port=args.port, baudrate=115200) + port = Serial(port=args.port, baudrate=4000000) elif args.inpipe: infd = open(args.inpipe, "rb") outfd = open(args.outpipe, "wb") From f370093b39314fa87fc39031587b84345dd21f6f Mon Sep 17 00:00:00 2001 From: Rene Schickbauer Date: Fri, 12 Dec 2025 00:15:41 +0100 Subject: [PATCH 6/8] Cleanup --- .component_hash | 1 - CHECKSUMS.json | 1 - ProtocolV2.md | 20 -------------------- idf_component.yml | 16 ++++++---------- 4 files changed, 6 insertions(+), 32 deletions(-) delete mode 100644 .component_hash delete mode 100644 CHECKSUMS.json diff --git a/.component_hash b/.component_hash deleted file mode 100644 index 124da67..0000000 --- a/.component_hash +++ /dev/null @@ -1 +0,0 @@ -793ba0d6780b2d8d59586ceee2d5c0d607dac7a0d8b5a8e1f924f515983c3b05 \ No newline at end of file diff --git a/CHECKSUMS.json b/CHECKSUMS.json deleted file mode 100644 index e0fa6c1..0000000 --- a/CHECKSUMS.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"1.0","algorithm":"sha256","created_at":"2025-10-29T02:15:50.457074+00:00","files":[{"path":"CMakeLists.txt","size":274,"hash":"f8a6dd4b73d9a79d108936b7881daf52d1fc536ad09c124388a84e3fa0aa7f6b"},{"path":"LICENSE","size":1073,"hash":"a5da5fc75d9aec40e75152f7e1c3dfbc7c015cac96c9738d8c61808f28676893"},{"path":"README.md","size":254,"hash":"787e938ee689d7d43eba3418e09a325dd0b2fe9ce3dc8d694461cd3a03995050"},{"path":"badgelink.c","size":12969,"hash":"28cdb7090ca1bb0a1f45454e2c8015c4bc967121be880a4767a99b5c05073824"},{"path":"badgelink.h","size":449,"hash":"0d4c8c298c2313800352604e5717b0fe55d25abd931a484fd7e4c602f044be6c"},{"path":"badgelink.pb.c","size":1404,"hash":"7f0ee21127a6f0201c9b5da6c37c2366bbc7f030544d2b2811db7bb6dab8ac53"},{"path":"badgelink.pb.h","size":41607,"hash":"4abf871d42027ca544f5a8691bb38ddf593cb4505f61f9f2ff892574fa55b517"},{"path":"badgelink_appfs.c","size":14178,"hash":"dbf603e7e979ddf1999f93daa82db3a8339cbebc048023af6f7c462e3656245b"},{"path":"badgelink_appfs.h","size":911,"hash":"75297375ed970ce11c2827a816982a5230997ff228e69b16fd33dc405c70f503"},{"path":"badgelink_fs.c","size":13045,"hash":"7c79e61e985d41e489348f7d9b3cf15225c212662d78fc4b40ada216c09870b2"},{"path":"badgelink_fs.h","size":948,"hash":"608799827fe96e1ac6ac8a23a97582728eba6a9f7bf5698f5f48e3168e821bde"},{"path":"badgelink_internal.h","size":2935,"hash":"8a7eacddfe1d12ada5179ced54ce0129e5b50d4f32a9e0dc26c049e31debf966"},{"path":"badgelink_nvs.c","size":15385,"hash":"fbbaf9641b7fe862a8c154fe074e4d8b6259b53f649bb16d9e4910c38f00b7f2"},{"path":"badgelink_nvs.h","size":428,"hash":"c1b13d0dd012c519c3b60cedc73616bce9d5687334d1c12aa69b8b1a92d787d0"},{"path":"badgelink_startapp.c","size":975,"hash":"0f559e740be2d9f8045f15f64b385f3b265acbfb2a163488c1b22c0f02fcbcce"},{"path":"badgelink_startapp.h","size":192,"hash":"09a4ce249e6e8569cd6fb296adfbe18208e0835754731ee95127c16272aa3caf"},{"path":"cobs.c","size":2156,"hash":"83a740e38f16aac3bbd0ca1a92ec9baf16867041270d5282df172e192087623b"},{"path":"cobs.h","size":823,"hash":"84946bb63a9fda456aeb9a460a78201efcfb1d7b0000c96069f0e1ba5a98993c"},{"path":"idf_component.yml","size":434,"hash":"ed67f1d35dca32f6f25e7857c5535ed89a29a6c7e77e57f06ba4f2c18e91ce3b"},{"path":"mock/CMakeLists.txt","size":890,"hash":"cf18c9abdbe57c372483a14d5d92c5f2ed07cfb3cbd1abae141bfc8da59d316c"},{"path":"mock/Makefile","size":353,"hash":"168e94a7c053c84cf9c11f52d4c53f34fa09c3afb57073aafd74bc125a502f32"},{"path":"nanopb/.bazelignore","size":29,"hash":"9c3dfa1e71dcceaebc95ddda9c0b63a16e5e81c427e5627928d77bc7a097c4cf"},{"path":"nanopb/.bazelversion","size":6,"hash":"910121d8fda1ee513d664110f94bef46c4791698010db514c2a71cc1932bc3cf"},{"path":"nanopb/.gitattributes","size":147,"hash":"fa64da464e48b153d41a2cb334d92b31d72e5364c94d552eea73f1bebb58c119"},{"path":"nanopb/.gitignore","size":559,"hash":"59889945b5b7f932c0f00bef85115005ec3ecb23ae5bc0318ab6da80d8d98c97"},{"path":"nanopb/AUTHORS.txt","size":5801,"hash":"e837f8a26776e38ceaa64c62a72a6707fc66aed389618d33be369c6e757c3c55"},{"path":"nanopb/BUILD.bazel","size":3031,"hash":"c590f2f952e8bbea678c2642e084b61b6192c35fa2328a05ef13e18fd3c174d0"},{"path":"nanopb/CHANGELOG.txt","size":30006,"hash":"7b5e43997a06543d74735ae412bcf106d4777931197ac6357650b076e85fcad1"},{"path":"nanopb/CMakeLists.txt","size":6883,"hash":"144c9feb9a63e778e49f23fc8413d457704c35850728b4a4beec4cd79ece6d16"},{"path":"nanopb/CONTRIBUTING.md","size":1227,"hash":"f255db55bdb7124a67fcf8a76c3279de9324f3939bdbe781d0ad0aec50bd8768"},{"path":"nanopb/LICENSE.txt","size":898,"hash":"e2f2fc8fe3faa7dcb09dbe995db48c6ec5c1f72705db915101e4a83fed44f66d"},{"path":"nanopb/MODULE.bazel","size":872,"hash":"b24f25ad5adc64d9b72ea1e9f4ba8257fb25730c15b87bf0834d208c382a6370"},{"path":"nanopb/MODULE.bazel.lock","size":14357,"hash":"40d859fe597aa13df91e4bb666d1e62a3cd3fae6adf46e99d924aafc946a3842"},{"path":"nanopb/Package.swift","size":1471,"hash":"587f10beea90055c8ebf778a01a17ae52c8ce0dcb181d79dfe3c8b20601c01fe"},{"path":"nanopb/README.md","size":4465,"hash":"ddfd9bfff7c5257b596eb80a24c0b9c29cef80ba3768c52848c1bfdb76250499"},{"path":"nanopb/WORKSPACE","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/build.py","size":205,"hash":"b45c55e08a081da6754499488cb64b3e878c9741da759ba163957396da6e970e"},{"path":"nanopb/conanfile.py","size":970,"hash":"725ffb9744dbf33789cd4fdf66590d5cfdb1e4440079930aa1aa27db796a3974"},{"path":"nanopb/library.json","size":1097,"hash":"9fec74236173af17854019b1702b4b78b2f76391722815006b7d42faa5030676"},{"path":"nanopb/pb.h","size":44732,"hash":"7cf917f225a17616887da585af4e05854cee4582f231684462b0fd23d70db1d6"},{"path":"nanopb/pb_common.c","size":12141,"hash":"8d2ec28baaaf2b7a5e90e4cb2fa9700d21cef7f826f051a637c30b7a1e6a0516"},{"path":"nanopb/pb_common.h","size":1677,"hash":"6495a691aca68d6973f2274b5dd54b74fbb57f6b019c45fff255a857fe1abcfd"},{"path":"nanopb/pb_decode.c","size":55680,"hash":"3c3394300a93a152ac6280786a2d98ed57e0012ab9ee69af31176a6c549e51b5"},{"path":"nanopb/pb_decode.h","size":7870,"hash":"1747746e5961de5789bcf0795588da0790cd18b2e4e706ad9c7099a0fa1cc83f"},{"path":"nanopb/pb_encode.c","size":30706,"hash":"30e22b48c5a4134f42d32a5abc9bc622f747c50049204a32210b1097e1554dd9"},{"path":"nanopb/pb_encode.h","size":7176,"hash":"9aa00fee4ff08adf0da16e33a55be08810ea657800a648dc78f82e89c60c10cf"},{"path":"nanopb/requirements.txt","size":22,"hash":"77da319753254b0b9582a704b20c0603054c1630ee04b1cbe8eb4b88cf0d3382"},{"path":"tools/60-badgelink.rules","size":239,"hash":"53080214a5bed1cff45a8cb511c1e505a5dd8407de8c5262f43e3b508f7ddd4f"},{"path":"tools/README.md","size":8832,"hash":"0b18b88180a0069b6be9047cb566fad6056398304b4bb99d89c00e237002e90c"},{"path":"tools/badgelink.py","size":44255,"hash":"5e064118307a598333cb390db92530ece063e4c042b02c436c78378019d109fa"},{"path":"tools/badgelink.sh","size":239,"hash":"8a7daee0d896bb6d47ee4bc71c64ac481cc7c7c3eb62c38dca87e7c337eceefc"},{"path":"tools/install.sh","size":239,"hash":"3a68ca668058e13ab02c66b02be04436fa564962c0a5581e07b0229382bdf5dd"},{"path":"tools/requirements.txt","size":29,"hash":"0a4e1505fc0114d7fc04f1a1dc8d1cbd6dc2e782a6331ce2bff1b8a08a1fecb5"},{"path":"tools/libraries/__init__.py","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"tools/libraries/badgelink_pb2.py","size":9256,"hash":"d67ae2fa467da8ff9eedafded3eed8867799cf427491d5eced32e09994d2ea6a"},{"path":"tools/libraries/badgelink_pb2.pyi","size":13554,"hash":"7933ed8f8e1d92531cdb14ca6e43e3319d0dca4b7e1a8f97dd9284ec41bff595"},{"path":"tools/libraries/device.py","size":2058,"hash":"f2a871514d0f5451c15b5c9dc31caa95e79f3b8d1ea6e9080c29f2b0df49ed05"},{"path":"nanopb/conan-wrapper/CMakeLists.txt","size":174,"hash":"03cc973b482dae454fa4312cea8dc1046ccf0d33ca2480b32d93197bccafc767"},{"path":"nanopb/docs/Makefile","size":825,"hash":"85a845ee5b888e6e2757d7afff08dad614df5677450cb38311e5f10159721737"},{"path":"nanopb/docs/bazel_build.md","size":1527,"hash":"bd93eecfd52ca9ddc9c13dc234b61874c6407a090d3f8f2789ce035a51aa16b9"},{"path":"nanopb/docs/concepts.md","size":23808,"hash":"14e36d946b81e38a45be328d59e5eabc0f31054f7ec63aa5179d826a86210e2a"},{"path":"nanopb/docs/generator_flow.svg","size":114305,"hash":"f0e6bd4bb84e8039dc190c04c6e11ab7d7f071daef371ef586bcfc5385aea66e"},{"path":"nanopb/docs/index.md","size":6361,"hash":"3afc3e850bc006bd3429aa530d21a3e1dae4e13e760322a813645808414fc020"},{"path":"nanopb/docs/lsr.css","size":3297,"hash":"f57eb047684e72d5737006361ddf7de2a089c8e2a40ee40250011751441fd442"},{"path":"nanopb/docs/migration.md","size":30644,"hash":"dc2b56c850952daf2ab0350833222b0de625257643e7855ef4e097db1495ef51"},{"path":"nanopb/docs/reference.md","size":53523,"hash":"ad2dbbc2ce931bde58a53928b09a873b8ab898c8345419888a2984adaec24a44"},{"path":"nanopb/docs/security.md","size":4104,"hash":"746cbbc33230c9a12d50b35b8c9ac8db2f6fa5888048790c571821841270bcd6"},{"path":"nanopb/docs/whats_new.md","size":8209,"hash":"215f462e7a55831cbfd7169129b456044d66760d07fd82d2ae504b537e877c79"},{"path":"nanopb/extra/FindNanopb.cmake","size":17872,"hash":"52af143cb469f4d4cf228cbba29b3159ea39bcf09aaecbf4fac788832e9dd298"},{"path":"nanopb/extra/nanopb-config-version.cmake.in","size":401,"hash":"bd2bdc5193e60738ad270b1f1ec0e568b937e91d4e6afd77710992d55ebfcec6"},{"path":"nanopb/extra/nanopb-config.cmake","size":57,"hash":"53fef9000f32b14d11b8d54f1a1a380d94a15b102d004f95a5980d6f41fe86a4"},{"path":"nanopb/extra/nanopb.mk","size":1091,"hash":"10807143c2a56a843fc0ec6f6ad00c1807c56d6208b59d3fe17fa7d98d7103da"},{"path":"nanopb/extra/pb_syshdr.h","size":2451,"hash":"be9a69f60bd7be72d519b0f7204a84328dabc7c76d915c7c398331f9f560ace0"},{"path":"nanopb/extra/requirements.txt","size":42,"hash":"7c773ae5858b23547c6e499944815683e300b17f070f95017bc9115ec774ad9f"},{"path":"nanopb/extra/requirements_lock.txt","size":10885,"hash":"2bcdca24f1a4429b4ab0f0bb80cca292a92e12f7bf3d0f46de7c2b14fd97ac25"},{"path":"nanopb/generator/__init__.py","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/generator/nanopb_generator","size":235,"hash":"a15c7870b70543ae6ffd6a09111530dec3c931b045b88d91634933bc63b7dec7"},{"path":"nanopb/generator/nanopb_generator.bat","size":206,"hash":"b8a463e498084db52897d8e479d187a47244f7e6c346d53267890a06f4ff00d7"},{"path":"nanopb/generator/nanopb_generator.py","size":117767,"hash":"d7cb5b8c1103a10d42aa262d4920f89eb9a23da61b1cc0c248b78cb1b55c5960"},{"path":"nanopb/generator/platformio_generator.py","size":6116,"hash":"f8b053021adbaf0ae2537712dd363248181df5d6a298c6cac1cefc868d42132f"},{"path":"nanopb/generator/protoc","size":1801,"hash":"6bc34847cc6c0c9ef6ec6137beceef6b05c378f248dee6a7086e5b2166ffc71d"},{"path":"nanopb/generator/protoc-gen-nanopb","size":374,"hash":"a2be7131063149e5cffb47c3c7921fc52fa44d4b85a13628a131c386323232e7"},{"path":"nanopb/generator/protoc-gen-nanopb.bat","size":449,"hash":"a35a3333fee6c39581a150d3fc6b4adc4b247fd8b0b4358dffa495798687ac5a"},{"path":"nanopb/generator/protoc.bat","size":302,"hash":"62a13daf0f2e2658f05378047668053fa96fd27d89cd1bcb4af21c975ca44341"},{"path":"nanopb/spm_headers/pb.h","size":23,"hash":"ffb03e429cb90d2e89c56eee94464913e0d42b22b4eb5b20fab14bded1d4e73f"},{"path":"nanopb/spm_headers/pb_common.h","size":30,"hash":"8479f2612a1df0bb1c5e2010da8aae590bb5695738ed25f0df7d5e2c301ebacb"},{"path":"nanopb/spm_headers/pb_decode.h","size":30,"hash":"00c9aa27bfe36745d7902a4a4aa282b6d4ce4fee3ea77eaf2c44c512d7b972b2"},{"path":"nanopb/spm_headers/pb_encode.h","size":30,"hash":"92c444291d604cd07c478c623966f66c23b3b567a18c4cbd1dd79391694851d9"},{"path":"nanopb/spm_resources/PrivacyInfo.xcprivacy","size":374,"hash":"729ba3cbd0f458c78cd61edf17350edafe0e34ca86e314ec64c8cb22ccd21b54"},{"path":"nanopb/tools/list_authors.sh","size":150,"hash":"6b8262b6991aa7bdae72e078d6f954688d5bd9c70797dcb3b63b6fdd60d8d929"},{"path":"nanopb/tools/make_linux_package.sh","size":1395,"hash":"43ef621e9b83b98c7f08acc3f081197be7237d7168cc9078ceb6cf44f921c073"},{"path":"nanopb/tools/make_mac_package.sh","size":1327,"hash":"d9e8dae1c0201156276f50ad75de3a41ee0cca74603b87109e87c79fa88985c5"},{"path":"nanopb/tools/make_windows_package.sh","size":1556,"hash":"e046d9335c1f9ca6d73987267bfd8728456f898799999776781131fb6cc0a4db"},{"path":"nanopb/tools/set_version.sh","size":1492,"hash":"6d6dd5932014398659668bcb7366cc9dff2f8d03396c88e3edaf35e900c36c8e"},{"path":"nanopb/zephyr/module.yml","size":265,"hash":"0d7f3144a36f423d5fcc01254c26ad38341a9f1989c2bb1785e382777ebb011c"},{"path":"nanopb/spm_headers/nanopb/pb.h","size":44732,"hash":"7cf917f225a17616887da585af4e05854cee4582f231684462b0fd23d70db1d6"},{"path":"nanopb/spm_headers/nanopb/pb_common.h","size":1677,"hash":"6495a691aca68d6973f2274b5dd54b74fbb57f6b019c45fff255a857fe1abcfd"},{"path":"nanopb/spm_headers/nanopb/pb_decode.h","size":7870,"hash":"1747746e5961de5789bcf0795588da0790cd18b2e4e706ad9c7099a0fa1cc83f"},{"path":"nanopb/spm_headers/nanopb/pb_encode.h","size":7176,"hash":"9aa00fee4ff08adf0da16e33a55be08810ea657800a648dc78f82e89c60c10cf"},{"path":"nanopb/spm-test/objc/c-header.c","size":62,"hash":"7f8d5b816e6b440ab3e5d5b119405073948dcc84fe115868f3b41d4975f0e99b"},{"path":"nanopb/spm-test/objc/objc-header.m","size":60,"hash":"21c2a62f318f71206756e3184db693552e44a23a399c01a877105d7b92e01d07"},{"path":"nanopb/spm-test/objc/objc-module.m","size":16,"hash":"1483995274d6b4d26201ee8df5c65191b8461271cd312ae160e6c6553042d3a8"},{"path":"nanopb/spm-test/objc/objc-qualified.m","size":81,"hash":"c76b495a4f316e3ecb8aad935b60c2d6c34e4c6febdc03dc9deadf4ce32df4fc"},{"path":"nanopb/spm-test/swift/main.swift","size":14,"hash":"65dc3460a2be279a48c5220239c37669b1aef3551b0e2045468d69a32a4a4032"},{"path":"nanopb/generator/proto/Makefile","size":126,"hash":"605bc10e05f82149d7dbfc620b76d7a6a888613d8aa7d76ff125258e869011e0"},{"path":"nanopb/generator/proto/__init__.py","size":4018,"hash":"4304e32d33a2f0085f19179c07b66266bcca41466de2770bc0ebba40fd42f515"},{"path":"nanopb/generator/proto/_utils.py","size":3338,"hash":"6d091e256cdda09002c357da4901d259078fe1ef53a010392a251dd1107d6313"},{"path":"nanopb/generator/proto/nanopb.proto","size":8421,"hash":"1a50d0822c5ba4395297755b11864af952053be3e0dc44c860f988b1b73c3c55"},{"path":"nanopb/generator/proto/google/protobuf/descriptor.proto","size":52085,"hash":"aee16e1d7f264200cb5c4eacc657a40347350a698faaa700d2585557f4daed11"},{"path":"nanopb/extra/bazel/BUILD.bazel","size":0,"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},{"path":"nanopb/extra/bazel/nanopb_cc_proto_library.bzl","size":3113,"hash":"9ba561ff6b8b6d4a62359bfc41fef904526ca04aa5673468c285448a31947d8d"},{"path":"nanopb/extra/bazel/nanopb_deps.bzl","size":2259,"hash":"73581fa3379220083898cabfcddd4e436ca7fb6bfe275752ea19f3a133187a4b"},{"path":"nanopb/extra/bazel/nanopb_workspace.bzl","size":424,"hash":"41ea4b966de1a2c2070357e2b0a3499be0f7469fdd6fae87aecc464836bbbec4"},{"path":"nanopb/extra/bazel/python_deps.bzl","size":446,"hash":"d8a3b3032adfcf4598257858078181b606720f5a0bd0bd93a005189a1beeb451"},{"path":"nanopb/extra/poetry/poetry_build.sh","size":442,"hash":"6d24ab55fdb89a877314389538851d4306e652e66e7b419f5f138d1af0291e1c"},{"path":"nanopb/extra/poetry/pyproject.toml","size":1061,"hash":"561a213eada3e46c20f11e3ed70290ef9c6a13b6a26eb1655f6bc633ae179525"},{"path":"nanopb/extra/script_wrappers/nanopb_generator.py.in","size":1052,"hash":"a06eaff39029b61e0f9c37e4ad3aa312aa1a12b703ba1a9bd3f1a0b843f130c5"},{"path":"nanopb/examples/cmake_relpath/CMakeLists.txt","size":383,"hash":"a485c7bbdabde8a77fee9fd1e024b245515d15fe92534fd0e1a13b2619fffd28"},{"path":"nanopb/examples/cmake_relpath/README.txt","size":533,"hash":"527a900f059ddb3b3d4617af3a65b1841ba8ea62251c94b33d443e302ac80b09"},{"path":"nanopb/examples/cmake_relpath/simple.c","size":2323,"hash":"1d2f56e6e8ddf8dc6c4e1d64451b9e8eb3183581fe88a9a5cdf381b9012f700c"},{"path":"nanopb/examples/cmake_simple/CMakeLists.txt","size":338,"hash":"d84c05afdf6dfaedca37326069f2b5c1e3ac34562672fe938d56904a9a619c45"},{"path":"nanopb/examples/cmake_simple/README.txt","size":533,"hash":"527a900f059ddb3b3d4617af3a65b1841ba8ea62251c94b33d443e302ac80b09"},{"path":"nanopb/examples/cmake_simple/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/examples/cmake_simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/conan_dependency/.gitignore","size":7,"hash":"181314065df2f2fdaf920b1a8b5311daa216a2d6489a06ada5b49cc514d89417"},{"path":"nanopb/examples/conan_dependency/CMakeLists.txt","size":316,"hash":"ddca586c17ba179aed6daa2589d2bb95619f825d1e17cf6537b90ecafbf1692e"},{"path":"nanopb/examples/conan_dependency/README.md","size":835,"hash":"361f3bd7e8c84ea7ddfdc7cc595e8cb734c9c46802cbe16ce662e42d26f463e5"},{"path":"nanopb/examples/conan_dependency/conanfile.py","size":1522,"hash":"f904a40804ffad2a4005f0c937a529faff78ebaac00cd6775791ed78808c9fd3"},{"path":"nanopb/examples/network_server/Makefile","size":356,"hash":"49984487e6fdf8a75ea1a1c01deee25d6b254adce9701e10f0c8469ca49225a2"},{"path":"nanopb/examples/network_server/README.txt","size":2135,"hash":"bb568a5ebd4d1160d3d023fd7b0c4812125e5d74a627abb076ea79bdcd8508aa"},{"path":"nanopb/examples/network_server/client.c","size":3880,"hash":"663b58ec2b4b052f13ed9e2e41386755b47d0f9f0c92cbbb9c09ede2869a7b3a"},{"path":"nanopb/examples/network_server/common.c","size":963,"hash":"3655262342478a76606f12f6e754a9d791648a14d534183d5e162e1c5293d53b"},{"path":"nanopb/examples/network_server/common.h","size":175,"hash":"6774fd7579f0a234f7ad7855b9aa0ae92b6266b25ba98afe4631cb03ccaba527"},{"path":"nanopb/examples/network_server/fileproto.options","size":632,"hash":"5069d54fd9161371d7ba652f9a7e816f5ec6e4c346fde90646340597b3d0e25e"},{"path":"nanopb/examples/network_server/fileproto.proto","size":423,"hash":"cb5d19a1b1d612432da0a1b268940e83fe9823c4382fd1a14943418e8ae73fe4"},{"path":"nanopb/examples/network_server/server.c","size":4792,"hash":"e935ea58afd780716995a5460a74b2e76f8be8f75fe3e38ee3b7285c98427ac4"},{"path":"nanopb/examples/platformio/.gitignore","size":66,"hash":"4b919aca11aac3e4dbbef0c89d891589e001c7658d692a4e4a01649293d0113e"},{"path":"nanopb/examples/platformio/platformio.ini","size":1205,"hash":"7d322a37b755c419633cb9b1f3ce5195190e7a7bb24d4441e4a5fdd969a26bbb"},{"path":"nanopb/examples/simple/Makefile","size":722,"hash":"5ce1951380f8b0d5da93ea0a665a85edad46a5339219df6d1b293a05e15f550f"},{"path":"nanopb/examples/simple/README.txt","size":848,"hash":"68b2b49a081cf5dd77066ab737ea095e05c25194216eec8c02e90eb45fc878b6"},{"path":"nanopb/examples/simple/simple.c","size":2218,"hash":"73a78d512608c349bf453f2f1f0eac677a2a9fd269ca5c34a10aa90ece85fe14"},{"path":"nanopb/examples/simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/using_union_messages/Makefile","size":412,"hash":"3147a8df59d0bce38b280c808a028704ba15611526951c0c1f3c06ce1237e901"},{"path":"nanopb/examples/using_union_messages/README.txt","size":2039,"hash":"27e889e281d7c526ac59428e1a13eb4c11d5f39586a1e6352d0b9fd81f8d1ae8"},{"path":"nanopb/examples/using_union_messages/decode.c","size":2620,"hash":"19eb903f44bcc653c80b834d51f3c25a6aff0308dbb04941c32a169523a0e934"},{"path":"nanopb/examples/using_union_messages/encode.c","size":2321,"hash":"4c72ed7cad5fa372039c46b6ba38c3bce90696e03830ba49bd49deb8d02e8dae"},{"path":"nanopb/examples/using_union_messages/unionproto.proto","size":631,"hash":"35e57746e681686afa461b2d697b469470dbaaa5995a08062d14d2f9426baf3a"},{"path":"nanopb/examples/platformio/proto/pio_with_options.options","size":39,"hash":"fdf7a2a9911019c828ff768ff84b54b752f1ae4c908977d4ecd8d51ec707fe23"},{"path":"nanopb/examples/platformio/proto/pio_with_options.proto","size":73,"hash":"b99efe4689e541cca1b76801b36747206bae31e0db384e14efe8eaf613312d29"},{"path":"nanopb/examples/platformio/proto/pio_without_options.proto","size":78,"hash":"0dbe95539ece82068e4af92a65d3b55e3f01d631376b6b442bead06bd290194c"},{"path":"nanopb/examples/platformio/src/CMakeLists.txt","size":62,"hash":"65c02481b7c1959cf9bbbb91e5b3a8cf63c5886aef5335a517359c4ded82867c"},{"path":"nanopb/examples/platformio/src/pio_esp32_idf.c","size":763,"hash":"cc6b9b46387aa45caef62e79d660da8424844335bb10da5347b5f67b58672760"},{"path":"nanopb/examples/platformio/src/pio_with_options.c","size":800,"hash":"3d9d8652170dfd1e7986f7d8351c9d9231b9995ec870a3bffdeb7793a5797c45"},{"path":"nanopb/examples/platformio/src/pio_without_options.c","size":801,"hash":"7c5410fb5446399441e2b451dd70b3b32307a0accd8b53c634bc2bcb554cfe57"},{"path":"nanopb/examples/platformio/src/test.h","size":248,"hash":"44e7f0c6214f3d710b0e16c72e877478576cb6fe59749df2edb07093f799de5c"},{"path":"nanopb/examples/conan_dependency/protos/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/examples/conan_dependency/src/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/examples/cmake_relpath/proto/simple.proto","size":226,"hash":"b5e1093b44d508ad17b9c8cded9432841c0d743a1d012472f4b996b92f390e64"},{"path":"nanopb/examples/cmake_relpath/proto/sub/unlucky.proto","size":75,"hash":"094f24d42a0f923294c663dca845e5592130901ae336df08d11f5a0216ff99b6"},{"path":"nanopb/docs/logo/logo.png","size":14973,"hash":"667f421b126598c0e53d8b28eef46d4d771c3e5138f43a10a088221a04dc5117"},{"path":"nanopb/docs/logo/logo.svg","size":103905,"hash":"19ff117ba34ef6b7c2f1ad9a88c618175662a657054b40a698df29f29b44327a"},{"path":"nanopb/docs/logo/logo16px.png","size":854,"hash":"1f034014fb4a31253ba96e474007b3ff91ba1ac552a64989d6867670f311ef1f"},{"path":"nanopb/docs/logo/logo48px.png","size":2577,"hash":"26d67f96d672d284a29b8678dfc21f6222bd0099b876ac5d95d3ec18382be6c4"},{"path":"nanopb/build-tests/cmake_with_components/CMakeLists.txt","size":371,"hash":"5ee734dcaa02cee58f049458c616f68b08ddba0f4c72e25d1a598212ef438cc5"},{"path":"nanopb/build-tests/cmake_with_components/simple.cpp","size":2200,"hash":"60dba84e4246937899ebfa7d63fc4fea9c9de0f1dad29a8f9009210b74b2f23b"},{"path":"nanopb/build-tests/cmake_with_components/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/build-tests/legacy_cmake_relpath/CMakeLists.txt","size":478,"hash":"a1db5abcf879c2649edb6604a434f57b215bd03a20c16c39db0a8c80b36fb6d1"},{"path":"nanopb/build-tests/legacy_cmake_relpath/simple.c","size":2323,"hash":"1d2f56e6e8ddf8dc6c4e1d64451b9e8eb3183581fe88a9a5cdf381b9012f700c"},{"path":"nanopb/build-tests/legacy_cmake_simple/CMakeLists.txt","size":432,"hash":"58544be0ea7cf473d6c1f5ec0979711f68a7cd81f96b59b67f3f6d6c92815ea3"},{"path":"nanopb/build-tests/legacy_cmake_simple/simple.c","size":2213,"hash":"263319bc99422dc8f63069f5058f9aaacda4762a275359ca2107d30e26db4aca"},{"path":"nanopb/build-tests/legacy_cmake_simple/simple.proto","size":158,"hash":"6d8836c38dfb09a74334b117ec21e6059d4335781b6206bc95e052912dc84ccb"},{"path":"nanopb/build-tests/legacy_cmake_relpath/proto/simple.proto","size":226,"hash":"b5e1093b44d508ad17b9c8cded9432841c0d743a1d012472f4b996b92f390e64"},{"path":"nanopb/build-tests/legacy_cmake_relpath/proto/sub/unlucky.proto","size":75,"hash":"094f24d42a0f923294c663dca845e5592130901ae336df08d11f5a0216ff99b6"},{"path":"mock/src/main.c","size":1448,"hash":"72a02425928b7af4f8f52add7e350fbd99e2bc71825402743526b4d85d55ef6d"},{"path":"mock/src/appfs_mock/appfs.c","size":1310,"hash":"c21e0b9ac9ddd0f19539a4f4b40708baa627b3691685f8ea0dac19bd7b724b1d"},{"path":"mock/src/appfs_mock/appfs.h","size":1196,"hash":"616365f35c4291ae92a26a9de0af988af3a098d880dc1abc3ca7ecf32214f3fc"},{"path":"mock/src/esp_mock/esp_crc.c","size":226,"hash":"d7349c212c743a1ad24421b20f5781e52415144929cb5a3f72398640d578c784"},{"path":"mock/src/esp_mock/esp_crc.h","size":210,"hash":"6370cf7a78e0c4f5b6c76b0425eb2c626e2eed4b78c993a86f15084369a252d0"},{"path":"mock/src/esp_mock/esp_err.c","size":398,"hash":"437a8c35828a1718d47d3ea31d8f04ca6a4e9ec237b21ce0288e262799214106"},{"path":"mock/src/esp_mock/esp_err.h","size":286,"hash":"83f9730df1683d2cd34ea85cbb308c8c00cadf57cec1945929aaa7a7465a549a"},{"path":"mock/src/esp_mock/esp_err_defs.inc","size":356,"hash":"61060bbc153478643932134c19229fb79cd923d73bacd9c806eedf0d1008af08"},{"path":"mock/src/esp_mock/esp_log.c","size":1547,"hash":"7bfaeb794fa5a7f430767ba801c228bbe1d676873216f990815da87f27334659"},{"path":"mock/src/esp_mock/esp_log.h","size":684,"hash":"d589d4354efc03c6bb3436faa3e41b342cbccc1e572cd3440fdcd56badaa4cfd"},{"path":"mock/src/esp_mock/nvs.c","size":5574,"hash":"27e33362e3870132752f73608a846aae175d001be17f27537b323e32efaefe5a"},{"path":"mock/src/esp_mock/nvs.h","size":3295,"hash":"97c036bcd59358517508f448f62a3d90e6f857584f21cbed96b3caf778ca7e66"},{"path":"mock/src/esp_mock/nvs_flash.h","size":97,"hash":"4da7fa596ae1858282dda9dd89abb78df0dd42153493850c5c65a94bce858fe1"},{"path":"mock/src/freertos_mock/freertos.c","size":1016,"hash":"b23a3d171114a2744e446f1b7d3f784c44b07245dca59231dd09caf71050f0cb"},{"path":"mock/src/freertos_mock/freertos/FreeRTOS.h","size":680,"hash":"73e7c089d5ff30c678916456721c311d7a1b93d6f4352e3ac3ead10d90c409fd"}]} \ No newline at end of file diff --git a/ProtocolV2.md b/ProtocolV2.md index 2d5a077..3fd9157 100644 --- a/ProtocolV2.md +++ b/ProtocolV2.md @@ -87,26 +87,6 @@ Version 2 changes how file downloads work to improve performance for large files **Benefit**: Download starts immediately without reading the entire file first. -### Client Implementation for Downloads - -``` -1. Send download request -2. Receive initial response with size (and crc32) -3. If protocol version >= 2: - - Ignore crc32 field (it will be 0) - - Initialize local running_crc = 0 -4. Request chunks with XferContinue -5. For each chunk received: - - Update local running_crc -6. Send XferFinish -7. If protocol version >= 2: - - Receive FsActionResp/AppfsActionResp with final crc32 - - Compare with local running_crc -8. If protocol version 1: - - Receive StatusOk - - Compare local running_crc with crc32 from step 2 -``` - ### Response Differences | Event | Version 1 | Version 2 | diff --git a/idf_component.yml b/idf_component.yml index d059d6a..8dcb5b7 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,12 +1,8 @@ -dependencies: - badgeteam/appfs: '>=1.0.1' - idf: '>=5.4' description: Protobuf protocol for managing basic device functions -issues: https://github.com/badgeteam/esp32-component-badgelink/issues -license: MIT -repository: git://github.com/badgeteam/esp32-component-badgelink.git -repository_info: - commit_sha: aff9b2bbad34db5fc873c66bef247bfbf4ef6328 - path: . url: https://github.com/badgeteam/esp32-component-badgelink -version: 0.0.4 +repository: git://git@github.com:badgeteam/esp32-component-badgelink.git +issues: https://github.com/badgeteam/esp32-component-badgelink/issues +dependencies: + idf: ">=5.4" + badgeteam/appfs: ">=1.0.1" +license: "MIT" From a9c3040a5236afa097b98336f9adee94f3d365a5 Mon Sep 17 00:00:00 2001 From: Rene Schickbauer Date: Fri, 12 Dec 2025 00:34:54 +0100 Subject: [PATCH 7/8] Cleanup --- tools/badgelink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/badgelink.py b/tools/badgelink.py index d75764b..8be2e7b 100755 --- a/tools/badgelink.py +++ b/tools/badgelink.py @@ -1093,7 +1093,7 @@ def print_row(row: list[str]): try: if args.port: - port = Serial(port=args.port, baudrate=4000000) + port = Serial(port=args.port, baudrate=115200) elif args.inpipe: infd = open(args.inpipe, "rb") outfd = open(args.outpipe, "wb") From 7b14dcd95b640a4d588c801be4b7d69889fda0a4 Mon Sep 17 00:00:00 2001 From: cavac Date: Tue, 16 Dec 2025 15:46:29 +0100 Subject: [PATCH 8/8] Tweaks to badglelink V2, update badgelink.proto to match --- ProtocolV2.md | 27 ++++++- badgelink.pb.h | 8 +- badgelink.proto | 11 +++ tools/badgelink.py | 68 ++++------------ tools/libraries/badgelink_pb2.py | 129 +++++++++++++++---------------- 5 files changed, 116 insertions(+), 127 deletions(-) diff --git a/ProtocolV2.md b/ProtocolV2.md index 3fd9157..e15e2d6 100644 --- a/ProtocolV2.md +++ b/ProtocolV2.md @@ -12,7 +12,7 @@ Sent by the client to negotiate the protocol version. | Field | Tag | Type | Description | |-------|-----|------|-------------| -| client_version | 1 | uint16 | Highest protocol version supported by the client | +| client_version | 1 | uint32 | Highest protocol version supported by the client | #### VersionResp (Response tag 6) @@ -20,8 +20,8 @@ Sent by the server in response to a VersionReq. | Field | Tag | Type | Description | |-------|-----|------|-------------| -| server_version | 1 | uint16 | Highest protocol version supported by the server | -| negotiated_version | 2 | uint16 | Protocol version to use for this session | +| server_version | 1 | uint32 | Highest protocol version supported by the server | +| negotiated_version | 2 | uint32 | Protocol version to use for this session | ### Negotiation Algorithm @@ -123,3 +123,24 @@ Use `--version1` when you need to connect using the legacy protocol, for example # Force version 1 protocol ./badgelink.sh --version1 fs download /sd/file.bin local_file.bin ``` + +--- + +## Revision History + +### 2025-12-16: Field Type Change (uint16 to uint32) + +The version fields in `VersionReq` and `VersionResp` were changed from `uint16` to `uint32`. + +**Reason**: Protocol Buffers (proto3) does not have a native `uint16` type. The smallest unsigned integer type available is `uint32`. While nanopb can generate C code with `uint16_t` fields using options, this creates inconsistency between the C implementation and other language bindings (Python, etc.) which use `uint32`. + +**Changes made**: + +| File | Change | +|------|--------| +| `badgelink.proto` | Added `VersionReq` and `VersionResp` messages with `uint32` fields | +| `badgelink.pb.h` | Changed struct fields from `uint16_t` to `uint32_t` | +| `tools/libraries/badgelink_pb2.py` | Regenerated from updated proto file | +| `tools/badgelink.py` | Simplified to use generated protobuf classes instead of manual encoding | + +**Wire compatibility**: This change is wire-compatible. Protobuf varints encode small values (like version numbers 1, 2, etc.) identically regardless of whether the field is declared as `uint16` or `uint32`. Existing implementations will continue to work. diff --git a/badgelink.pb.h b/badgelink.pb.h index 2250ce8..454ec23 100644 --- a/badgelink.pb.h +++ b/badgelink.pb.h @@ -103,15 +103,15 @@ typedef enum _badgelink_NvsValueType { /* Protocol version request. */ typedef struct _badgelink_VersionReq { /* Highest protocol version supported by client. */ - uint16_t client_version; + uint32_t client_version; } badgelink_VersionReq; /* Protocol version response. */ typedef struct _badgelink_VersionResp { /* Highest protocol version supported by server. */ - uint16_t server_version; + uint32_t server_version; /* Negotiated protocol version (min of client and server). */ - uint16_t negotiated_version; + uint32_t negotiated_version; } badgelink_VersionResp; typedef struct _badgelink_StartAppReq { @@ -795,6 +795,8 @@ extern const pb_msgdesc_t badgelink_NvsActionResp_msg; #define badgelink_Request_size 4153 #define badgelink_Response_size 5134 #define badgelink_StartAppReq_size 179 +#define badgelink_VersionReq_size 6 +#define badgelink_VersionResp_size 12 #ifdef __cplusplus } /* extern "C" */ diff --git a/badgelink.proto b/badgelink.proto index 2256260..e8cfa8f 100644 --- a/badgelink.proto +++ b/badgelink.proto @@ -190,6 +190,7 @@ message Request { NvsActionReq nvs_action = 4; StartAppReq start_app = 5; XferReq xfer_ctrl = 6; + VersionReq version_req = 7; } } @@ -199,6 +200,7 @@ message Response { AppfsActionResp appfs_resp = 3; FsActionResp fs_resp = 4; NvsActionResp nvs_resp = 5; + VersionResp version_resp = 6; } StatusCode status_code = 1; @@ -208,3 +210,12 @@ message StartAppReq { string slug = 1; string arg = 2; } + +message VersionReq { + uint32 client_version = 1; +} + +message VersionResp { + uint32 server_version = 1; + uint32 negotiated_version = 2; +} diff --git a/tools/badgelink.py b/tools/badgelink.py index 8be2e7b..a8c1b17 100755 --- a/tools/badgelink.py +++ b/tools/badgelink.py @@ -332,6 +332,8 @@ def simple_request(self, request: Request|FsActionReq|AppfsActionReq|NvsActionRe request = Request(upload_chunk=request) elif type(request) == StartAppReq: request = Request(start_app=request) + elif type(request) == VersionReq: + request = Request(version_req=request) elif type(request) != Request: raise TypeError("Invalid request type") @@ -397,65 +399,25 @@ def _negotiate_version(self): Sends a VersionReq and handles the response. """ try: - # Build VersionReq manually since it's not in the generated protobuf - # Request tag 7, field 1 = client_version (uint16) - # We'll send this as a raw request - self.conn.serial_no = (self.conn.serial_no + 1) % (1 << 32) + resp = self.conn.simple_request( + VersionReq(client_version=self.PROTOCOL_VERSION), + timeout=self.def_timeout + ) - # Create a packet with version request - # The version_req is tag 7 in Request oneof - # VersionReq has client_version as field 1 (uint32 in protobuf wire format) - packet = Packet(serial=self.conn.serial_no) - packet.request.SetInParent() - - # Manually encode version request: tag 7, field 1 = PROTOCOL_VERSION - # Using protobuf wire format: field 1 varint = client_version - version_req_bytes = b'\x08' + bytes([self.PROTOCOL_VERSION]) # field 1, varint - - # Set the raw bytes for the version_req field (tag 7) - # This is a workaround since VersionReq isn't in the generated code - raw_request = b'\x3a' + bytes([len(version_req_bytes)]) + version_req_bytes # tag 7, length-delimited - - # Build full packet manually - serial_bytes = b'\x08' + self._encode_varint(self.conn.serial_no) # field 1 = serial - request_wrapper = b'\x12' + bytes([len(raw_request)]) + raw_request # field 2 = request - - full_packet = serial_bytes + request_wrapper - self.conn.send_frame(full_packet) - - resp_packet = self.conn.recv_packet(self.def_timeout) - - if resp_packet.response.status_code == StatusCode.StatusNotSupported: - # Old server, use protocol version 1 - self.protocol_version = 1 - print("Server uses protocol version 1 (legacy)") - elif resp_packet.response.status_code == StatusCode.StatusOk: - # Parse version response from raw bytes - # Response tag 6 = version_resp - # VersionResp: field 1 = server_version, field 2 = negotiated_version - if resp_packet.response.HasField('fs_resp'): - # Version response comes back as fs_resp due to tag collision workaround - # Actually, we need to check the raw response - pass - # For now, if we got StatusOk, assume v2 - self.protocol_version = 2 - print(f"Negotiated protocol version {self.protocol_version}") + if resp.HasField('version_resp'): + self.protocol_version = resp.version_resp.negotiated_version + print(f"Negotiated protocol version {self.protocol_version} (server supports v{resp.version_resp.server_version})") else: - # Unexpected response, fall back to v1 + # Unexpected response format, fall back to v1 self.protocol_version = 1 - except (TimeoutError, NotSupportedError): + except NotSupportedError: # Server doesn't support version negotiation, use v1 self.protocol_version = 1 print("Server uses protocol version 1 (legacy)") - - def _encode_varint(self, value: int) -> bytes: - """Encode an integer as a protobuf varint.""" - result = [] - while value > 127: - result.append((value & 0x7f) | 0x80) - value >>= 7 - result.append(value) - return bytes(result) + except TimeoutError: + # Server didn't respond, use v1 + self.protocol_version = 1 + print("Server uses protocol version 1 (legacy)") def start_app(self, slug: str, app_arg: str): """ diff --git a/tools/libraries/badgelink_pb2.py b/tools/libraries/badgelink_pb2.py index 70a5fce..f84a64d 100644 --- a/tools/libraries/badgelink_pb2.py +++ b/tools/libraries/badgelink_pb2.py @@ -1,22 +1,11 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE # source: badgelink.proto -# Protobuf Python Version: 6.33.1 """Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import runtime_version as _runtime_version from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 6, - 33, - 1, - '', - 'badgelink.proto' -) # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -24,61 +13,65 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x62\x61\x64gelink.proto\x12\tbadgelink\"\x9f\x01\n\x0e\x41ppfsActionReq\x12,\n\x08metadata\x18\x02 \x01(\x0b\x32\x18.badgelink.AppfsMetadataH\x00\x12\x0e\n\x04slug\x18\x03 \x01(\tH\x00\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.FsActionType\x12\r\n\x05\x63rc32\x18\x04 \x01(\r\x12\x13\n\x0blist_offset\x18\x05 \x01(\rB\x04\n\x02id\"\xb0\x01\n\x0f\x41ppfsActionResp\x12,\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.badgelink.AppfsMetadataH\x00\x12\x0f\n\x05\x63rc32\x18\x02 \x01(\rH\x00\x12$\n\x04list\x18\x03 \x01(\x0b\x32\x14.badgelink.AppfsListH\x00\x12#\n\x05usage\x18\x04 \x01(\x0b\x32\x12.badgelink.FsUsageH\x00\x12\x0c\n\x04size\x18\x05 \x01(\rB\x05\n\x03val\"G\n\tAppfsList\x12&\n\x04list\x18\x01 \x03(\x0b\x32\x18.badgelink.AppfsMetadata\x12\x12\n\ntotal_size\x18\x02 \x01(\r\"K\n\rAppfsMetadata\x12\x0c\n\x04slug\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\r\x12\x0c\n\x04size\x18\x04 \x01(\r\"\'\n\x05\x43hunk\x12\x10\n\x08position\x18\x02 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"t\n\x0b\x46sActionReq\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.FsActionType\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\r\n\x05\x63rc32\x18\x03 \x01(\r\x12\x13\n\x0blist_offset\x18\x04 \x01(\r\x12\x0c\n\x04size\x18\x05 \x01(\r\"\xa5\x01\n\x0c\x46sActionResp\x12!\n\x04stat\x18\x01 \x01(\x0b\x32\x11.badgelink.FsStatH\x00\x12\x0f\n\x05\x63rc32\x18\x02 \x01(\rH\x00\x12\'\n\x04list\x18\x03 \x01(\x0b\x32\x17.badgelink.FsDirentListH\x00\x12#\n\x05usage\x18\x04 \x01(\x0b\x32\x12.badgelink.FsUsageH\x00\x12\x0c\n\x04size\x18\x05 \x01(\rB\x05\n\x03val\"(\n\x08\x46sDirent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06is_dir\x18\x02 \x01(\x08\"E\n\x0c\x46sDirentList\x12!\n\x04list\x18\x01 \x03(\x0b\x32\x13.badgelink.FsDirent\x12\x12\n\ntotal_size\x18\x02 \x01(\r\"S\n\x06\x46sStat\x12\x0c\n\x04size\x18\x01 \x01(\r\x12\r\n\x05mtime\x18\x02 \x01(\x04\x12\r\n\x05\x63time\x18\x03 \x01(\x04\x12\r\n\x05\x61time\x18\x04 \x01(\x04\x12\x0e\n\x06is_dir\x18\x05 \x01(\x08\"%\n\x07\x46sUsage\x12\x0c\n\x04size\x18\x01 \x01(\r\x12\x0c\n\x04used\x18\x02 \x01(\r\"\xb9\x01\n\x0cNvsActionReq\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.badgelink.NvsActionType\x12\x0f\n\x07namespc\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\"\n\x05wdata\x18\x04 \x01(\x0b\x32\x13.badgelink.NvsValue\x12\x13\n\x0blist_offset\x18\x05 \x01(\r\x12*\n\tread_type\x18\x06 \x01(\x0e\x32\x17.badgelink.NvsValueType\"j\n\rNvsActionResp\x12$\n\x05rdata\x18\x01 \x01(\x0b\x32\x13.badgelink.NvsValueH\x00\x12,\n\x07\x65ntries\x18\x02 \x01(\x0b\x32\x19.badgelink.NvsEntriesListH\x00\x42\x05\n\x03val\"M\n\x0eNvsEntriesList\x12$\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x13.badgelink.NvsEntry\x12\x15\n\rtotal_entries\x18\x02 \x01(\r\"O\n\x08NvsEntry\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.NvsValueType\x12\x0f\n\x07namespc\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\"v\n\x08NvsValue\x12\x14\n\nnumericval\x18\x02 \x01(\x04H\x00\x12\x13\n\tstringval\x18\x03 \x01(\tH\x00\x12\x11\n\x07\x62lobval\x18\x04 \x01(\x0cH\x00\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.NvsValueTypeB\x05\n\x03val\"\x82\x01\n\x06Packet\x12%\n\x07request\x18\x02 \x01(\x0b\x32\x12.badgelink.RequestH\x00\x12\'\n\x08response\x18\x03 \x01(\x0b\x32\x13.badgelink.ResponseH\x00\x12\x0e\n\x04sync\x18\x04 \x01(\x08H\x00\x12\x0e\n\x06serial\x18\x01 \x01(\x04\x42\x08\n\x06packet\"\x9f\x02\n\x07Request\x12(\n\x0cupload_chunk\x18\x01 \x01(\x0b\x32\x10.badgelink.ChunkH\x00\x12\x31\n\x0c\x61ppfs_action\x18\x02 \x01(\x0b\x32\x19.badgelink.AppfsActionReqH\x00\x12+\n\tfs_action\x18\x03 \x01(\x0b\x32\x16.badgelink.FsActionReqH\x00\x12-\n\nnvs_action\x18\x04 \x01(\x0b\x32\x17.badgelink.NvsActionReqH\x00\x12+\n\tstart_app\x18\x05 \x01(\x0b\x32\x16.badgelink.StartAppReqH\x00\x12\'\n\txfer_ctrl\x18\x06 \x01(\x0e\x32\x12.badgelink.XferReqH\x00\x42\x05\n\x03req\"\xf6\x01\n\x08Response\x12*\n\x0e\x64ownload_chunk\x18\x02 \x01(\x0b\x32\x10.badgelink.ChunkH\x00\x12\x30\n\nappfs_resp\x18\x03 \x01(\x0b\x32\x1a.badgelink.AppfsActionRespH\x00\x12*\n\x07\x66s_resp\x18\x04 \x01(\x0b\x32\x17.badgelink.FsActionRespH\x00\x12,\n\x08nvs_resp\x18\x05 \x01(\x0b\x32\x18.badgelink.NvsActionRespH\x00\x12*\n\x0bstatus_code\x18\x01 \x01(\x0e\x32\x15.badgelink.StatusCodeB\x06\n\x04resp\"(\n\x0bStartAppReq\x12\x0c\n\x04slug\x18\x01 \x01(\t\x12\x0b\n\x03\x61rg\x18\x02 \x01(\t*\xbf\x01\n\x0c\x46sActionType\x12\x10\n\x0c\x46sActionList\x10\x00\x12\x12\n\x0e\x46sActionDelete\x10\x01\x12\x11\n\rFsActionMkdir\x10\x02\x12\x12\n\x0e\x46sActionUpload\x10\x03\x12\x14\n\x10\x46sActionDownload\x10\x04\x12\x10\n\x0c\x46sActionStat\x10\x05\x12\x11\n\rFsActionCrc23\x10\x06\x12\x14\n\x10\x46sActionGetUsage\x10\x07\x12\x11\n\rFsActionRmdir\x10\x08*^\n\rNvsActionType\x12\x11\n\rNvsActionList\x10\x00\x12\x11\n\rNvsActionRead\x10\x01\x12\x12\n\x0eNvsActionWrite\x10\x02\x12\x13\n\x0fNvsActionDelete\x10\x03*\xce\x01\n\x0cNvsValueType\x12\x11\n\rNvsValueUint8\x10\x00\x12\x10\n\x0cNvsValueInt8\x10\x01\x12\x12\n\x0eNvsValueUint16\x10\x02\x12\x11\n\rNvsValueInt16\x10\x03\x12\x12\n\x0eNvsValueUint32\x10\x04\x12\x11\n\rNvsValueInt32\x10\x05\x12\x12\n\x0eNvsValueUint64\x10\x06\x12\x11\n\rNvsValueInt64\x10\x07\x12\x12\n\x0eNvsValueString\x10\x08\x12\x10\n\x0cNvsValueBlob\x10\t*\xe8\x01\n\nStatusCode\x12\x0c\n\x08StatusOk\x10\x00\x12\x16\n\x12StatusNotSupported\x10\x01\x12\x12\n\x0eStatusNotFound\x10\x02\x12\x13\n\x0fStatusMalformed\x10\x03\x12\x17\n\x13StatusInternalError\x10\x04\x12\x16\n\x12StatusIllegalState\x10\x05\x12\x11\n\rStatusNoSpace\x10\x06\x12\x12\n\x0eStatusNotEmpty\x10\x07\x12\x10\n\x0cStatusIsFile\x10\x08\x12\x0f\n\x0bStatusIsDir\x10\t\x12\x10\n\x0cStatusExists\x10\n*:\n\x07XferReq\x12\x10\n\x0cXferContinue\x10\x00\x12\r\n\tXferAbort\x10\x01\x12\x0e\n\nXferFinish\x10\x02\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x62\x61\x64gelink.proto\x12\tbadgelink\"\x9f\x01\n\x0e\x41ppfsActionReq\x12,\n\x08metadata\x18\x02 \x01(\x0b\x32\x18.badgelink.AppfsMetadataH\x00\x12\x0e\n\x04slug\x18\x03 \x01(\tH\x00\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.FsActionType\x12\r\n\x05\x63rc32\x18\x04 \x01(\r\x12\x13\n\x0blist_offset\x18\x05 \x01(\rB\x04\n\x02id\"\xb0\x01\n\x0f\x41ppfsActionResp\x12,\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.badgelink.AppfsMetadataH\x00\x12\x0f\n\x05\x63rc32\x18\x02 \x01(\rH\x00\x12$\n\x04list\x18\x03 \x01(\x0b\x32\x14.badgelink.AppfsListH\x00\x12#\n\x05usage\x18\x04 \x01(\x0b\x32\x12.badgelink.FsUsageH\x00\x12\x0c\n\x04size\x18\x05 \x01(\rB\x05\n\x03val\"G\n\tAppfsList\x12&\n\x04list\x18\x01 \x03(\x0b\x32\x18.badgelink.AppfsMetadata\x12\x12\n\ntotal_size\x18\x02 \x01(\r\"K\n\rAppfsMetadata\x12\x0c\n\x04slug\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\r\x12\x0c\n\x04size\x18\x04 \x01(\r\"\'\n\x05\x43hunk\x12\x10\n\x08position\x18\x02 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"t\n\x0b\x46sActionReq\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.FsActionType\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\r\n\x05\x63rc32\x18\x03 \x01(\r\x12\x13\n\x0blist_offset\x18\x04 \x01(\r\x12\x0c\n\x04size\x18\x05 \x01(\r\"\xa5\x01\n\x0c\x46sActionResp\x12!\n\x04stat\x18\x01 \x01(\x0b\x32\x11.badgelink.FsStatH\x00\x12\x0f\n\x05\x63rc32\x18\x02 \x01(\rH\x00\x12\'\n\x04list\x18\x03 \x01(\x0b\x32\x17.badgelink.FsDirentListH\x00\x12#\n\x05usage\x18\x04 \x01(\x0b\x32\x12.badgelink.FsUsageH\x00\x12\x0c\n\x04size\x18\x05 \x01(\rB\x05\n\x03val\"(\n\x08\x46sDirent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06is_dir\x18\x02 \x01(\x08\"E\n\x0c\x46sDirentList\x12!\n\x04list\x18\x01 \x03(\x0b\x32\x13.badgelink.FsDirent\x12\x12\n\ntotal_size\x18\x02 \x01(\r\"S\n\x06\x46sStat\x12\x0c\n\x04size\x18\x01 \x01(\r\x12\r\n\x05mtime\x18\x02 \x01(\x04\x12\r\n\x05\x63time\x18\x03 \x01(\x04\x12\r\n\x05\x61time\x18\x04 \x01(\x04\x12\x0e\n\x06is_dir\x18\x05 \x01(\x08\"%\n\x07\x46sUsage\x12\x0c\n\x04size\x18\x01 \x01(\r\x12\x0c\n\x04used\x18\x02 \x01(\r\"\xb9\x01\n\x0cNvsActionReq\x12&\n\x04type\x18\x01 \x01(\x0e\x32\x18.badgelink.NvsActionType\x12\x0f\n\x07namespc\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\"\n\x05wdata\x18\x04 \x01(\x0b\x32\x13.badgelink.NvsValue\x12\x13\n\x0blist_offset\x18\x05 \x01(\r\x12*\n\tread_type\x18\x06 \x01(\x0e\x32\x17.badgelink.NvsValueType\"j\n\rNvsActionResp\x12$\n\x05rdata\x18\x01 \x01(\x0b\x32\x13.badgelink.NvsValueH\x00\x12,\n\x07\x65ntries\x18\x02 \x01(\x0b\x32\x19.badgelink.NvsEntriesListH\x00\x42\x05\n\x03val\"M\n\x0eNvsEntriesList\x12$\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x13.badgelink.NvsEntry\x12\x15\n\rtotal_entries\x18\x02 \x01(\r\"O\n\x08NvsEntry\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.NvsValueType\x12\x0f\n\x07namespc\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\"v\n\x08NvsValue\x12\x14\n\nnumericval\x18\x02 \x01(\x04H\x00\x12\x13\n\tstringval\x18\x03 \x01(\tH\x00\x12\x11\n\x07\x62lobval\x18\x04 \x01(\x0cH\x00\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.badgelink.NvsValueTypeB\x05\n\x03val\"\x82\x01\n\x06Packet\x12%\n\x07request\x18\x02 \x01(\x0b\x32\x12.badgelink.RequestH\x00\x12\'\n\x08response\x18\x03 \x01(\x0b\x32\x13.badgelink.ResponseH\x00\x12\x0e\n\x04sync\x18\x04 \x01(\x08H\x00\x12\x0e\n\x06serial\x18\x01 \x01(\x04\x42\x08\n\x06packet\"\xcd\x02\n\x07Request\x12(\n\x0cupload_chunk\x18\x01 \x01(\x0b\x32\x10.badgelink.ChunkH\x00\x12\x31\n\x0c\x61ppfs_action\x18\x02 \x01(\x0b\x32\x19.badgelink.AppfsActionReqH\x00\x12+\n\tfs_action\x18\x03 \x01(\x0b\x32\x16.badgelink.FsActionReqH\x00\x12-\n\nnvs_action\x18\x04 \x01(\x0b\x32\x17.badgelink.NvsActionReqH\x00\x12+\n\tstart_app\x18\x05 \x01(\x0b\x32\x16.badgelink.StartAppReqH\x00\x12\'\n\txfer_ctrl\x18\x06 \x01(\x0e\x32\x12.badgelink.XferReqH\x00\x12,\n\x0bversion_req\x18\x07 \x01(\x0b\x32\x15.badgelink.VersionReqH\x00\x42\x05\n\x03req\"\xa6\x02\n\x08Response\x12*\n\x0e\x64ownload_chunk\x18\x02 \x01(\x0b\x32\x10.badgelink.ChunkH\x00\x12\x30\n\nappfs_resp\x18\x03 \x01(\x0b\x32\x1a.badgelink.AppfsActionRespH\x00\x12*\n\x07\x66s_resp\x18\x04 \x01(\x0b\x32\x17.badgelink.FsActionRespH\x00\x12,\n\x08nvs_resp\x18\x05 \x01(\x0b\x32\x18.badgelink.NvsActionRespH\x00\x12.\n\x0cversion_resp\x18\x06 \x01(\x0b\x32\x16.badgelink.VersionRespH\x00\x12*\n\x0bstatus_code\x18\x01 \x01(\x0e\x32\x15.badgelink.StatusCodeB\x06\n\x04resp\"(\n\x0bStartAppReq\x12\x0c\n\x04slug\x18\x01 \x01(\t\x12\x0b\n\x03\x61rg\x18\x02 \x01(\t\"$\n\nVersionReq\x12\x16\n\x0e\x63lient_version\x18\x01 \x01(\r\"A\n\x0bVersionResp\x12\x16\n\x0eserver_version\x18\x01 \x01(\r\x12\x1a\n\x12negotiated_version\x18\x02 \x01(\r*\xbf\x01\n\x0c\x46sActionType\x12\x10\n\x0c\x46sActionList\x10\x00\x12\x12\n\x0e\x46sActionDelete\x10\x01\x12\x11\n\rFsActionMkdir\x10\x02\x12\x12\n\x0e\x46sActionUpload\x10\x03\x12\x14\n\x10\x46sActionDownload\x10\x04\x12\x10\n\x0c\x46sActionStat\x10\x05\x12\x11\n\rFsActionCrc23\x10\x06\x12\x14\n\x10\x46sActionGetUsage\x10\x07\x12\x11\n\rFsActionRmdir\x10\x08*^\n\rNvsActionType\x12\x11\n\rNvsActionList\x10\x00\x12\x11\n\rNvsActionRead\x10\x01\x12\x12\n\x0eNvsActionWrite\x10\x02\x12\x13\n\x0fNvsActionDelete\x10\x03*\xce\x01\n\x0cNvsValueType\x12\x11\n\rNvsValueUint8\x10\x00\x12\x10\n\x0cNvsValueInt8\x10\x01\x12\x12\n\x0eNvsValueUint16\x10\x02\x12\x11\n\rNvsValueInt16\x10\x03\x12\x12\n\x0eNvsValueUint32\x10\x04\x12\x11\n\rNvsValueInt32\x10\x05\x12\x12\n\x0eNvsValueUint64\x10\x06\x12\x11\n\rNvsValueInt64\x10\x07\x12\x12\n\x0eNvsValueString\x10\x08\x12\x10\n\x0cNvsValueBlob\x10\t*\xe8\x01\n\nStatusCode\x12\x0c\n\x08StatusOk\x10\x00\x12\x16\n\x12StatusNotSupported\x10\x01\x12\x12\n\x0eStatusNotFound\x10\x02\x12\x13\n\x0fStatusMalformed\x10\x03\x12\x17\n\x13StatusInternalError\x10\x04\x12\x16\n\x12StatusIllegalState\x10\x05\x12\x11\n\rStatusNoSpace\x10\x06\x12\x12\n\x0eStatusNotEmpty\x10\x07\x12\x10\n\x0cStatusIsFile\x10\x08\x12\x0f\n\x0bStatusIsDir\x10\t\x12\x10\n\x0cStatusExists\x10\n*:\n\x07XferReq\x12\x10\n\x0cXferContinue\x10\x00\x12\r\n\tXferAbort\x10\x01\x12\x0e\n\nXferFinish\x10\x02\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'badgelink_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'badgelink_pb2', _globals) -if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None - _globals['_FSACTIONTYPE']._serialized_start=2376 - _globals['_FSACTIONTYPE']._serialized_end=2567 - _globals['_NVSACTIONTYPE']._serialized_start=2569 - _globals['_NVSACTIONTYPE']._serialized_end=2663 - _globals['_NVSVALUETYPE']._serialized_start=2666 - _globals['_NVSVALUETYPE']._serialized_end=2872 - _globals['_STATUSCODE']._serialized_start=2875 - _globals['_STATUSCODE']._serialized_end=3107 - _globals['_XFERREQ']._serialized_start=3109 - _globals['_XFERREQ']._serialized_end=3167 - _globals['_APPFSACTIONREQ']._serialized_start=31 - _globals['_APPFSACTIONREQ']._serialized_end=190 - _globals['_APPFSACTIONRESP']._serialized_start=193 - _globals['_APPFSACTIONRESP']._serialized_end=369 - _globals['_APPFSLIST']._serialized_start=371 - _globals['_APPFSLIST']._serialized_end=442 - _globals['_APPFSMETADATA']._serialized_start=444 - _globals['_APPFSMETADATA']._serialized_end=519 - _globals['_CHUNK']._serialized_start=521 - _globals['_CHUNK']._serialized_end=560 - _globals['_FSACTIONREQ']._serialized_start=562 - _globals['_FSACTIONREQ']._serialized_end=678 - _globals['_FSACTIONRESP']._serialized_start=681 - _globals['_FSACTIONRESP']._serialized_end=846 - _globals['_FSDIRENT']._serialized_start=848 - _globals['_FSDIRENT']._serialized_end=888 - _globals['_FSDIRENTLIST']._serialized_start=890 - _globals['_FSDIRENTLIST']._serialized_end=959 - _globals['_FSSTAT']._serialized_start=961 - _globals['_FSSTAT']._serialized_end=1044 - _globals['_FSUSAGE']._serialized_start=1046 - _globals['_FSUSAGE']._serialized_end=1083 - _globals['_NVSACTIONREQ']._serialized_start=1086 - _globals['_NVSACTIONREQ']._serialized_end=1271 - _globals['_NVSACTIONRESP']._serialized_start=1273 - _globals['_NVSACTIONRESP']._serialized_end=1379 - _globals['_NVSENTRIESLIST']._serialized_start=1381 - _globals['_NVSENTRIESLIST']._serialized_end=1458 - _globals['_NVSENTRY']._serialized_start=1460 - _globals['_NVSENTRY']._serialized_end=1539 - _globals['_NVSVALUE']._serialized_start=1541 - _globals['_NVSVALUE']._serialized_end=1659 - _globals['_PACKET']._serialized_start=1662 - _globals['_PACKET']._serialized_end=1792 - _globals['_REQUEST']._serialized_start=1795 - _globals['_REQUEST']._serialized_end=2082 - _globals['_RESPONSE']._serialized_start=2085 - _globals['_RESPONSE']._serialized_end=2331 - _globals['_STARTAPPREQ']._serialized_start=2333 - _globals['_STARTAPPREQ']._serialized_end=2373 + DESCRIPTOR._options = None + _FSACTIONTYPE._serialized_start=2575 + _FSACTIONTYPE._serialized_end=2766 + _NVSACTIONTYPE._serialized_start=2768 + _NVSACTIONTYPE._serialized_end=2862 + _NVSVALUETYPE._serialized_start=2865 + _NVSVALUETYPE._serialized_end=3071 + _STATUSCODE._serialized_start=3074 + _STATUSCODE._serialized_end=3306 + _XFERREQ._serialized_start=3308 + _XFERREQ._serialized_end=3366 + _APPFSACTIONREQ._serialized_start=31 + _APPFSACTIONREQ._serialized_end=190 + _APPFSACTIONRESP._serialized_start=193 + _APPFSACTIONRESP._serialized_end=369 + _APPFSLIST._serialized_start=371 + _APPFSLIST._serialized_end=442 + _APPFSMETADATA._serialized_start=444 + _APPFSMETADATA._serialized_end=519 + _CHUNK._serialized_start=521 + _CHUNK._serialized_end=560 + _FSACTIONREQ._serialized_start=562 + _FSACTIONREQ._serialized_end=678 + _FSACTIONRESP._serialized_start=681 + _FSACTIONRESP._serialized_end=846 + _FSDIRENT._serialized_start=848 + _FSDIRENT._serialized_end=888 + _FSDIRENTLIST._serialized_start=890 + _FSDIRENTLIST._serialized_end=959 + _FSSTAT._serialized_start=961 + _FSSTAT._serialized_end=1044 + _FSUSAGE._serialized_start=1046 + _FSUSAGE._serialized_end=1083 + _NVSACTIONREQ._serialized_start=1086 + _NVSACTIONREQ._serialized_end=1271 + _NVSACTIONRESP._serialized_start=1273 + _NVSACTIONRESP._serialized_end=1379 + _NVSENTRIESLIST._serialized_start=1381 + _NVSENTRIESLIST._serialized_end=1458 + _NVSENTRY._serialized_start=1460 + _NVSENTRY._serialized_end=1539 + _NVSVALUE._serialized_start=1541 + _NVSVALUE._serialized_end=1659 + _PACKET._serialized_start=1662 + _PACKET._serialized_end=1792 + _REQUEST._serialized_start=1795 + _REQUEST._serialized_end=2128 + _RESPONSE._serialized_start=2131 + _RESPONSE._serialized_end=2425 + _STARTAPPREQ._serialized_start=2427 + _STARTAPPREQ._serialized_end=2467 + _VERSIONREQ._serialized_start=2469 + _VERSIONREQ._serialized_end=2505 + _VERSIONRESP._serialized_start=2507 + _VERSIONRESP._serialized_end=2572 # @@protoc_insertion_point(module_scope)