diff --git a/examples/storage/semihost_vfs/CMakeLists.txt b/examples/storage/semihost_vfs/CMakeLists.txt new file mode 100644 index 000000000..5f6944151 --- /dev/null +++ b/examples/storage/semihost_vfs/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(semihost_vfs) diff --git a/examples/storage/semihost_vfs/Makefile b/examples/storage/semihost_vfs/Makefile new file mode 100644 index 000000000..6a9282104 --- /dev/null +++ b/examples/storage/semihost_vfs/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := semihost_vfs + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/storage/semihost_vfs/README.md b/examples/storage/semihost_vfs/README.md new file mode 100644 index 000000000..4728f0866 --- /dev/null +++ b/examples/storage/semihost_vfs/README.md @@ -0,0 +1,91 @@ +# Semihosting VFS driver example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates how to use semihosting VFS driver with ESP32. Example does the following steps: + +1. Uses `esp_vfs_semihost_register` function to register exposed host directory in VFS, enabling C standard library and POSIX functions to be used. +2. Redirects `stdout` from the UART to the file on the host using `freopen`. +3. Prints several messages to the redirected. +4. Switches back to UART `stdout` using `freopen`. +5. Opens text file on the host. +6. Reads the file and prints its content on stdout. + +## How to use example + +### Hardware and tools required + +This example does not require any special hardware, and can be run on any common development board. +This example requires [OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd). +NOTE: In order to run this example you need OpenOCD version `v0.10.0-esp32-20190313` or later. + +Run OpenOCD using command: +``` +bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -c 'set ESP_SEMIHOST_BASEDIR '$IDF_PATH/examples/storage/semihost_vfs/data -f board/esp-wroom-32.cfg +``` +This command also configures OpenOCD to expose example project `data` subdirectory to the target's semihosting VFS driver. + +### Configure the project + +If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options. + +If using CMake based build system, no configuration is required. + +### Build and flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +make -j4 flash monitor +``` + +Or, for CMake based build system (replace PORT with serial port name): + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +There are two types of outputs produced by example: +1. File `esp32_stdout.txt` in the host directory mounted to the target: + +``` +W (274) example: Switched to semihosted stdout +Semihosted stdout write 0 +Semihosted stdout write 1 +Semihosted stdout write 2 +... +Semihosted stdout write 98 +Semihosted stdout write 99 +W (274) example: Switch to UART stdout +``` + +2. On the boards console: + +``` +W (274) example: Switch to semihosted stdout +W (274) example: Switched back to UART stdout +I (274) example: Wrote 2798 bytes +====================== HOST DATA START ========================= +The following are the graphical (non-control) characters defined by +ISO 8859-1 (1987). Descriptions in words aren't all that helpful, +but they're the best we can do in text. A graphics file illustrating +the character set should be available from the same archive as this +file. + +Hex Description Hex Description + +20 SPACE +... +7D RIGHT CURLY BRACKET FD SMALL LETTER Y WITH ACUTE +7E TILDE FE SMALL LETTER THORN (Icelandic) + FF SMALL LETTER Y WITH DIAERESIS +====================== HOST DATA END ========================= +I (694) example: Read 6121 bytes +``` + diff --git a/examples/storage/semihost_vfs/data/host_file.txt b/examples/storage/semihost_vfs/data/host_file.txt new file mode 100644 index 000000000..f14a8d5b8 --- /dev/null +++ b/examples/storage/semihost_vfs/data/host_file.txt @@ -0,0 +1,104 @@ +The following are the graphical (non-control) characters defined by +ISO 8859-1 (1987). Descriptions in words aren't all that helpful, +but they're the best we can do in text. A graphics file illustrating +the character set should be available from the same archive as this +file. + +Hex Description Hex Description + +20 SPACE +21 EXCLAMATION MARK A1 INVERTED EXCLAMATION MARK +22 QUOTATION MARK A2 CENT SIGN +23 NUMBER SIGN A3 POUND SIGN +24 DOLLAR SIGN A4 CURRENCY SIGN +25 PERCENT SIGN A5 YEN SIGN +26 AMPERSAND A6 BROKEN BAR +27 APOSTROPHE A7 SECTION SIGN +28 LEFT PARENTHESIS A8 DIAERESIS +29 RIGHT PARENTHESIS A9 COPYRIGHT SIGN +2A ASTERISK AA FEMININE ORDINAL INDICATOR +2B PLUS SIGN AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +2C COMMA AC NOT SIGN +2D HYPHEN-MINUS AD SOFT HYPHEN +2E FULL STOP AE REGISTERED SIGN +2F SOLIDUS AF OVERLINE +30 DIGIT ZERO B0 DEGREE SIGN +31 DIGIT ONE B1 PLUS-MINUS SIGN +32 DIGIT TWO B2 SUPERSCRIPT TWO +33 DIGIT THREE B3 SUPERSCRIPT THREE +34 DIGIT FOUR B4 ACUTE ACCENT +35 DIGIT FIVE B5 MICRO SIGN +36 DIGIT SIX B6 PILCROW SIGN +37 DIGIT SEVEN B7 MIDDLE DOT +38 DIGIT EIGHT B8 CEDILLA +39 DIGIT NINE B9 SUPERSCRIPT ONE +3A COLON BA MASCULINE ORDINAL INDICATOR +3B SEMICOLON BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +3C LESS-THAN SIGN BC VULGAR FRACTION ONE QUARTER +3D EQUALS SIGN BD VULGAR FRACTION ONE HALF +3E GREATER-THAN SIGN BE VULGAR FRACTION THREE QUARTERS +3F QUESTION MARK BF INVERTED QUESTION MARK +40 COMMERCIAL AT C0 CAPITAL LETTER A WITH GRAVE +41 CAPITAL LETTER A C1 CAPITAL LETTER A WITH ACUTE +42 CAPITAL LETTER B C2 CAPITAL LETTER A WITH CIRCUMFLEX +43 CAPITAL LETTER C C3 CAPITAL LETTER A WITH TILDE +44 CAPITAL LETTER D C4 CAPITAL LETTER A WITH DIAERESIS +45 CAPITAL LETTER E C5 CAPITAL LETTER A WITH RING ABOVE +46 CAPITAL LETTER F C6 CAPITAL LETTER AE +47 CAPITAL LETTER G C7 CAPITAL LETTER C WITH CEDILLA +48 CAPITAL LETTER H C8 CAPITAL LETTER E WITH GRAVE +49 CAPITAL LETTER I C9 CAPITAL LETTER E WITH ACUTE +4A CAPITAL LETTER J CA CAPITAL LETTER E WITH CIRCUMFLEX +4B CAPITAL LETTER K CB CAPITAL LETTER E WITH DIAERESIS +4C CAPITAL LETTER L CC CAPITAL LETTER I WITH GRAVE +4D CAPITAL LETTER M CD CAPITAL LETTER I WITH ACUTE +4E CAPITAL LETTER N CE CAPITAL LETTER I WITH CIRCUMFLEX +4F CAPITAL LETTER O CF CAPITAL LETTER I WITH DIAERESIS +50 CAPITAL LETTER P D0 CAPITAL LETTER ETH (Icelandic) +51 CAPITAL LETTER Q D1 CAPITAL LETTER N WITH TILDE +52 CAPITAL LETTER R D2 CAPITAL LETTER O WITH GRAVE +53 CAPITAL LETTER S D3 CAPITAL LETTER O WITH ACUTE +54 CAPITAL LETTER T D4 CAPITAL LETTER O WITH CIRCUMFLEX +55 CAPITAL LETTER U D5 CAPITAL LETTER O WITH TILDE +56 CAPITAL LETTER V D6 CAPITAL LETTER O WITH DIAERESIS +57 CAPITAL LETTER W D7 MULTIPLICATION SIGN +58 CAPITAL LETTER X D8 CAPITAL LETTER O WITH STROKE +59 CAPITAL LETTER Y D9 CAPITAL LETTER U WITH GRAVE +5A CAPITAL LETTER Z DA CAPITAL LETTER U WITH ACUTE +5B LEFT SQUARE BRACKET DB CAPITAL LETTER U WITH CIRCUMFLEX +5C REVERSE SOLIDUS DC CAPITAL LETTER U WITH DIAERESIS +5D RIGHT SQUARE BRACKET DD CAPITAL LETTER Y WITH ACUTE +5E CIRCUMFLEX ACCENT DE CAPITAL LETTER THORN (Icelandic) +5F LOW LINE DF SMALL LETTER SHARP S (German) +60 GRAVE ACCENT E0 SMALL LETTER A WITH GRAVE +61 SMALL LETTER A E1 SMALL LETTER A WITH ACUTE +62 SMALL LETTER B E2 SMALL LETTER A WITH CIRCUMFLEX +63 SMALL LETTER C E3 SMALL LETTER A WITH TILDE +64 SMALL LETTER D E4 SMALL LETTER A WITH DIAERESIS +65 SMALL LETTER E E5 SMALL LETTER A WITH RING ABOVE +66 SMALL LETTER F E6 SMALL LETTER AE +67 SMALL LETTER G E7 SMALL LETTER C WITH CEDILLA +68 SMALL LETTER H E8 SMALL LETTER E WITH GRAVE +69 SMALL LETTER I E9 SMALL LETTER E WITH ACUTE +6A SMALL LETTER J EA SMALL LETTER E WITH CIRCUMFLEX +6B SMALL LETTER K EB SMALL LETTER E WITH DIAERESIS +6C SMALL LETTER L EC SMALL LETTER I WITH GRAVE +6D SMALL LETTER M ED SMALL LETTER I WITH ACUTE +6E SMALL LETTER N EE SMALL LETTER I WITH CIRCUMFLEX +6F SMALL LETTER O EF SMALL LETTER I WITH DIAERESIS +70 SMALL LETTER P F0 SMALL LETTER ETH (Icelandic) +71 SMALL LETTER Q F1 SMALL LETTER N WITH TILDE +72 SMALL LETTER R F2 SMALL LETTER O WITH GRAVE +73 SMALL LETTER S F3 SMALL LETTER O WITH ACUTE +74 SMALL LETTER T F4 SMALL LETTER O WITH CIRCUMFLEX +75 SMALL LETTER U F5 SMALL LETTER O WITH TILDE +76 SMALL LETTER V F6 SMALL LETTER O WITH DIAERESIS +77 SMALL LETTER W F7 DIVISION SIGN +78 SMALL LETTER X F8 SMALL LETTER O WITH STROKE +79 SMALL LETTER Y F9 SMALL LETTER U WITH GRAVE +7A SMALL LETTER Z FA SMALL LETTER U WITH ACUTE +7B LEFT CURLY BRACKET FB SMALL LETTER U WITH CIRCUMFLEX +7C VERTICAL LINE FC SMALL LETTER U WITH DIAERESIS +7D RIGHT CURLY BRACKET FD SMALL LETTER Y WITH ACUTE +7E TILDE FE SMALL LETTER THORN (Icelandic) + FF SMALL LETTER Y WITH DIAERESIS diff --git a/examples/storage/semihost_vfs/main/CMakeLists.txt b/examples/storage/semihost_vfs/main/CMakeLists.txt new file mode 100644 index 000000000..34d60ad45 --- /dev/null +++ b/examples/storage/semihost_vfs/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "semihost_vfs_example_main.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/storage/semihost_vfs/main/component.mk b/examples/storage/semihost_vfs/main/component.mk new file mode 100644 index 000000000..a98f634ea --- /dev/null +++ b/examples/storage/semihost_vfs/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c b/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c new file mode 100644 index 000000000..edbeabbbe --- /dev/null +++ b/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c @@ -0,0 +1,92 @@ +/* SPIFFS filesystem example. + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include +#include +#include "esp_err.h" +#include "esp_log.h" +#include "esp_vfs_semihost.h" + +static const char *TAG = "example"; + +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + +static uint8_t s_buf[512]; + +void app_main(void) +{ + // Register host FS at '/host'. On the host file will be written/read in the current semihosting dir of OpenOCD + esp_err_t ret = esp_vfs_semihost_register("/host", NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register semihost driver (%s)!", esp_err_to_name(ret)); + return; + } + + ESP_LOGW(TAG, "Switch to semihosted stdout"); + FILE *fout = freopen("/host/esp32_stdout.txt", "w", stdout); + if (fout == NULL) { + ESP_LOGE(TAG, "Failed to reopen stdout (%d)!", errno); + return; + } + // Increase file buffer to perform data transfers using larger chunks. + // Every read/write triggers breakpoint, so transfering of small chunks is quite inefficient. + setvbuf(fout, (char *)s_buf, _IOFBF, sizeof(s_buf)); + + // this will be printed to the file on host + ESP_LOGW(TAG, "Switched to semihosted stdout"); + for (int i = 0; i < 100; i++) { + // printf is also redirected and sends data to the file on host + printf("Semihosted stdout write %d\n", i); + } + ESP_LOGW(TAG, "Switch to UART stdout"); + fflush(fout); // ensure that all data are sent to the host file + // ftell can also be used, get file size before closing it in `freopen` + int count = ftell(fout); + stdout = freopen("/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM), "w", fout); + if (stdout == NULL) { + ESP_LOGE(TAG, "Failed to reopen semihosted stdout (%d)!", errno); + return; + } + // all remaining messages will be printed to UART + ESP_LOGW(TAG, "Switched back to UART stdout"); + ESP_LOGI(TAG, "Wrote %d bytes", count); + + printf("====================== HOST DATA START =========================\n"); + // open() can also be used to access files on the host + int fd = open("/host/host_file.txt", O_RDONLY, 0); + if (fd == -1) { + ESP_LOGE(TAG, "Failed to open file (%d)!", errno); + return; + } + ssize_t read_bytes; + count = 0; + do { + read_bytes = read(fd, s_buf, sizeof(s_buf)); + if(read_bytes == -1) { + ESP_LOGE(TAG, "Failed to read file (%d)!", errno); + } else if(read_bytes > 0) { + fwrite(s_buf, 1, read_bytes, stdout); + count += read_bytes; + } + } while(read_bytes > 0); + printf("====================== HOST DATA END =========================\n"); + ESP_LOGI(TAG, "Read %d bytes", count); + if (close(fd) == -1) { + ESP_LOGE(TAG, "Failed to close file (%d)!", errno); + } + + ret = esp_vfs_semihost_unregister("/host"); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to unregister semihost driver (%s)!", esp_err_to_name(ret)); + } +} diff --git a/examples/storage/semihost_vfs/sdkconfig.defaults b/examples/storage/semihost_vfs/sdkconfig.defaults new file mode 100644 index 000000000..989d01c23 --- /dev/null +++ b/examples/storage/semihost_vfs/sdkconfig.defaults @@ -0,0 +1,2 @@ +# need this to detect that OpenOCD is connected +CONFIG_ESP32_DEBUG_OCDAWARE=y