You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add USB-Serial-based file transfer feature for ESP32 environment #64
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).
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
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.)
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
Merge into R2P2-ESP32 as a component
Users manually implement the startup condition in main().
Provide some examples about main() implementation.
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.
Keep it as a personal repository (current state)
Add a link from R2P2-ESP32 README as an optional utility.
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.)
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:
Boot into file-transfer mode
Transfer the files
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.
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.
@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;
| ^~~~~~~~~~~~
@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.
Activity
hasumikin commentedon Nov 26, 2025
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:
main()function be maintained properly for many ESP32 variants?kishima commentedon Nov 26, 2025
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:
main()showing how to enter the file transfer mode#ifdefblock)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()isfs_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:
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:
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.
hasumikin commentedon Nov 26, 2025
Yes, I was meaning "ESP32 variant" as you say "board differences".
I think it would be good if the
main()can be built properly using only constant macros for typical boards.yuuu commentedon Nov 29, 2025
Thanks for the suggestion!
I’m planning to add
esp32_uart_file_transferunder thecomponentsdirectory and consider running it as a separate task. Let me give it a try on my side, so please give me a little time.yuuu commentedon Nov 29, 2025
@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?
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?
kishima commentedon Nov 30, 2025
@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.
kishima commentedon Dec 17, 2025
@yuuu I’ve fixed the build error in v5.4.1 and removed the warnings. Could you check the latest main branch?
yuuu commentedon Mar 30, 2026
@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?
kishima commentedon Mar 31, 2026
@yuuu Sure. BLE is better than limited UART.