init project
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
CompileFlags:
|
||||
Remove: [-f*, -m*]
|
||||
@@ -0,0 +1,13 @@
|
||||
ARG DOCKER_TAG=latest
|
||||
FROM espressif/idf:${DOCKER_TAG}
|
||||
|
||||
ENV LC_ALL=C.UTF-8
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update -y && apt-get install udev -y
|
||||
|
||||
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
|
||||
|
||||
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
|
||||
|
||||
CMD ["/bin/bash", "-c"]
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "ESP-IDF QEMU",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"terminal.integrated.defaultProfile.linux": "bash",
|
||||
"idf.gitPath": "/usr/bin/git"
|
||||
},
|
||||
"extensions": [
|
||||
"espressif.esp-idf-extension",
|
||||
"espressif.esp-idf-web"
|
||||
]
|
||||
}
|
||||
},
|
||||
"runArgs": ["--privileged"]
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Directory metadata
|
||||
.directory
|
||||
|
||||
# Temporary files
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Build artifacts and directories
|
||||
**/build/
|
||||
build/
|
||||
*.o
|
||||
*.a
|
||||
*.out
|
||||
*.exe # For any host-side utilities compiled on Windows
|
||||
|
||||
# ESP-IDF specific build outputs
|
||||
*.bin
|
||||
*.elf
|
||||
*.map
|
||||
flasher_args.json # Generated in build directory
|
||||
sdkconfig.old
|
||||
# sdkconfig
|
||||
|
||||
# ESP-IDF dependencies
|
||||
# For older versions or manual component management
|
||||
/components/.idf/
|
||||
**/components/.idf/
|
||||
# For modern ESP-IDF component manager
|
||||
managed_components/
|
||||
# If ESP-IDF tools are installed/referenced locally to the project
|
||||
.espressif/
|
||||
|
||||
# CMake generated files
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
CTestTestfile.cmake
|
||||
|
||||
# Python environment files
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
__pycache__/
|
||||
*.egg-info/
|
||||
dist/
|
||||
|
||||
# Virtual environment folders
|
||||
venv/
|
||||
.venv/
|
||||
env/
|
||||
|
||||
# Language Servers
|
||||
.clangd/
|
||||
.ccls-cache/
|
||||
compile_commands.json
|
||||
|
||||
# Windows specific
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# User-specific configuration files
|
||||
*.user
|
||||
*.workspace # General workspace files, can be from various tools
|
||||
*.suo # Visual Studio Solution User Options
|
||||
*.sln.docstates # Visual Studio
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ESP-IDF",
|
||||
"compilerPath": "C:\\Espressif\\tools\\xtensa-esp-elf\\esp-14.2.0_20241119\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe",
|
||||
"compileCommands": "${config:idf.buildPath}/compile_commands.json",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "gdbtarget",
|
||||
"request": "attach",
|
||||
"name": "Eclipse CDT GDB Adapter"
|
||||
}
|
||||
]
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"C_Cpp.intelliSenseEngine": "default",
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32s3-builtin.cfg"
|
||||
],
|
||||
"idf.portWin": "COM10",
|
||||
"idf.currentSetup": "C:\\Users\\wuwen\\esp\\v5.5.1\\esp-idf",
|
||||
"idf.customExtraVars": {
|
||||
"IDF_TARGET": "esp32s3"
|
||||
},
|
||||
"clangd.path": "C:\\Espressif\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clangd.exe",
|
||||
"clangd.arguments": [
|
||||
"--background-index",
|
||||
"--query-driver=**",
|
||||
"--compile-commands-dir=c:\\Users\\wuwen\\Documents\\project\\lilygo_t_deck_pro_project\\code\\hello_world_01\\build"
|
||||
],
|
||||
"idf.flashType": "UART"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# 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.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(hello_world_01)
|
||||
@@ -0,0 +1,53 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | ----- |
|
||||
|
||||
# Hello World Example
|
||||
|
||||
Starts a FreeRTOS task to print "Hello World".
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## How to use example
|
||||
|
||||
Follow detailed instructions provided specifically for this example.
|
||||
|
||||
Select the instructions depending on Espressif chip installed on your development board:
|
||||
|
||||
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
||||
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||
|
||||
|
||||
## Example folder contents
|
||||
|
||||
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
||||
|
||||
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||
|
||||
Below is short explanation of remaining files in the project folder.
|
||||
|
||||
```
|
||||
├── CMakeLists.txt
|
||||
├── pytest_hello_world.py Python script used for automated testing
|
||||
├── main
|
||||
│ ├── CMakeLists.txt
|
||||
│ └── hello_world_main.c
|
||||
└── README.md This is the file you are currently reading
|
||||
```
|
||||
|
||||
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* Program upload failure
|
||||
|
||||
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||
|
||||
## Technical support and feedback
|
||||
|
||||
Please use the following feedback channels:
|
||||
|
||||
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
||||
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
||||
|
||||
We will get back to you as soon as possible.
|
||||
@@ -0,0 +1,28 @@
|
||||
# 收集当前目录下所有 .c 文件
|
||||
file(GLOB_RECURSE SRC_LIST "*.c")
|
||||
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SRC_LIST}
|
||||
PRIV_REQUIRES spi_flash esp_driver_spi esp_driver_gpio esp_timer
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES
|
||||
spiffs
|
||||
PRIV_REQUIRES
|
||||
)
|
||||
|
||||
|
||||
|
||||
set(SPIFFS_PARTITION_NAME "storage") # 如果分区名是 "storage"
|
||||
# 设置 SPIFFS 根目录路径
|
||||
set(SPIFFS_IMAGE_DIR "${CMAKE_SOURCE_DIR}/spiffs_image")
|
||||
# 确保目录存在
|
||||
if(NOT EXISTS ${SPIFFS_IMAGE_DIR})
|
||||
file(MAKE_DIRECTORY ${SPIFFS_IMAGE_DIR})
|
||||
endif()
|
||||
# 添加 SPIFFS 镜像生成
|
||||
spiffs_create_partition_image(
|
||||
${SPIFFS_PARTITION_NAME} # 分区名称
|
||||
${SPIFFS_IMAGE_DIR} # 源文件目录
|
||||
FLASH_IN_PROJECT # 生成 flash 目标
|
||||
)
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
|
||||
static const char *TAG = "SYS";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Hello world!");
|
||||
|
||||
/* Print chip information */
|
||||
esp_chip_info_t chip_info;
|
||||
uint32_t flash_size;
|
||||
esp_chip_info(&chip_info);
|
||||
ESP_LOGI(TAG, "This is %s chip with %d CPU core(s), %s%s%s%s, ",
|
||||
CONFIG_IDF_TARGET,
|
||||
chip_info.cores,
|
||||
(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
|
||||
(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
|
||||
(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");
|
||||
|
||||
unsigned major_rev = chip_info.revision / 100;
|
||||
unsigned minor_rev = chip_info.revision % 100;
|
||||
ESP_LOGI(TAG, "silicon revision v%d.%d, ", major_rev, minor_rev);
|
||||
if (esp_flash_get_size(NULL, &flash_size) != ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Get flash size failed");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%" PRIu32 "MB %s flash", flash_size / (uint32_t)(1024 * 1024),
|
||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
||||
|
||||
ESP_LOGI(TAG, "Minimum free heap size: %" PRIu32 " bytes", esp_get_minimum_free_heap_size());
|
||||
|
||||
ESP_LOGI(TAG, "sizeof(int) ==%d", sizeof(int));
|
||||
|
||||
|
||||
// 1. 初始化 SPIFFS
|
||||
const char *spiffs_base_path = "/spiffs";
|
||||
esp_err_t ret = spiffs_init(spiffs_base_path);
|
||||
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "SPIFFS 初始化失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "SPIFFS 初始化OK");
|
||||
|
||||
list_spiffs_files_safe(spiffs_base_path);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
vTaskDelay(1); // 必须让出CPU
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#include "spiffs.h"
|
||||
|
||||
static const char *TAG = "SPIFFS";
|
||||
|
||||
/**
|
||||
* @brief 初始化并挂载 SPIFFS 文件系统
|
||||
* @param base_path 挂载点路径(如 "/spiffs")
|
||||
* @return esp_err_t ESP_OK 成功,其他失败
|
||||
*/
|
||||
esp_err_t spiffs_init(const char *base_path)
|
||||
{
|
||||
ESP_LOGI(TAG, "正在初始化 SPIFFS...");
|
||||
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = base_path,
|
||||
.partition_label = NULL, // 使用第一个找到的 SPIFFS 分区
|
||||
.max_files = 10, // 最大打开文件数
|
||||
.format_if_mount_failed = true // 如果挂载失败则格式化
|
||||
};
|
||||
|
||||
// 挂载 SPIFFS 分区
|
||||
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
if (ret == ESP_FAIL)
|
||||
{
|
||||
ESP_LOGE(TAG, "挂载 SPIFFS 失败");
|
||||
}
|
||||
else if (ret == ESP_ERR_NOT_FOUND)
|
||||
{
|
||||
ESP_LOGE(TAG, "未找到 SPIFFS 分区");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "SPIFFS 初始化失败 (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "SPIFFS 挂载成功,挂载点: %s", base_path);
|
||||
|
||||
// 获取分区信息
|
||||
size_t total = 0, used = 0;
|
||||
ret = esp_spiffs_info(NULL, &total, &used);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "获取 SPIFFS 分区信息失败 (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "分区大小: 总共 %d KB, 已用 %d KB, 可用 %d KB",
|
||||
total / 1024, used / 1024, (total - used) / 1024);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 列出 SPIFFS 文件(安全版本)
|
||||
*/
|
||||
void list_spiffs_files_safe(const char *base_path)
|
||||
{
|
||||
ESP_LOGI(TAG, "Listing files in %s:", base_path);
|
||||
|
||||
DIR *dir = opendir(base_path);
|
||||
if (dir == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open directory %s: %s",
|
||||
base_path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
int count = 0;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// 跳过 "." 和 ".."
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 方法1:使用固定大小缓冲区(512字节足够)
|
||||
char full_path[512];
|
||||
int ret = snprintf(full_path, sizeof(full_path), "%s/%s", base_path, entry->d_name);
|
||||
|
||||
if (ret < 0) {
|
||||
ESP_LOGW(TAG, "Error formatting path for: %s", entry->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((size_t)ret >= sizeof(full_path)) {
|
||||
ESP_LOGW(TAG, "Path truncated for: %s", entry->d_name);
|
||||
// 继续处理,但路径可能不完整
|
||||
}
|
||||
|
||||
// 方法2:使用动态分配(如果文件名可能很长)
|
||||
// size_t path_len = strlen(base_path) + 1 + strlen(entry->d_name) + 1;
|
||||
// char *full_path = malloc(path_len);
|
||||
// if (full_path) {
|
||||
// snprintf(full_path, path_len, "%s/%s", base_path, entry->d_name);
|
||||
// // ... 使用 full_path
|
||||
// free(full_path);
|
||||
// }
|
||||
|
||||
struct stat entry_stat;
|
||||
if (stat(full_path, &entry_stat) == -1) {
|
||||
ESP_LOGW(TAG, " %s - cannot stat: %s",
|
||||
entry->d_name, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(entry_stat.st_mode)) {
|
||||
ESP_LOGI(TAG, " [DIR] %-32s", entry->d_name);
|
||||
} else {
|
||||
const char *unit = "B";
|
||||
double size = (double)entry_stat.st_size;
|
||||
|
||||
if (size >= 1024.0 * 1024.0) {
|
||||
size /= 1024.0 * 1024.0;
|
||||
unit = "MB";
|
||||
} else if (size >= 1024.0) {
|
||||
size /= 1024.0;
|
||||
unit = "KB";
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, " [FILE] %-32s %8.2f %s",
|
||||
entry->d_name, size, unit);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (count == 0) {
|
||||
ESP_LOGI(TAG, " No files found");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Total: %d items", count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef SPIFFS_H
|
||||
#define SPIFFS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include <string.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h> // 关键:包含 DIR 相关定义
|
||||
#include <errno.h> // 错误码定义
|
||||
#include <time.h> // 时间相关函数
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
esp_err_t spiffs_init(const char *base_path);
|
||||
void list_spiffs_files_safe(const char *base_path);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||
# 16M Flash
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x800000,
|
||||
storage, data, spiffs, , 0x400000,
|
||||
|
@@ -0,0 +1,55 @@
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import hashlib
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
from pytest_embedded_qemu.app import QemuApp
|
||||
from pytest_embedded_qemu.dut import QemuDut
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target'])
|
||||
def test_hello_world(dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]) -> None:
|
||||
dut.expect('Hello world!')
|
||||
log_minimum_free_heap_size()
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_hello_world_linux(dut: IdfDut) -> None:
|
||||
dut.expect('Hello world!')
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.macos_shell
|
||||
@idf_parametrize('target', ['linux'], indirect=['target'])
|
||||
def test_hello_world_macos(dut: IdfDut) -> None:
|
||||
dut.expect('Hello world!')
|
||||
|
||||
|
||||
def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None:
|
||||
sha256 = hashlib.sha256()
|
||||
with open(app.elf_file, 'rb') as f:
|
||||
sha256.update(f.read())
|
||||
sha256_expected = sha256.hexdigest()
|
||||
|
||||
logging.info(f'ELF file SHA256: {sha256_expected}')
|
||||
logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}')
|
||||
|
||||
# the app reports only the first several hex characters of the SHA256, check that they match
|
||||
if not sha256_expected.startswith(sha256_reported):
|
||||
raise ValueError('ELF file SHA256 mismatch')
|
||||
|
||||
|
||||
@pytest.mark.host_test
|
||||
@pytest.mark.qemu
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
|
||||
def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None:
|
||||
sha256_reported = dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8')
|
||||
verify_elf_sha256_embedding(app, sha256_reported)
|
||||
|
||||
dut.expect('Hello world!')
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user