mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
docs: describe the firmware that exists; ship the NXP firmware EULA
README: replace the stalled REST/GUI roadmap with what the firmware does - GRBL mode over TCP for LightBurn/UGS/cncjs, optional cloud mode, the web control panel, cameras, A/B install beside the factory firmware - plus the supported hardware incl. the 8 MP camera limitation and a real roadmap. kas/README: xvclk is the board's 24 MHz oscillator; the pin/push rule covers every source repo; camera and motion sections are hardware-validated, with the OV8856 caveat spelled out; the device-tree item closes with the control_12v residue named; forgectrl is the machine-services daemon with two supervised controllers. LIGHTBURN.md: drop the pre-first-light status line. BUILD.md: state the NXP firmware licensing and where the EULA lives on the machine. The image now installs firmware-imx-lic, so the EULA text ships beside the VPU/EPDC blobs it covers; a bbappend declares that package at parse time, which is what makes it installable from an image recipe.
This commit is contained in:
@@ -70,6 +70,15 @@ kas lock kas/forgefirm-glowforge.yml
|
|||||||
See [`kas/README.md`](kas/README.md) for details, the container-build option,
|
See [`kas/README.md`](kas/README.md) for details, the container-build option,
|
||||||
and the Scarthgap migration backlog.
|
and the Scarthgap migration backlog.
|
||||||
|
|
||||||
|
## Third-party firmware licensing
|
||||||
|
|
||||||
|
The i.MX6 BSP installs NXP firmware blobs (VPU, EPDC) that are distributed
|
||||||
|
under NXP's firmware EULA. The build config accepts it
|
||||||
|
(`ACCEPT_FSL_EULA = "1"`), and the image ships the license text alongside the
|
||||||
|
blobs at `/usr/share/licenses/firmware-imx/EULA` — keep it there in any
|
||||||
|
redistributed image. The SDMA firmware comes from `linux-firmware`, which
|
||||||
|
carries its own license package.
|
||||||
|
|
||||||
## Write to an SD card
|
## Write to an SD card
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
|||||||
@@ -1,15 +1,60 @@
|
|||||||
# OpenGlow/ForgeFIRM Firmware for Glowforge
|
# OpenGlow/ForgeFIRM Firmware for Glowforge
|
||||||
This repository contains opensource firmware for Glowforge brand CNC lasers.
|
|
||||||
|
Open-source firmware for Glowforge brand CNC lasers. ForgeFIRM replaces the
|
||||||
* [Latest Release](https://github.com/ScottW514/forgefirm/releases)
|
cloud-dependent factory software on the **stock control board** — no hardware
|
||||||
* [Installation Instructions](https://github.com/ScottW514/forgefirm/blob/master/INSTALL.md)
|
modification — and gives the machine a local controller, a local web control
|
||||||
* [Build Instructions](https://github.com/ScottW514/forgefirm/blob/master/BUILD.md)
|
panel, and a standard Grbl interface.
|
||||||
* [Community Support](https://community.openglow.org)
|
|
||||||
|
* [Latest Release](https://github.com/ScottW514/forgefirm/releases)
|
||||||
# Roadmap
|
* [Installation Instructions](https://github.com/ScottW514/forgefirm/blob/master/INSTALL.md)
|
||||||
* Base image that supports all Glowforge hardware (complete)
|
* [Build Instructions](https://github.com/ScottW514/forgefirm/blob/master/BUILD.md)
|
||||||
* Support Glowforge web service - Python implementation (mostly complete)
|
* [Connecting LightBurn](https://github.com/ScottW514/forgefirm/blob/master/docs/LIGHTBURN.md)
|
||||||
* REST API w/ G-Code support (~~in progress~~) Stalled
|
* [Community Support](https://community.openglow.org)
|
||||||
* Browser-based GUI (~~pending~~) Stalled
|
|
||||||
|
## What it does
|
||||||
This project is for experimental purposes only, and is not supported or endorsed by Glowforge.
|
|
||||||
|
**Two controller modes, selected in the web panel and switchable while the
|
||||||
|
machine is idle:**
|
||||||
|
|
||||||
|
* **GRBL mode** — [grblHAL](https://github.com/grblHAL) runs on the machine and
|
||||||
|
speaks Grbl 1.1 over TCP port 23, so LightBurn, UGS, and cncjs drive the
|
||||||
|
laser directly. Motion runs on the board's own hardware step engine (SDMA +
|
||||||
|
EPIT), fed live by the planner. M3/M4 dynamic laser power, coolant-flow
|
||||||
|
verification, over-temp holds, and an operator button press to arm the laser
|
||||||
|
for each job.
|
||||||
|
* **Cloud mode** — the machine presents itself as a stock Glowforge to the
|
||||||
|
Glowforge web service, so the phone and web apps work as they always did.
|
||||||
|
Optional, and off by default; nothing about GRBL mode needs it.
|
||||||
|
|
||||||
|
**Around both modes:**
|
||||||
|
|
||||||
|
* A **web control panel** on port 8080: machine status and position, coolant
|
||||||
|
and fan telemetry, safety-switch states, camera view, machine settings,
|
||||||
|
hardware diagnostics, firmware updates, and boot-slot management.
|
||||||
|
* Both **cameras** as MJPEG streams and full-resolution snapshots — the lid
|
||||||
|
camera feeds LightBurn's camera overlay directly.
|
||||||
|
* **Camera-referenced homing**: `$H` from any sender runs the factory-style
|
||||||
|
camera homing cycle through the Glowforge service, and the machine records
|
||||||
|
where it is.
|
||||||
|
* **Installs alongside the factory firmware** in the unused A/B rootfs slot,
|
||||||
|
archiving every factory version first, so the machine can be switched back
|
||||||
|
to stock at any time without the Glowforge cloud.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
The control board is common to Glowforge Basic, Plus, and Pro. The 5 MP
|
||||||
|
(OV5648) camera modules are fully supported; the 8 MP (OV8856) modules found in
|
||||||
|
"HD" units bind but do not capture yet — see the camera note in
|
||||||
|
[kas/README.md](kas/README.md).
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
* Limit-switch homing as an alternative to camera-referenced homing.
|
||||||
|
* Camera lens calibration and bed alignment for the LightBurn overlay.
|
||||||
|
* Capture support for the 8 MP (OV8856) camera modules.
|
||||||
|
* Cloud mode: stream jobs into the motion ring during the run, lifting the
|
||||||
|
job-length cap that buffering the whole job imposes.
|
||||||
|
|
||||||
|
**A very important warning: this is experimental software. Use of this software
|
||||||
|
could seriously maim or kill you or others, and voids your warranty. It is not
|
||||||
|
affiliated with or endorsed by Glowforge. Use it at your own risk.**
|
||||||
|
|||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
# LightBurn setup & operation (ForgeFIRM)
|
# LightBurn setup & operation (ForgeFIRM)
|
||||||
|
|
||||||
Status: laser software implemented, **first light pending** (see
|
The laser fires only inside an operator-armed window:
|
||||||
BRINGUP.md for the commissioning record). The laser fires only inside
|
|
||||||
an operator-armed window:
|
|
||||||
|
|
||||||
- **Starting a job that fires: press the button.** At the first
|
- **Starting a job that fires: press the button.** At the first
|
||||||
laser-on command of a job the machine unlocks its laser latch,
|
laser-on command of a job the machine unlocks its laser latch,
|
||||||
|
|||||||
+44
-31
@@ -89,11 +89,13 @@ kas auto-loads the lockfile on subsequent runs. Commit it; refresh deliberately.
|
|||||||
The build is only reproducible when recipe pins, layer branches, and the kas
|
The build is only reproducible when recipe pins, layer branches, and the kas
|
||||||
config move in the right order. The sequence, with current status:
|
config move in the right order. The sequence, with current status:
|
||||||
|
|
||||||
1. **Source repos pushed & pinned** — **DONE.**
|
1. **Source repos pushed & pinned** — **DONE.** Every source repo
|
||||||
`kernel-module-glowforge` (`029dfb6`) and `python3-gfhardware` (`9bf31fd`)
|
(`kernel-module-glowforge`, `python3-gfhardware`, `Glowforge-Utilities`,
|
||||||
pushed to GitHub master; both recipes in meta-openglow pin those exact
|
`grblHAL-glowforge`, `forgectrl`) is on GitHub and its recipe pins an exact
|
||||||
SRCREVs (no `AUTOREV` anywhere). Whenever either repo changes: push it,
|
`SRCREV` — no `AUTOREV` anywhere. Whenever a source repo changes: push it,
|
||||||
then bump the recipe `SRCREV` in meta-openglow deliberately.
|
then bump the recipe `SRCREV` deliberately (BSP recipes in meta-openglow,
|
||||||
|
ForgeFIRM components in meta-forgefirm) and re-verify with
|
||||||
|
`bitbake -c fetch <recipe>`.
|
||||||
2. **meta-openglow pushed** — **DONE.** The Scarthgap port lives on
|
2. **meta-openglow pushed** — **DONE.** The Scarthgap port lives on
|
||||||
the **`scarthgap` branch** (Yocto layer convention; the Dunfell-era `master`
|
the **`scarthgap` branch** (Yocto layer convention; the Dunfell-era `master`
|
||||||
is untouched). Development continues on the local sibling checkout; push /
|
is untouched). Development continues on the local sibling checkout; push /
|
||||||
@@ -104,9 +106,6 @@ config move in the right order. The sequence, with current status:
|
|||||||
4. **At release time**:
|
4. **At release time**:
|
||||||
- flip `meta-openglow` in `forgefirm-glowforge.yml` from the local-sibling
|
- flip `meta-openglow` in `forgefirm-glowforge.yml` from the local-sibling
|
||||||
block to the pinned-remote block (commented FUTURE block in the file);
|
block to the pinned-remote block (commented FUTURE block in the file);
|
||||||
- drop meta-openglow's `kernel-module-glowforge.bbappend` (externalsrc to
|
|
||||||
the local sibling — its perl-native DEPENDS is already carried in the
|
|
||||||
base recipe) so a fresh clone is fully self-contained;
|
|
||||||
- refresh `kas lock`, tag all repos, and prove self-containment by building
|
- refresh `kas lock`, tag all repos, and prove self-containment by building
|
||||||
from a **fresh clone**.
|
from a **fresh clone**.
|
||||||
5. **GitHub release**: run `scripts/release.sh <version>` on the build
|
5. **GitHub release**: run `scripts/release.sh <version>` on the build
|
||||||
@@ -120,8 +119,11 @@ config move in the right order. The sequence, with current status:
|
|||||||
`v<version>` = `FORGEFIRM_RELEASE` = the rootfs `/etc/forgefirm-version`
|
`v<version>` = `FORGEFIRM_RELEASE` = the rootfs `/etc/forgefirm-version`
|
||||||
= the `.fw` meta-version; `release.sh` enforces the agreement.
|
= the `.fw` meta-version; `release.sh` enforces the agreement.
|
||||||
|
|
||||||
For gfhardware development, either bump the recipe pin per iteration or add a
|
All recipes fetch their pinned revision from GitHub, so an image build is
|
||||||
tracked externalsrc bbappend mirroring the kernel-module pattern.
|
reproducible from the repos alone. For fast iteration on a source repo, bump
|
||||||
|
its pin per iteration, or add a **local, untracked** `externalsrc` bbappend
|
||||||
|
pointing at the sibling checkout — never commit one, or released images stop
|
||||||
|
matching the pins.
|
||||||
|
|
||||||
## Scarthgap migration backlog
|
## Scarthgap migration backlog
|
||||||
|
|
||||||
@@ -145,8 +147,9 @@ Scarthgap, but the legacy (Dunfell/Gatesgarth) layers won't build clean until:
|
|||||||
`st,lis2hh12` ×3 + `national,lm75b` + `ti,wl1805` + gpio keys/leds bind to
|
`st,lis2hh12` ×3 + `national,lm75b` + `ti,wl1805` + gpio keys/leds bind to
|
||||||
mainline drivers; `reg-userspace-consumer` enabled via `glowforge.cfg`.
|
mainline drivers; `reg-userspace-consumer` enabled via `glowforge.cfg`.
|
||||||
(SPI-delay / PWM-prescaler dispositions are under Motion polish below.)
|
(SPI-delay / PWM-prescaler dispositions are under Motion polish below.)
|
||||||
- **Motion path — DONE (builds clean; runtime needs hardware).** The whole
|
- **Motion path — DONE and hardware-validated** (live-fed pulse stream,
|
||||||
chain forward-ports and compiles on 6.12:
|
real gantry motion, laser fire). The whole chain forward-ports and
|
||||||
|
compiles on 6.12:
|
||||||
- **EPIT API**: `epit_api.c` in `arch/arm/mach-imx` (`CONFIG_MXC_EPIT_API`),
|
- **EPIT API**: `epit_api.c` in `arch/arm/mach-imx` (`CONFIG_MXC_EPIT_API`),
|
||||||
in vmlinux, symbols exported; `&epit1/&epit2` in the DT.
|
in vmlinux, symbols exported; `&epit1/&epit2` in the DT.
|
||||||
- **SDMA-expose**: re-created `dma-imx-sdma.h` + `0003-imx-sdma-*.patch`
|
- **SDMA-expose**: re-created `dma-imx-sdma.h` + `0003-imx-sdma-*.patch`
|
||||||
@@ -166,16 +169,22 @@ Scarthgap, but the legacy (Dunfell/Gatesgarth) layers won't build clean until:
|
|||||||
`spi_imx_setupxfer` (write `MX51_ECSPI_PERIODREG` from `t->word_delay`,
|
`spi_imx_setupxfer` (write `MX51_ECSPI_PERIODREG` from `t->word_delay`,
|
||||||
guarded to ECSPI) and verify the wait-states on a scope. pic.c keeps the
|
guarded to ECSPI) and verify the wait-states on a scope. pic.c keeps the
|
||||||
inter-transfer delay meanwhile. `glowforge,imx-pwm-audio` (buzzer) deferred.
|
inter-transfer delay meanwhile. `glowforge,imx-pwm-audio` (buzzer) deferred.
|
||||||
- **Camera — DONE (builds clean; runtime needs hardware).** The factory
|
- **Camera — DONE and hardware-validated.** The factory
|
||||||
`ov5648_mipi.c` (NXP's removed `v4l2_int_device`/`mxc_v4l2_capture`) is
|
`ov5648_mipi.c` (NXP's removed `v4l2_int_device`/`mxc_v4l2_capture`) is
|
||||||
replaced by the mainline `ovti,ov5648` subdev + imx6 `imx-media` (IPU CSI)
|
replaced by the mainline `ovti,ov5648` subdev + imx6 `imx-media` (IPU CSI)
|
||||||
+ `imx6-mipi-csi2` receiver. The factory CAM_SEL MIPI switch is modelled
|
+ `imx6-mipi-csi2` receiver. The factory CAM_SEL MIPI switch is modelled
|
||||||
with the mainline `video-mux` (gpio-mux on `gpio7 10`): both `ov5648`s →
|
with the mainline `video-mux` (gpio-mux on `gpio7 10`): both sensors →
|
||||||
video-mux → `mipi_csi` → IPU CSI. Sensor `xvclk` (25 MHz fixed-clock) +
|
video-mux → `mipi_csi` → IPU CSI. Sensor `xvclk` is the board's 24 MHz
|
||||||
avdd/dovdd/dvdd rails in the DT. All drivers build as modules and
|
fixed oscillator (matching the factory DTB); avdd/dovdd/dvdd rails are in
|
||||||
`glowforge.dtb` compiles with the full pipeline. **HW bring-up:** confirm
|
the DT. Both cameras stream live through forgectrl (MJPEG at 15 fps with
|
||||||
the real supply rails, CSI-2 lane count/order and CAM_SEL polarity, then
|
VPU JPEG encode, full-resolution snapshots, mux arbitration).
|
||||||
validate with `media-ctl` + a v4l2 capture.
|
**HD-unit caveat:** the DT lists both `ovti,ov5648` (5 MP) and
|
||||||
|
`ovti,ov8856` (8 MP) at 0x36 so one image covers both, and the driver
|
||||||
|
matching the chip ID wins — but mainline `ov8856` expects a 19.2 MHz
|
||||||
|
xvclk and only warns at 24 MHz, and the capture path is written to
|
||||||
|
ov5648's SBGGR8 2592×1944 format set. 8 MP "HD" modules therefore bind
|
||||||
|
but do not capture; adding 24 MHz PLL modes plus a sensor-aware capture
|
||||||
|
path is the open work.
|
||||||
3. **u-boot** — **DONE.** The `glowforge` u-boot is
|
3. **u-boot** — **DONE.** The `glowforge` u-boot is
|
||||||
a standalone `u-boot_2020.01.bb` (Scarthgap's poky has no u-boot 2020.01
|
a standalone `u-boot_2020.01.bb` (Scarthgap's poky has no u-boot 2020.01
|
||||||
base recipe to extend). It reuses poky's
|
base recipe to extend). It reuses poky's
|
||||||
@@ -186,8 +195,11 @@ Scarthgap, but the legacy (Dunfell/Gatesgarth) layers won't build clean until:
|
|||||||
`fw_printenv`/`fw_setenv` from `u-boot-fw-utils` to `libubootenv`
|
`fw_printenv`/`fw_setenv` from `u-boot-fw-utils` to `libubootenv`
|
||||||
(`PREFERRED_PROVIDER_u-boot-fw-utils` in `glowforge.inc`) when the rootfs needs
|
(`PREFERRED_PROVIDER_u-boot-fw-utils` in `glowforge.inc`) when the rootfs needs
|
||||||
them.
|
them.
|
||||||
4. **Device tree** — revalidate the `glowforge` `.dts` against the linux-fslc
|
4. **Device tree — DONE.** The `glowforge` `.dts` is validated against the
|
||||||
6.12 DT bindings (paired with the kernel forward-port in #2).
|
linux-fslc 6.12 bindings and against the running board (motion, safety
|
||||||
|
readbacks, cameras, sensors all bind and work). Residue: `control_12v`
|
||||||
|
still uses the `reg-userspace-consumer` compatible, which matches no 6.12
|
||||||
|
driver — convert it to `regulator-output` or drop the node.
|
||||||
5. **Real-time strategy — decided.** The kernel runs
|
5. **Real-time strategy — decided.** The kernel runs
|
||||||
`CONFIG_PREEMPT=y` (factory behavior; `imx_v6_v7_defconfig` alone gives only
|
`CONFIG_PREEMPT=y` (factory behavior; `imx_v6_v7_defconfig` alone gives only
|
||||||
`PREEMPT_VOLUNTARY`). **PREEMPT_RT is not selectable on arm32 6.12** (no
|
`PREEMPT_VOLUNTARY`). **PREEMPT_RT is not selectable on arm32 6.12** (no
|
||||||
@@ -200,14 +212,14 @@ Scarthgap, but the legacy (Dunfell/Gatesgarth) layers won't build clean until:
|
|||||||
the underrun bench ever contradicts this arithmetic. (Bench: 5 s of
|
the underrun bench ever contradicts this arithmetic. (Bench: 5 s of
|
||||||
continuous feed at a 1 s buffer depth, zero underruns.)
|
continuous feed at a 1 s buffer depth, zero underruns.)
|
||||||
|
|
||||||
6. **gfui-client → forgectrl** — the Glowforge **cloud client is excluded**
|
6. **gfui-client → forgectrl — DONE.** The stock `gfui-client` is excluded
|
||||||
from `forgefirm-image` (`IMAGE_INSTALL:remove = "gfui-client"` in
|
from `forgefirm-image` (`IMAGE_INSTALL:remove = "gfui-client"` in
|
||||||
`meta-forgefirm/recipes-forgefirm/images/forgefirm-image.bb`) — it connected to
|
`meta-forgefirm/recipes-forgefirm/images/forgefirm-image.bb`). Its slot is
|
||||||
Glowforge's servers, the dependency ForgeFIRM exists to cut. Its slot is
|
filled by `forgectrl` (github.com/ScottW514/forgectrl — the machine-services
|
||||||
filled by `forgectrl` (github.com/ScottW514/forgectrl — the ForgeFIRM
|
daemon: web control panel, cameras, telemetry, settings, diagnostics,
|
||||||
control daemon; camera MJPEG service today, hardware status/control and
|
cooling engine, updates, and controller-mode supervision) plus the two
|
||||||
GRBL-vs-cloud mode selection planned) plus the `grblhal-glowforge`
|
controllers it supervises, `grblhal-glowforge` (Grbl over TCP:23) and
|
||||||
motion controller (both in the images with boot autostart).
|
`gfcloud` (the optional Glowforge web-service client, off unless selected).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -215,6 +227,7 @@ Scarthgap, but the legacy (Dunfell/Gatesgarth) layers won't build clean until:
|
|||||||
stack and deploys `forgefirm-image-glowforge.rootfs.wic.gz` (+ `zImage`,
|
stack and deploys `forgefirm-image-glowforge.rootfs.wic.gz` (+ `zImage`,
|
||||||
`glowforge.dtb`, `u-boot-glowforge.imx`) under `build/tmp/deploy/images/glowforge/`.
|
`glowforge.dtb`, `u-boot-glowforge.imx`) under `build/tmp/deploy/images/glowforge/`.
|
||||||
Build-time prerequisites baked into the config: `ACCEPT_FSL_EULA = "1"` (NXP
|
Build-time prerequisites baked into the config: `ACCEPT_FSL_EULA = "1"` (NXP
|
||||||
firmware-imx) and the kernel default in `glowforge.conf`. Everything compiles;
|
firmware-imx — the image also installs `firmware-imx-lic` so the EULA text
|
||||||
on-hardware bring-up (motion timing, laser/safety chain, camera pipeline) is the
|
ships beside the blobs) and the kernel default in `glowforge.conf`. The stack
|
||||||
remaining validation and needs a real board.
|
is hardware-validated end to end: motion timing, the laser and safety chain,
|
||||||
|
the camera pipeline, both controller modes, and the A/B install path.
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# NXP distributes the i.MX VPU/EPDC firmware blobs under its firmware EULA
|
||||||
|
# (accepted with ACCEPT_FSL_EULA), so an image carrying those blobs has to
|
||||||
|
# carry the license text with them.
|
||||||
|
#
|
||||||
|
# LICENSE_CREATE_PACKAGE builds the license package, but license.bbclass adds
|
||||||
|
# it to PACKAGES during do_package - too late for an image to depend on the
|
||||||
|
# name. Declaring it here makes it resolvable at parse time; the class then
|
||||||
|
# logs one "package already existed" note for this recipe, which is why FILES
|
||||||
|
# is set here as well.
|
||||||
|
LICENSE_CREATE_PACKAGE = "1"
|
||||||
|
|
||||||
|
PACKAGES:prepend = "${PN}-lic "
|
||||||
|
FILES:${PN}-lic = "${datadir}/licenses/${PN}"
|
||||||
@@ -25,6 +25,11 @@ IMAGE_INSTALL:remove = "gfui-client"
|
|||||||
# slotmigrate: boot-time reclaim of the legacy p4 layout (grows /data).
|
# slotmigrate: boot-time reclaim of the legacy p4 layout (grows /data).
|
||||||
IMAGE_INSTALL:append = " grblhal-glowforge forgectrl gfhome gfcloud v4l-utils fwup ffboot slotmigrate"
|
IMAGE_INSTALL:append = " grblhal-glowforge forgectrl gfhome gfcloud v4l-utils fwup ffboot slotmigrate"
|
||||||
|
|
||||||
|
# NXP's firmware EULA covers the i.MX VPU/EPDC blobs the BSP installs, so the
|
||||||
|
# image ships the license text with them (/usr/share/licenses/firmware-imx).
|
||||||
|
# The SDMA firmware brings its own -license package through linux-firmware.
|
||||||
|
IMAGE_INSTALL:append = " firmware-imx-lic"
|
||||||
|
|
||||||
# The release rootfs must fit a 200 MiB factory eMMC slot (409600 blocks).
|
# The release rootfs must fit a 200 MiB factory eMMC slot (409600 blocks).
|
||||||
# Sizing: content + 40 MiB working space, hard-capped at the slot size —
|
# Sizing: content + 40 MiB working space, hard-capped at the slot size —
|
||||||
# the build fails rather than emit an unflashable image. The raw ext4 is
|
# the build fails rather than emit an unflashable image. The raw ext4 is
|
||||||
|
|||||||
Reference in New Issue
Block a user