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:
commit
3a779380a7
13 changed files with 593 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
46
components/vfs/include/esp_vfs_semihost.h
Normal file
46
components/vfs/include/esp_vfs_semihost.h
Normal 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
|
216
components/vfs/vfs_semihost.c
Normal file
216
components/vfs/vfs_semihost.c
Normal 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;
|
||||
}
|
|
@ -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 \
|
||||
|
|
6
examples/storage/semihost_vfs/CMakeLists.txt
Normal file
6
examples/storage/semihost_vfs/CMakeLists.txt
Normal 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)
|
9
examples/storage/semihost_vfs/Makefile
Normal file
9
examples/storage/semihost_vfs/Makefile
Normal 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
|
||||
|
91
examples/storage/semihost_vfs/README.md
Normal file
91
examples/storage/semihost_vfs/README.md
Normal 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
|
||||
```
|
||||
|
104
examples/storage/semihost_vfs/data/host_file.txt
Normal file
104
examples/storage/semihost_vfs/data/host_file.txt
Normal 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
|
4
examples/storage/semihost_vfs/main/CMakeLists.txt
Normal file
4
examples/storage/semihost_vfs/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
set(COMPONENT_SRCS "semihost_vfs_example_main.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
4
examples/storage/semihost_vfs/main/component.mk
Normal file
4
examples/storage/semihost_vfs/main/component.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
|
@ -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));
|
||||
}
|
||||
}
|
2
examples/storage/semihost_vfs/sdkconfig.defaults
Normal file
2
examples/storage/semihost_vfs/sdkconfig.defaults
Normal file
|
@ -0,0 +1,2 @@
|
|||
# need this to detect that OpenOCD is connected
|
||||
CONFIG_ESP32_DEBUG_OCDAWARE=y
|
Loading…
Reference in a new issue