Merge branch 'feature/semihost_vfs' into 'master'

Adds semihosting VFS driver

Closes IDF-367

See merge request idf/esp-idf!4145
This commit is contained in:
Ivan Grokhotkov 2019-03-21 22:03:06 +08:00
commit 3a779380a7
13 changed files with 593 additions and 1 deletions

View File

@ -1,5 +1,6 @@
set(COMPONENT_SRCS "vfs.c"
"vfs_uart.c")
"vfs_uart.c"
"vfs_semihost.c")
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_REQUIRES)

View File

@ -15,4 +15,20 @@ menu "Virtual file system"
help
Disabling this option can save memory when the support for termios.h is not required.
menu "Host File System I/O (Semihosting)"
config SEMIHOSTFS_MAX_MOUNT_POINTS
int "Maximum number of the host filesystem mount points"
default 1
help
Define maximum number of host filesystem mount points.
config SEMIHOSTFS_HOST_PATH_MAX_LEN
int "Maximum path length for the host base directory"
default 128
help
Define maximum path length for the host base directory which is to be mounted.
If host path passed to esp_vfs_semihost_register() is longer than this value
it will be truncated.
endmenu
endmenu

View File

@ -0,0 +1,46 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp_vfs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief add virtual filesystem semihosting driver
*
* @param base_path VFS path to mount host directory
* @param host_path host path to mount; if NULL default dirctory will be used (see OpenOCD configuration)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if esp_vfs_semihost_register was already called for specified VFS path
* - ESP_ERR_NO_MEM if there are no slots to register new mount point
*/
esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path);
/**
* @brief Un-register semihosting driver from VFS
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if semihosting driver is not registered in VFS at that path
*/
esp_err_t esp_vfs_semihost_unregister(const char* base_path);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,216 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "soc/cpu.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_vfs.h"
#define LOG_LOCAL_LEVEL ESP_LOG_NONE
#include "esp_log.h"
const static char *TAG = "esp_semihost";
#define SYSCALL_INSTR "break 1,1\n"
#define SYS_OPEN 0x01
#define SYS_CLOSE 0x02
#define SYS_WRITE 0x05
#define SYS_READ 0x06
#define SYS_SEEK 0x0A
/** ESP-specific file open flag. Indicates that path passed to open() is absolute host path. */
#define ESP_O_SEMIHOST_ABSPATH 0x80000000
typedef struct {
char base_path[ESP_VFS_PATH_MAX+1]; /* base path in VFS where host semohosting dir is mounted */
char host_path[CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN+1]; /* host path to use as base dir for open files */
} vfs_semihost_ctx_t;
static vfs_semihost_ctx_t s_semhost_ctx[CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS];
static inline int generic_syscall(int sys_nr, int arg1, int arg2, int arg3, int arg4, int* ret_errno)
{
int host_ret, host_errno;
if (!esp_cpu_in_ocd_debug_mode()) {
*ret_errno = EIO;
return -1;
}
__asm__ volatile (
"mov a2, %[sys_nr]\n" \
"mov a3, %[arg1]\n" \
"mov a4, %[arg2]\n" \
"mov a5, %[arg3]\n" \
"mov a6, %[arg4]\n" \
SYSCALL_INSTR \
"mov %[host_ret], a2\n" \
"mov %[host_errno], a3\n" \
:[host_ret]"=r"(host_ret),[host_errno]"=r"(host_errno)
:[sys_nr]"r"(sys_nr),[arg1]"r"(arg1),[arg2]"r"(arg2),[arg3]"r"(arg3),[arg4]"r"(arg4)
:"a2","a3","a4","a5","a6");
*ret_errno = host_errno;
return host_ret;
}
inline bool ctx_is_unused(const vfs_semihost_ctx_t* ctx)
{
return ctx->base_path[0] == 0;
}
inline bool ctx_uses_abspath(const vfs_semihost_ctx_t* ctx)
{
return ctx->host_path[0];
}
static int vfs_semihost_open(void* ctx, const char * path, int flags, int mode)
{
int fd = -1, host_err = 0;
char *host_path;
vfs_semihost_ctx_t *semi_ctx = ctx;
ESP_LOGV(TAG, "%s: %p '%s 0x%x 0x%x'", __func__, semi_ctx, path, flags, mode);
if (ctx_uses_abspath(semi_ctx)) {
flags |= ESP_O_SEMIHOST_ABSPATH;
host_path = malloc(strlen(semi_ctx->host_path)+strlen(path)+1);
if(host_path == NULL) {
errno = ENOMEM;
return -1;
}
strcpy(host_path, semi_ctx->host_path);
strcat(host_path, path);
} else {
host_path = (char *)path;
}
fd = generic_syscall(SYS_OPEN, (int)host_path, strlen(host_path), flags, mode, &host_err);
if (ctx_uses_abspath(semi_ctx)) {
free(host_path);
}
if (fd == -1) {
errno = host_err;
}
return fd;
}
static ssize_t vfs_semihost_write(void* ctx, int fd, const void * data, size_t size)
{
int host_err = 0;
size_t ret = -1;
ESP_LOGV(TAG, "%s: %d %u bytes", __func__, fd, size);
ret = generic_syscall(SYS_WRITE, fd, (int)data, size, 0, &host_err);
if (ret == -1) {
errno = host_err;
}
return (ssize_t)ret;
}
static ssize_t vfs_semihost_read(void* ctx, int fd, void* data, size_t size)
{
int host_err = 0;
size_t ret = -1;
ESP_LOGV(TAG, "%s: %d %u bytes", __func__, fd, size);
ret = generic_syscall(SYS_READ, fd, (int)data, size, 0, &host_err);
if (ret == -1) {
errno = host_err;
}
return (ssize_t)ret;
}
static int vfs_semihost_close(void* ctx, int fd)
{
int ret = -1, host_err = 0;
ESP_LOGV(TAG, "%s: %d", __func__, fd);
ret = generic_syscall(SYS_CLOSE, fd, 0, 0, 0, &host_err);
if (ret == -1) {
errno = host_err;
}
return ret;
}
static off_t vfs_semihost_lseek(void* ctx, int fd, off_t size, int mode)
{
int ret = -1, host_err = 0;
ESP_LOGV(TAG, "%s: %d %ld %d", __func__, fd, size, mode);
ret = generic_syscall(SYS_SEEK, fd, size, mode, 0, &host_err);
if (ret == -1) {
errno = host_err;
}
return (off_t)ret;
}
esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path)
{
const esp_vfs_t vfs = {
.flags = ESP_VFS_FLAG_CONTEXT_PTR,
.write_p = &vfs_semihost_write,
.open_p = &vfs_semihost_open,
.close_p = &vfs_semihost_close,
.read_p = &vfs_semihost_read,
.lseek_p = &vfs_semihost_lseek,
};
ESP_LOGD(TAG, "Register semihosting driver '%s' -> '%s'", base_path, host_path ? host_path : "null");
if (!esp_cpu_in_ocd_debug_mode()) {
ESP_LOGE(TAG, "OpenOCD is not connected!");
return ESP_ERR_NOT_SUPPORTED;
}
int i = 0;
for (i = 0; i < CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS; i++) {
if (ctx_is_unused(&s_semhost_ctx[i])) {
break;
}
if (strcmp(base_path, s_semhost_ctx[i].base_path) == 0) {
return ESP_ERR_INVALID_STATE;
}
}
if (i == CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS) {
return ESP_ERR_NO_MEM;
}
strlcpy(s_semhost_ctx[i].base_path, base_path, sizeof(s_semhost_ctx[i].base_path) - 1);
if (host_path) {
strlcpy(s_semhost_ctx[i].host_path, host_path, sizeof(s_semhost_ctx[i].host_path) - 1);
}
ESP_LOGD(TAG, "Register semihosting driver %d %p", i, &s_semhost_ctx[i]);
return esp_vfs_register(base_path, &vfs, &s_semhost_ctx[i]);
}
esp_err_t esp_vfs_semihost_unregister(const char* base_path)
{
ESP_LOGD(TAG, "Unregister semihosting driver @ '%s'", base_path);
int i = 0;
for (i = 0; i < CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS; i++) {
if (s_semhost_ctx[i].base_path[0] != 0 && strcmp(base_path, s_semhost_ctx[i].base_path) == 0) {
break;
}
}
if (i == CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = esp_vfs_unregister(s_semhost_ctx[i].base_path);
if (ret != ESP_OK) {
return ret;
}
s_semhost_ctx[i].base_path[0] = 0;
s_semhost_ctx[i].host_path[0] = 0;
ESP_LOGD(TAG, "Unregistered semihosting driver @ '%s'", base_path);
return ESP_OK;
}

View File

@ -137,6 +137,7 @@ INPUT = \
## Virtual Filesystem
../../components/vfs/include/esp_vfs.h \
../../components/vfs/include/esp_vfs_dev.h \
../../components/vfs/include/esp_vfs_semihost.h \
## FAT Filesystem
## NOTE: for two lines below header_file.inc is not used
../../components/fatfs/src/esp_vfs_fat.h \

View File

@ -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)

View File

@ -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

View File

@ -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
```

View File

@ -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

View File

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "semihost_vfs_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -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 <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#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));
}
}

View File

@ -0,0 +1,2 @@
# need this to detect that OpenOCD is connected
CONFIG_ESP32_DEBUG_OCDAWARE=y