Skip to content

Add USB-Serial-based file transfer feature for ESP32 environment #64

Closed

Description

@kishima

Unlike the Raspberry Pi Pico version, the ESP32 version of R2P2 does not currently support MSC (Mass Storage Class).
As a result, users must rebuild and flash the firmware every time they update their Ruby scripts.

In my own project this was a major inconvenience, so I implemented a mechanism that allows a PC-side Ruby script to read and write the ESP32 FAT filesystem over USB-Serial (UART).

Features (already working)

  • One-line commands to read/write files
  • Interactive shell: get, put, cd, ls

Source code (prototype, working):
https://github.com/kishima/esp32_uart_file_transfer


Proposal

I would like to propose adding this USB-Serial-based file transfer feature as an optional component for R2P2-ESP32.
If this functionality is considered useful, I would like to open a PR.


Issues / Concerns

  1. It uses UART0, which is normally occupied by the terminal.
    Therefore, it cannot be used simultaneously with R2P2’s default terminal I/O.
    (Using another UART avoids this but requires an external USB-Serial adapter, reducing convenience.)

  2. Entering “file transfer mode” must occur right after boot and before PicoRuby starts in main().
    However, the trigger method (GPIO, timeout, button, etc.) differs between projects and cannot be standardized.


Possible delivery methods

  1. Merge into R2P2-ESP32 as a component

    • Users manually implement the startup condition in main().
    • Provide some examples about main() implementation.
  2. Provide as a separate repository under the PicoRuby organization

    • Users integrate it manually into their R2P2-ESP32 project.
    • Documentation will explain how to include it.
  3. Keep it as a personal repository (current state)

    • Add a link from R2P2-ESP32 README as an optional utility.

Feedback requested

  • Is this feature useful for R2P2-ESP32 users?
  • Which delivery method (1–3) is preferred?

Thank you.

Activity

  1. hasumikin commented on Nov 26, 2025

    @hasumikin
    Member

    I think "Merge into R2P2-ESP32 as a component" would be the best option.
    But I also want to know more about the downside of this choice.

    Questions:

    • If we ship this feature with the R2P2-ESP32 binary, should the main() function be maintained properly for many ESP32 variants?
    • In any case, is rebooting R2P2 needed when transfering a local file to ESP32?
  2. kishima commented on Nov 26, 2025

    @kishima
    Author

    If we ship this feature with the R2P2-ESP32 binary, should the main() function be maintained properly for many ESP32 variants?

    The implementation in esp32_uart_file_transfer/src/ does not depend on any specific ESP32 variant, so it should be built for all variants without modification.

    The real issue is not the ESP32 variant but the board differences.
    The condition for entering the “file transfer mode” (button GPIO, GPIO logic level, timeout, etc.) is different on each board.
    For example, even within the M5 series, each model uses different GPIO numbers for its buttons.

    Because of this, I think it is unrealistic for R2P2-ESP32 to maintain a fully generic main() that supports all boards.

    If this feature is merged as a component, my suggestion is:

    • Provide a simple example in main() showing how to enter the file transfer mode
    • Keep it disabled by default (commented out or #ifdef block)
    • Each board can override or adjust the condition (GPIO number, logic, etc.)

    Here is an example that I use on the M5StickC Plus2:
    https://github.com/kishima/R2P2-ESP32/blob/uart_file_transfer/main/main.c

    The only function that must be called from main() is fs_proxy_create_task().
    However, this task cannot coexist with normal R2P2 because both require UART0.
    Therefore, in this example, the board checks the state of Button A (GPIO 37) at boot and chooses either:

    • file-transfer mode, or
    • starting PicoRuby.

    In any case, is rebooting R2P2 needed when transfering a local file to ESP32?

    Yes.
    As long as the file transfer uses the USB Serial (UART0), it cannot run at the same time as R2P2.
    So the workflow becomes:

    1. Boot into file-transfer mode
    2. Transfer the files
    3. Reboot into normal R2P2 mode

    This is required because the file-transfer task and R2P2 compete for UART0 and cannot run concurrently.

    If the user uses another UART with a USB-UART converter, then the file-transfer mode could be used without rebooting R2P2.

  3. hasumikin commented on Nov 26, 2025

    @hasumikin
    Member

    The real issue is not the ESP32 variant but the board differences.

    Yes, I was meaning "ESP32 variant" as you say "board differences".

    Keep it disabled by default (commented out or #ifdef block)

    I think it would be good if the main() can be built properly using only constant macros for typical boards.

  4. yuuu commented on Nov 29, 2025

    @yuuu
    Collaborator

    Thanks for the suggestion!

    I’m planning to add esp32_uart_file_transfer under the components directory and consider running it as a separate task. Let me give it a try on my side, so please give me a little time.

  5. yuuu commented on Nov 29, 2025

    @yuuu
    Collaborator

    @kishima
    I’m currently trying to integrate this. #69

    With ESP-IDF v5.4.1 , I encountered the following error.
    It looks like an ESP-IDF-side issue.
    Is there any recommended workaround?

    In file included from /home/yuhei/ghq/github.com/espressif/esp-idf/components/log/include/esp_log.h:15,
                     from /home/yuhei/ghq/github.com/picoruby/R2P2-ESP32/components/esp32_uart_file_transfer/src/fs_proxy.c:11:
    /home/yuhei/ghq/github.com/picoruby/R2P2-ESP32/components/esp32_uart_file_transfer/src/fs_proxy.c: In function 'cmd_get':
    /home/yuhei/ghq/github.com/espressif/esp-idf/components/log/include/esp_log_color.h:98:31: error: format '%d' expects argument of type 'int', but argument 7 has type 'int32_t' {aka 'long int'} [-Werror=format=]
       98 | #define LOG_COLOR_E           ""
          |                               ^~
    

    With ESP-IDF v5.5.1 , I’m getting the following warnings.
    I assume these are caused by unused variables due to commented-out code.
    Is it acceptable to comment out the variable declarations as well?

    /home/yuhei/ghq/github.com/picoruby/R2P2-ESP32/components/esp32_uart_file_transfer/src/fs_proxy.c: In function 'fs_proxy_task':
    /home/yuhei/ghq/github.com/picoruby/R2P2-ESP32/components/esp32_uart_file_transfer/src/fs_proxy.c:791:20: warning: unused variable 'BEACON_INTERVAL' [-Wunused-variable]
      791 |     const uint32_t BEACON_INTERVAL = 50; // Send beacon every 5 seconds (50 * 100ms)
          |                    ^~~~~~~~~~~~~~~
    /home/yuhei/ghq/github.com/picoruby/R2P2-ESP32/components/esp32_uart_file_transfer/src/fs_proxy.c:790:14: warning: variable 'idle_counter' set but not used [-Wunused-but-set-variable]
      790 |     uint32_t idle_counter = 0;
          |              ^~~~~~~~~~~~
    
  6. kishima commented on Nov 30, 2025

    @kishima
    Author

    @hasumikin thank you for your feedback.
    @yuuu Thank you for your effort.
    About the issue on ESP-IDF v5.4.1: let me check it, since I'm using v5.5.1.
    About the warning on ESP-IDF v5.4.1: as I mentioned at the beginning of this issue, my current code is just a prototype, and I haven’t fully checked the warnings yet. I plan to address the warning suppression along with the code cleanup.

  7. kishima commented on Dec 17, 2025

    @kishima
    Author

    @yuuu I’ve fixed the build error in v5.4.1 and removed the warnings. Could you check the latest main branch?

  8. yuuu commented on Mar 30, 2026

    @yuuu
    Collaborator

    @kishima
    I believe this issue has been resolved by the addition of picoruby-picomodem in https://github.com/picoruby/picoruby. Would it be okay to close this?

  9. kishima commented on Mar 31, 2026

    @kishima
    Author

    @yuuu Sure. BLE is better than limited UART.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions