Compare commits
52 Commits
1a44154287
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| dce11538d1 | |||
| 21f8e0e38a | |||
| 0ad2c63123 | |||
| 6780936d2d | |||
| 82639a7a86 | |||
| bff8bc1910 | |||
| c9bcb29f50 | |||
| dc97677e72 | |||
| 4535c4508f | |||
| 726ef77194 | |||
| 13c35400a1 | |||
| f71b6ab629 | |||
| 9b559eb7e6 | |||
| d3735d17ee | |||
| db7d83304f | |||
| 113542f7fb | |||
| 72a2083d76 | |||
| 3f6bbc0752 | |||
| d1fc24dae8 | |||
| ef104bce41 | |||
| 0015c7e8ac | |||
| 6dde73f39e | |||
| 97e8c3d965 | |||
| 586afc2f56 | |||
| f943887b39 | |||
| 335ea03b05 | |||
| b0523ada6c | |||
| 9a2307a8ee | |||
| e71fb13bfc | |||
| 5bcd3987a2 | |||
| 15b7cb1f4c | |||
| 4b124a9998 | |||
| 89279e27d5 | |||
| 4ae286d21a | |||
| 880a9af105 | |||
| 7fac0e50bb | |||
| 2c32f19262 | |||
| 4effcf513b | |||
| 6b04eb5d89 | |||
| ed93c32131 | |||
| bae5ecebf1 | |||
| ef16df416b | |||
| f81cd8e381 | |||
| 04362c6e0c | |||
| 8457cdd5a6 | |||
| d1f78968a4 | |||
| b2c245d6ab | |||
| 50618d4607 | |||
|
|
4d43ddf1e5 | ||
|
|
4a4147686e | ||
|
|
fdad061616 | ||
|
|
3d3489f1e6 |
32
.github/workflows/build.yml
vendored
Normal file
32
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: devkitpro/devkitarm:latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install dependencies
|
||||||
|
run: apt-get update && apt-get install -y nodejs
|
||||||
|
|
||||||
|
- name: Checkout latest code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
clean: true
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
export DEVKITPRO=/opt/devkitpro
|
||||||
|
export DEVKITARM=/opt/devkitpro/devkitARM
|
||||||
|
make -j4
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: OmniNX-Installer.bin
|
||||||
|
path: output/OmniNX-Installer.bin
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -20,3 +20,6 @@ Thumbs.db
|
|||||||
# Version file is tracked, ignore local edits
|
# Version file is tracked, ignore local edits
|
||||||
# VERSION
|
# VERSION
|
||||||
|
|
||||||
|
# Vendored TegraExplorer tree
|
||||||
|
source/TegraExplorer/
|
||||||
|
|
||||||
|
|||||||
17
.vscode/settings.json
vendored
17
.vscode/settings.json
vendored
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"claudeCode.disableLoginPrompt": false,
|
|
||||||
"claudeCode.environmentVariables": [
|
|
||||||
{
|
|
||||||
"name": "ANTHROPIC_BASE_URL",
|
|
||||||
"value": "https://api.z.ai/api/anthropic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ANTHROPIC_AUTH_TOKEN",
|
|
||||||
"value": "caceb12fd1a740c68631842764f1b38a.kBX5z6hfW95z8QHj"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "CLAUDE_CODE_SKIP_AUTH_LOGIN",
|
|
||||||
"value": "true"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
90
DEBUG_INI.md
Normal file
90
DEBUG_INI.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# Debug configuration (`debug.ini`)
|
||||||
|
|
||||||
|
Optional file to **skip parts of the install** for testing (e.g. run only deletion and inspect the SD card). If the file is **missing**, the installer ignores debug entirely and runs the full flow.
|
||||||
|
|
||||||
|
## Location
|
||||||
|
|
||||||
|
```
|
||||||
|
sd:/config/omninx/debug.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the folder `sd:/config/omninx/` on the SD card if it does not exist. Same parent directory as `manifest.ini` and `ram_config.ini`.
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
- Section name must be exactly **`[Debug]`** (case-sensitive in the parser).
|
||||||
|
- One key per line: `name=value`.
|
||||||
|
- **Enabling a skip:** set the value so it **starts** with one of: `1`, `t`, `T`, `y`, `Y`
|
||||||
|
Examples: `1`, `true`, `yes`, `True` — all enable that skip.
|
||||||
|
- **Disabling:** `0`, `false`, `no`, or omit the key.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
### Clean install mode (`INSTALL_MODE_CLEAN`)
|
||||||
|
|
||||||
|
| Key | What is skipped |
|
||||||
|
|-----|-----------------|
|
||||||
|
| `skip_clean_backup` | Step 1 — backup of `sd:/switch/DBI/dbi.config`, `sd:/switch/prod.keys` to `sd:/temp_backup` |
|
||||||
|
| `skip_clean_wipe` | Step 2 — all cleanup from `deletion_lists_clean.h` (deletion / wipe) |
|
||||||
|
| `skip_clean_restore` | Step 3 — restore from `sd:/temp_backup` and post-restore paths (e.g. delete `sd:/switch/tinfoil/db`) |
|
||||||
|
| `skip_clean_install` | Step 4 — copy files from the OmniNX staging folder to the SD root |
|
||||||
|
| `skip_clean_staging_cleanup` | After install: do not remove the staging directory or other variant staging folders |
|
||||||
|
|
||||||
|
### Update mode (`INSTALL_MODE_UPDATE`)
|
||||||
|
|
||||||
|
| Key | What is skipped |
|
||||||
|
|-----|-----------------|
|
||||||
|
| `skip_update_cleanup` | Step 1 — selective deletion from `deletion_lists_update.h` |
|
||||||
|
| `skip_update_install` | Step 2 — copy from staging to SD |
|
||||||
|
| `skip_update_staging_cleanup` | End: do not remove staging / other variant folders |
|
||||||
|
| `skip_update_horizon_oc` | **OC variant only:** HorizonOC config backup before update, restore and cleanup after (entire HorizonOC update side path) |
|
||||||
|
|
||||||
|
### Both modes
|
||||||
|
|
||||||
|
| Key | What is skipped |
|
||||||
|
|-----|-----------------|
|
||||||
|
| `skip_hekate_8gb_post_copy` | After a successful copy: the optional `hekate_8GB` / RAM menu and related file moves (see `install_hekate_8gb_post_copy` in `install.c`) |
|
||||||
|
|
||||||
|
## Behaviour
|
||||||
|
|
||||||
|
- On startup, if `debug.ini` exists and parses successfully, the payload prints a **DEBUG-MODUS** banner listing which skips are active.
|
||||||
|
- If the file is absent, unreadable, or has no `[Debug]` section, **no** skips apply — behaviour matches a release install.
|
||||||
|
- Skipping steps can leave the SD in an inconsistent state; this is **for developers/testers only**.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Wipe only (test deletion, no backup/restore/copy)
|
||||||
|
|
||||||
|
Inspect leftovers after the clean-install wipe, without backing up, restoring, installing, or cleaning staging:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Debug]
|
||||||
|
skip_clean_backup=1
|
||||||
|
skip_clean_restore=1
|
||||||
|
skip_clean_install=1
|
||||||
|
skip_clean_staging_cleanup=1
|
||||||
|
skip_hekate_8gb_post_copy=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Do **not** set `skip_clean_wipe` (leave unset or `0`).
|
||||||
|
|
||||||
|
### Update: deletion only
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Debug]
|
||||||
|
skip_update_install=1
|
||||||
|
skip_update_staging_cleanup=1
|
||||||
|
skip_hekate_8gb_post_copy=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### OC update without touching HorizonOC backup/restore
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Debug]
|
||||||
|
skip_update_horizon_oc=1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
- Parsed in `install.c`: `install_debug_load()`, `perform_installation()`.
|
||||||
|
- Uses the same INI parser as `ram_config.ini` (`ini_parse` from BDK).
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
This document provides a detailed, step-by-step breakdown of everything that is checked and done during the OmniNX installation/update process.
|
This document provides a detailed, step-by-step breakdown of everything that is checked and done during the OmniNX installation/update process.
|
||||||
|
|
||||||
|
For **optional debug step skips** (`sd:/config/omninx/debug.ini`), see **[DEBUG_INI.md](DEBUG_INI.md)**.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The OmniNX Installer Payload operates in two modes:
|
The OmniNX Installer Payload operates in two modes:
|
||||||
@@ -272,7 +274,7 @@ Creates/overwrites `sd:/config/omninx/manifest.ini`:
|
|||||||
**Content Structure**:
|
**Content Structure**:
|
||||||
```ini
|
```ini
|
||||||
[OmniNX]
|
[OmniNX]
|
||||||
current_pack={variant} # "standard", "light", or "oc"
|
current_pack={variant} # "Standard", "Light", or "OC"
|
||||||
version={VERSION} # e.g., "1.0.0"
|
version={VERSION} # e.g., "1.0.0"
|
||||||
update_channel={0|1|2} # light=0, oc=1, standard=2
|
update_channel={0|1|2} # light=0, oc=1, standard=2
|
||||||
channel_pack={variant} # Same as current_pack
|
channel_pack={variant} # Same as current_pack
|
||||||
@@ -305,17 +307,12 @@ channel_pack={variant} # Same as current_pack
|
|||||||
#### 32. Create Backup Directory
|
#### 32. Create Backup Directory
|
||||||
- Creates `sd:/temp_backup/` directory
|
- Creates `sd:/temp_backup/` directory
|
||||||
|
|
||||||
#### 33. Backup DBI
|
#### 33. Backup DBI settings
|
||||||
- **Source**: `sd:/switch/DBI/`
|
- **Source**: `sd:/switch/DBI/dbi.config` (file only, not the whole `DBI` tree)
|
||||||
- **Destination**: `sd:/temp_backup/DBI/`
|
- **Destination**: `sd:/temp_backup/dbi.config`
|
||||||
- Only if source exists
|
- Only if the source file exists
|
||||||
|
|
||||||
#### 34. Backup Tinfoil
|
#### 34. Backup prod.keys
|
||||||
- **Source**: `sd:/switch/tinfoil/`
|
|
||||||
- **Destination**: `sd:/temp_backup/tinfoil/`
|
|
||||||
- Only if source exists
|
|
||||||
|
|
||||||
#### 35. Backup prod.keys
|
|
||||||
- **Source**: `sd:/switch/prod.keys`
|
- **Source**: `sd:/switch/prod.keys`
|
||||||
- **Destination**: `sd:/temp_backup/prod.keys`
|
- **Destination**: `sd:/temp_backup/prod.keys`
|
||||||
- Only if source exists
|
- Only if source exists
|
||||||
@@ -325,22 +322,22 @@ channel_pack={variant} # Same as current_pack
|
|||||||
### Step 2: Wipe Directories
|
### Step 2: Wipe Directories
|
||||||
**Location**: `install.c:543-602`
|
**Location**: `install.c:543-602`
|
||||||
|
|
||||||
#### 36. Delete Entire Directories
|
#### 35. Delete Entire Directories
|
||||||
Recursively deletes (if they exist):
|
Recursively deletes (if they exist):
|
||||||
- `sd:/atmosphere/` (entire directory tree)
|
- `sd:/atmosphere/` (entire directory tree)
|
||||||
- `sd:/bootloader/` (entire directory tree)
|
- `sd:/bootloader/` (entire directory tree)
|
||||||
- `sd:/config/` (entire directory tree)
|
- `sd:/config/` (entire directory tree)
|
||||||
- `sd:/switch/` (entire directory tree)
|
- `sd:/switch/` (entire directory tree)
|
||||||
|
|
||||||
#### 37. Delete Root Files
|
#### 36. Delete Root Files
|
||||||
- Uses same deletion list as update mode (Step 19)
|
- Uses same deletion list as update mode (Step 19)
|
||||||
- Deletes `boot.dat`, `boot.ini`, `exosphere.ini`, etc.
|
- Deletes `boot.dat`, `boot.ini`, `exosphere.ini`, etc.
|
||||||
|
|
||||||
#### 38. Delete Miscellaneous Items
|
#### 37. Delete Miscellaneous Items
|
||||||
- Uses same deletion lists as update mode (Steps 20-21)
|
- Uses same deletion lists as update mode (Steps 20-21)
|
||||||
- Deletes `argon/`, `games/`, `SaltySD/`, etc.
|
- Deletes `argon/`, `games/`, `SaltySD/`, etc.
|
||||||
|
|
||||||
#### 39. Recreate Switch Directory
|
#### 38. Recreate Switch Directory
|
||||||
- Creates empty `sd:/switch/` directory for restoration
|
- Creates empty `sd:/switch/` directory for restoration
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -348,27 +345,17 @@ Recursively deletes (if they exist):
|
|||||||
### Step 3: Restore User Data
|
### Step 3: Restore User Data
|
||||||
**Location**: `backup.c:55-95`
|
**Location**: `backup.c:55-95`
|
||||||
|
|
||||||
#### 40. Restore DBI
|
#### 39. Restore DBI settings
|
||||||
- **Source**: `sd:/temp_backup/DBI/`
|
- **Source**: `sd:/temp_backup/dbi.config`
|
||||||
- **Destination**: `sd:/switch/DBI/`
|
- **Destination**: `sd:/switch/DBI/dbi.config` (creates `sd:/switch/DBI/` if needed)
|
||||||
- **Cleanup**: After restoration, deletes old DBI NRO files:
|
- No longer copies the full `DBI` folder; old `.nro` cleanup is unnecessary
|
||||||
- `sd:/switch/DBI/DBI_810_EN.nro`
|
|
||||||
- `sd:/switch/DBI/DBI_810_DE.nro`
|
|
||||||
- `sd:/switch/DBI/DBI_845_EN.nro`
|
|
||||||
- `sd:/switch/DBI/DBI_845_DE.nro`
|
|
||||||
- `sd:/switch/DBI/DBI.nro`
|
|
||||||
|
|
||||||
#### 41. Restore Tinfoil
|
#### 40. Restore prod.keys
|
||||||
- **Source**: `sd:/temp_backup/tinfoil/`
|
|
||||||
- **Destination**: `sd:/switch/tinfoil/`
|
|
||||||
- **Cleanup**: After restoration, deletes `sd:/switch/tinfoil/tinfoil.nro`
|
|
||||||
|
|
||||||
#### 42. Restore prod.keys
|
|
||||||
- **Source**: `sd:/temp_backup/prod.keys`
|
- **Source**: `sd:/temp_backup/prod.keys`
|
||||||
- **Destination**: `sd:/switch/prod.keys`
|
- **Destination**: `sd:/switch/prod.keys`
|
||||||
|
|
||||||
#### 43. Cleanup Backup Directory
|
#### 41. Cleanup Backup Directory
|
||||||
**Location**: `backup.c:98-103`
|
**Location**: `backup.c` (`cleanup_backup`)
|
||||||
- Deletes `sd:/temp_backup/` directory after restoration
|
- Deletes `sd:/temp_backup/` directory after restoration
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
24
Makefile
24
Makefile
@@ -31,6 +31,9 @@ OBJS += $(patsubst $(BDKDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
|
|||||||
$(patsubst $(BDKDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \
|
$(patsubst $(BDKDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \
|
||||||
$(call rwildcard, $(BDKDIR), *.S *.c)))
|
$(call rwildcard, $(BDKDIR), *.S *.c)))
|
||||||
|
|
||||||
|
# Optional vendored tree under source/TegraExplorer/ is not part of this payload build.
|
||||||
|
OBJS := $(filter-out $(BUILDDIR)/$(TARGET)/TegraExplorer/%,$(OBJS))
|
||||||
|
|
||||||
GFX_INC := '"../$(SOURCEDIR)/gfx.h"'
|
GFX_INC := '"../$(SOURCEDIR)/gfx.h"'
|
||||||
FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
|
FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
|
||||||
|
|
||||||
@@ -46,7 +49,11 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defs
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
.PHONY: all clean release
|
RAMTEST_BIN := $(OUTPUTDIR)/RAM-Test.bin
|
||||||
|
OBJS_RAMTEST := $(filter-out $(BUILDDIR)/$(TARGET)/main.o,$(OBJS)) \
|
||||||
|
$(BUILDDIR)/$(TARGET)/ram_test_main.o
|
||||||
|
|
||||||
|
.PHONY: all clean release ram-test
|
||||||
|
|
||||||
all: $(OUTPUTDIR)/$(OUTPUT_NAME)
|
all: $(OUTPUTDIR)/$(OUTPUT_NAME)
|
||||||
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
|
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
|
||||||
@@ -56,6 +63,7 @@ all: $(OUTPUTDIR)/$(OUTPUT_NAME)
|
|||||||
clean:
|
clean:
|
||||||
@rm -rf $(BUILDDIR)
|
@rm -rf $(BUILDDIR)
|
||||||
@rm -rf $(OUTPUTDIR)
|
@rm -rf $(OUTPUTDIR)
|
||||||
|
@rm -f $(RAMTEST_BIN)
|
||||||
@rm -rf release
|
@rm -rf release
|
||||||
@rm -f $(TARGET)-*.zip
|
@rm -f $(TARGET)-*.zip
|
||||||
|
|
||||||
@@ -67,6 +75,20 @@ $(OUTPUTDIR)/$(OUTPUT_NAME): $(BUILDDIR)/$(TARGET)/$(TARGET).elf
|
|||||||
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/ram_test_main.o: tools/ram_test_main.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/$(TARGET)/ram_test.elf: $(OBJS_RAMTEST)
|
||||||
|
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
|
||||||
|
|
||||||
|
$(RAMTEST_BIN): $(BUILDDIR)/$(TARGET)/ram_test.elf
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(OBJCOPY) -S -O binary $< $@
|
||||||
|
@echo "RAM-Test payload: $(RAMTEST_BIN) ($$(wc -c < $@) bytes)"
|
||||||
|
|
||||||
|
ram-test: $(RAMTEST_BIN)
|
||||||
|
|
||||||
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
|
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
|
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -1,5 +1,7 @@
|
|||||||
# OmniNX Installer Payload
|
# OmniNX Installer Payload
|
||||||
|
|
||||||
|
> **To properly use this payload, download the latest OmniNX Release:** [https://git.niklascfw.de/OmniNX/OmniNX/releases](https://git.niklascfw.de/OmniNX/OmniNX/releases)
|
||||||
|
|
||||||
A minimal payload for installing OmniNX CFW Pack files on Nintendo Switch outside of Horizon OS.
|
A minimal payload for installing OmniNX CFW Pack files on Nintendo Switch outside of Horizon OS.
|
||||||
|
|
||||||
Based on [TegraExplorer](https://github.com/shchmue/TegraExplorer) and [hekate](https://github.com/CTCaer/hekate) by CTCaer, naehrwert, and shchmue.
|
Based on [TegraExplorer](https://github.com/shchmue/TegraExplorer) and [hekate](https://github.com/CTCaer/hekate) by CTCaer, naehrwert, and shchmue.
|
||||||
@@ -10,7 +12,7 @@ Based on [HATS-Installer-Payload](https://github.com/sthetix/HATS-Installer-Payl
|
|||||||
- **Automatic Variant Detection**: Detects which OmniNX pack variant is present (Standard/Light/OC)
|
- **Automatic Variant Detection**: Detects which OmniNX pack variant is present (Standard/Light/OC)
|
||||||
- **Smart Installation Modes**:
|
- **Smart Installation Modes**:
|
||||||
- **Update Mode**: Selective deletion when OmniNX is already installed
|
- **Update Mode**: Selective deletion when OmniNX is already installed
|
||||||
- **Clean Install**: Full wipe with backup/restore of user data (DBI, Tinfoil, prod.keys)
|
- **Clean Install**: Full wipe with backup/restore of user data (DBI `dbi.config`, prod.keys)
|
||||||
- **Version Detection**: Detects installed OmniNX version via marker files (`1.0.0s`, `1.0.0l`, `1.0.0oc`)
|
- **Version Detection**: Detects installed OmniNX version via marker files (`1.0.0s`, `1.0.0l`, `1.0.0oc`)
|
||||||
- **Progress Display**: Visual status messages during installation
|
- **Progress Display**: Visual status messages during installation
|
||||||
- **Error Handling**: Detailed error reporting on screen
|
- **Error Handling**: Detailed error reporting on screen
|
||||||
@@ -20,6 +22,7 @@ Based on [HATS-Installer-Payload](https://github.com/sthetix/HATS-Installer-Payl
|
|||||||
|
|
||||||
For detailed information about the installation process, see:
|
For detailed information about the installation process, see:
|
||||||
- **[INSTALLATION_PROCESS.md](INSTALLATION_PROCESS.md)** - Complete step-by-step breakdown of everything checked and done during installation/update
|
- **[INSTALLATION_PROCESS.md](INSTALLATION_PROCESS.md)** - Complete step-by-step breakdown of everything checked and done during installation/update
|
||||||
|
- **[DEBUG_INI.md](DEBUG_INI.md)** - Optional `sd:/config/omninx/debug.ini` parameters to skip install steps (for testing)
|
||||||
|
|
||||||
## Installation Modes
|
## Installation Modes
|
||||||
|
|
||||||
@@ -33,8 +36,7 @@ For detailed information about the installation process, see:
|
|||||||
- Detected when no version marker files are found
|
- Detected when no version marker files are found
|
||||||
- Performs full wipe of `/atmosphere`, `/bootloader`, `/config`, and `/switch`
|
- Performs full wipe of `/atmosphere`, `/bootloader`, `/config`, and `/switch`
|
||||||
- **Backs up and restores**:
|
- **Backs up and restores**:
|
||||||
- `sd:/switch/DBI` → preserved
|
- `sd:/switch/DBI/dbi.config` → preserved (not the whole `DBI` folder)
|
||||||
- `sd:/switch/tinfoil` → preserved
|
|
||||||
- `sd:/switch/prod.keys` → preserved
|
- `sd:/switch/prod.keys` → preserved
|
||||||
- Fresh installation of all CFW components
|
- Fresh installation of all CFW components
|
||||||
|
|
||||||
@@ -52,7 +54,11 @@ make clean
|
|||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
The built payload will be output to `output/omninx-installer.bin`.
|
The built payload will be output to `output/OmniNX-Installer.bin`.
|
||||||
|
|
||||||
|
### CI / GitHub Actions
|
||||||
|
|
||||||
|
Every push triggers a build. The `.bin` file is produced and attached as a workflow artifact (Actions tab → select run → Artifacts).
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -111,11 +117,11 @@ Use hekate or another bootloader to launch the payload:
|
|||||||
|
|
||||||
The payload supports three OmniNX variants:
|
The payload supports three OmniNX variants:
|
||||||
|
|
||||||
- **Standard** (`1.0.0s`): Full CFW pack
|
- **Standard** – `sd:/OmniNX Standard/`
|
||||||
- **Light** (`1.0.0l`): Lightweight CFW pack
|
- **Light** – `sd:/OmniNX Light/`
|
||||||
- **OC** (`1.0.0oc`): Overclock-enabled CFW pack (includes SaltySD)
|
- **OC** – `sd:/OmniNX OC/`
|
||||||
|
|
||||||
The payload automatically detects which variant is present on the SD card and installs accordingly.
|
The payload detects the pack variant from the staging directory presence and detects the current installation (variant + version) from `sd:/config/omninx/manifest.ini` (`current_pack` and `version` keys).
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ void bq24193_enable_charger()
|
|||||||
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg);
|
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool bq24193_charger_connected()
|
||||||
|
{
|
||||||
|
u8 status = bq24193_get_reg(BQ24193_Status);
|
||||||
|
return (status & BQ24193_STATUS_PG_MASK) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void bq24193_fake_battery_removal()
|
void bq24193_fake_battery_removal()
|
||||||
{
|
{
|
||||||
// Disable watchdog to keep BATFET disabled.
|
// Disable watchdog to keep BATFET disabled.
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#ifndef __BQ24193_H_
|
#ifndef __BQ24193_H_
|
||||||
#define __BQ24193_H_
|
#define __BQ24193_H_
|
||||||
|
|
||||||
|
#include <utils/types.h>
|
||||||
|
|
||||||
#define BQ24193_I2C_ADDR 0x6B
|
#define BQ24193_I2C_ADDR 0x6B
|
||||||
|
|
||||||
// REG 0 masks.
|
// REG 0 masks.
|
||||||
@@ -117,5 +119,6 @@ enum BQ24193_reg_prop {
|
|||||||
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
|
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
|
||||||
void bq24193_enable_charger();
|
void bq24193_enable_charger();
|
||||||
void bq24193_fake_battery_removal();
|
void bq24193_fake_battery_removal();
|
||||||
|
bool bq24193_charger_connected();
|
||||||
|
|
||||||
#endif /* __BQ24193_H_ */
|
#endif /* __BQ24193_H_ */
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# HATS Tools Universal Config
|
|
||||||
# Location: sd:/config/hats-tools/config.ini
|
|
||||||
# Shared between HATS Tools GUI and hats-installer payload
|
|
||||||
|
|
||||||
[hats]
|
|
||||||
install_mode=default ; options: replace, default, clean
|
|
||||||
|
|
||||||
# Mode descriptions:
|
|
||||||
# replace - Only replace files, no deletion (old files may remain)
|
|
||||||
# default - Delete /atmosphere only, keep /bootloader and /switch
|
|
||||||
# clean - Delete /atmosphere, /bootloader, and /switch (fresh install)
|
|
||||||
#
|
|
||||||
# All modes will remove HATS-*.txt version files from SD root
|
|
||||||
@@ -24,17 +24,9 @@ int backup_user_data(void) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup DBI if it exists
|
// Backup DBI settings file only (not .nro installers)
|
||||||
if (path_exists("sd:/switch/DBI")) {
|
if (path_exists(DBI_CONFIG_PATH)) {
|
||||||
res = folder_copy("sd:/switch/DBI", TEMP_BACKUP_PATH);
|
res = file_copy(DBI_CONFIG_PATH, TEMP_BACKUP_DBI_CONFIG);
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backup Tinfoil if it exists
|
|
||||||
if (path_exists("sd:/switch/tinfoil")) {
|
|
||||||
res = folder_copy("sd:/switch/tinfoil", TEMP_BACKUP_PATH);
|
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -61,25 +53,15 @@ int restore_user_data(void) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore DBI if backup exists
|
// Restore DBI settings if backed up
|
||||||
if (path_exists("sd:/temp_backup/DBI")) {
|
if (path_exists(TEMP_BACKUP_DBI_CONFIG)) {
|
||||||
res = folder_copy("sd:/temp_backup/DBI", "sd:/switch");
|
res = f_mkdir("sd:/switch/DBI");
|
||||||
if (res == FR_OK) {
|
if (res != FR_OK && res != FR_EXIST) {
|
||||||
// Delete old DBI .nro files
|
return res;
|
||||||
f_unlink("sd:/switch/DBI/DBI_810_EN.nro");
|
|
||||||
f_unlink("sd:/switch/DBI/DBI_810_DE.nro");
|
|
||||||
f_unlink("sd:/switch/DBI/DBI_845_EN.nro");
|
|
||||||
f_unlink("sd:/switch/DBI/DBI_845_DE.nro");
|
|
||||||
f_unlink("sd:/switch/DBI/DBI.nro");
|
|
||||||
}
|
}
|
||||||
}
|
res = file_copy(TEMP_BACKUP_DBI_CONFIG, DBI_CONFIG_PATH);
|
||||||
|
if (res != FR_OK) {
|
||||||
// Restore Tinfoil if backup exists
|
return res;
|
||||||
if (path_exists("sd:/temp_backup/tinfoil")) {
|
|
||||||
res = folder_copy("sd:/temp_backup/tinfoil", "sd:/switch");
|
|
||||||
if (res == FR_OK) {
|
|
||||||
// Delete old tinfoil.nro
|
|
||||||
f_unlink("sd:/switch/tinfoil/tinfoil.nro");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,3 +83,34 @@ int cleanup_backup(void) {
|
|||||||
}
|
}
|
||||||
return FR_OK;
|
return FR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int backup_horizon_oc_config_for_oc_update(void) {
|
||||||
|
if (!path_exists(HORIZON_OC_CONFIG_PATH))
|
||||||
|
return FR_OK;
|
||||||
|
|
||||||
|
int res = f_mkdir(HORIZON_OC_UPDATE_BACKUP_DIR);
|
||||||
|
if (res != FR_OK && res != FR_EXIST)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return file_copy(HORIZON_OC_CONFIG_PATH, HORIZON_OC_UPDATE_BACKUP_INI);
|
||||||
|
}
|
||||||
|
|
||||||
|
int restore_horizon_oc_config_after_oc_update(void) {
|
||||||
|
if (!path_exists(HORIZON_OC_UPDATE_BACKUP_INI))
|
||||||
|
return FR_OK;
|
||||||
|
|
||||||
|
int res = f_mkdir("sd:/config");
|
||||||
|
if (res != FR_OK && res != FR_EXIST)
|
||||||
|
return res;
|
||||||
|
res = f_mkdir("sd:/config/horizon-oc");
|
||||||
|
if (res != FR_OK && res != FR_EXIST)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return file_copy(HORIZON_OC_UPDATE_BACKUP_INI, HORIZON_OC_CONFIG_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cleanup_horizon_oc_update_backup(void) {
|
||||||
|
if (!path_exists(HORIZON_OC_UPDATE_BACKUP_DIR))
|
||||||
|
return FR_OK;
|
||||||
|
return folder_delete(HORIZON_OC_UPDATE_BACKUP_DIR);
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,8 +7,17 @@
|
|||||||
#include <utils/types.h>
|
#include <utils/types.h>
|
||||||
|
|
||||||
#define TEMP_BACKUP_PATH "sd:/temp_backup"
|
#define TEMP_BACKUP_PATH "sd:/temp_backup"
|
||||||
|
/** DBI settings; preserved across clean install (not whole DBI folder). */
|
||||||
|
#define DBI_CONFIG_PATH "sd:/switch/DBI/dbi.config"
|
||||||
|
#define TEMP_BACKUP_DBI_CONFIG TEMP_BACKUP_PATH "/dbi.config"
|
||||||
|
|
||||||
// Backup user data (DBI, Tinfoil, prod.keys) before clean install
|
/** Live HorizonOC settings (Overclock tool). */
|
||||||
|
#define HORIZON_OC_CONFIG_PATH "sd:/config/horizon-oc/config.ini"
|
||||||
|
/** Scratch dir during OC-variant update only; removed after successful restore. */
|
||||||
|
#define HORIZON_OC_UPDATE_BACKUP_DIR "sd:/.omninx_oc_update"
|
||||||
|
#define HORIZON_OC_UPDATE_BACKUP_INI HORIZON_OC_UPDATE_BACKUP_DIR "/config.ini"
|
||||||
|
|
||||||
|
// Backup user data (DBI dbi.config, prod.keys) before clean install
|
||||||
int backup_user_data(void);
|
int backup_user_data(void);
|
||||||
|
|
||||||
// Restore user data after clean install
|
// Restore user data after clean install
|
||||||
@@ -16,3 +25,10 @@ int restore_user_data(void);
|
|||||||
|
|
||||||
// Clean up temporary backup directory
|
// Clean up temporary backup directory
|
||||||
int cleanup_backup(void);
|
int cleanup_backup(void);
|
||||||
|
|
||||||
|
// HorizonOC: backup config.ini before OC pack update (update mode only); no-op if missing
|
||||||
|
int backup_horizon_oc_config_for_oc_update(void);
|
||||||
|
// Restore after file copy; no-op if no backup from this run
|
||||||
|
int restore_horizon_oc_config_after_oc_update(void);
|
||||||
|
// Delete sd:/.omninx_oc_update after successful restore
|
||||||
|
int cleanup_horizon_oc_update_backup(void);
|
||||||
|
|||||||
@@ -1,86 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* OmniNX Installer - Deletion Lists for Clean Install Mode
|
* OmniNX Installer - Deletion Lists for Clean Install Mode
|
||||||
* Selective deletion when no OmniNX install was found.
|
* Deletion policy aligned with NiklasCFW pack clean install (TegraExplorer script):
|
||||||
* Only listed paths are removed; does not wipe whole card or user configs.
|
* full sd:/atmosphere, bootloader/config subsets, sd:/switch, root + misc, then
|
||||||
|
* post-restore paths (e.g. tinfoil db). DBI/prod.keys backup is in backup.c.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Atmosphere subdirectories to delete
|
// Entire atmosphere/ tree (NiklasCFW: deldir("sd:/atmosphere"))
|
||||||
static const char* clean_atmosphere_dirs_to_delete[] = {
|
static const char* clean_atmosphere_dirs_to_delete[] = {
|
||||||
"sd:/atmosphere/config",
|
"sd:/atmosphere",
|
||||||
"sd:/atmosphere/crash_reports",
|
|
||||||
"sd:/atmosphere/erpt_reports",
|
|
||||||
"sd:/atmosphere/exefs_patches/CrunchPatch",
|
|
||||||
"sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0",
|
|
||||||
"sd:/atmosphere/exefs_patches/bluetooth_patches",
|
|
||||||
"sd:/atmosphere/exefs_patches/bootlogo",
|
|
||||||
"sd:/atmosphere/exefs_patches/btm_patches",
|
|
||||||
"sd:/atmosphere/exefs_patches/es_patches",
|
|
||||||
"sd:/atmosphere/exefs_patches/hid_patches",
|
|
||||||
"sd:/atmosphere/exefs_patches/logo1",
|
|
||||||
"sd:/atmosphere/exefs_patches/nfim_ctest",
|
|
||||||
"sd:/atmosphere/exefs_patches/nim_ctest",
|
|
||||||
"sd:/atmosphere/exefs_patches/nvnflinger_cmu",
|
|
||||||
"sd:/atmosphere/extrazz",
|
|
||||||
"sd:/atmosphere/fatal_errors",
|
|
||||||
"sd:/atmosphere/fatal_reports",
|
|
||||||
"sd:/atmosphere/flags",
|
|
||||||
"sd:/atmosphere/hbl_html",
|
|
||||||
"sd:/atmosphere/hosts",
|
|
||||||
"sd:/atmosphere/kips",
|
|
||||||
"sd:/atmosphere/kip1",
|
|
||||||
"sd:/atmosphere/kip_patches",
|
|
||||||
"sd:/atmosphere/logs",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Atmosphere contents directories (title IDs; only under atmosphere/contents/)
|
|
||||||
static const char* clean_atmosphere_contents_dirs_to_delete[] = {
|
static const char* clean_atmosphere_contents_dirs_to_delete[] = {
|
||||||
"sd:/atmosphere/contents/0000000000534C56",
|
|
||||||
"sd:/atmosphere/contents/00FF0000B378D640",
|
|
||||||
"sd:/atmosphere/contents/00FF0000636C6BFF",
|
|
||||||
"sd:/atmosphere/contents/00FF0000A53BB665",
|
|
||||||
"sd:/atmosphere/contents/0100000000000008",
|
|
||||||
"sd:/atmosphere/contents/010000000000000D",
|
|
||||||
"sd:/atmosphere/contents/010000000000002B",
|
|
||||||
"sd:/atmosphere/contents/0100000000000032",
|
|
||||||
"sd:/atmosphere/contents/0100000000000034",
|
|
||||||
"sd:/atmosphere/contents/0100000000000036",
|
|
||||||
"sd:/atmosphere/contents/0100000000000037",
|
|
||||||
"sd:/atmosphere/contents/010000000000003C",
|
|
||||||
"sd:/atmosphere/contents/0100000000000042",
|
|
||||||
"sd:/atmosphere/contents/0100000000000895",
|
|
||||||
"sd:/atmosphere/contents/0100000000000F12",
|
|
||||||
"sd:/atmosphere/contents/0100000000001000",
|
|
||||||
"sd:/atmosphere/contents/0100000000001007",
|
|
||||||
"sd:/atmosphere/contents/0100000000001013",
|
|
||||||
"sd:/atmosphere/contents/010000000000DA7A",
|
|
||||||
"sd:/atmosphere/contents/010000000000bd00",
|
|
||||||
"sd:/atmosphere/contents/01006a800016e000",
|
|
||||||
"sd:/atmosphere/contents/01009D901BC56000",
|
|
||||||
"sd:/atmosphere/contents/0100A3900C3E2000",
|
|
||||||
"sd:/atmosphere/contents/0100F43008C44000",
|
|
||||||
"sd:/atmosphere/contents/050000BADDAD0000",
|
|
||||||
"sd:/atmosphere/contents/4200000000000000",
|
|
||||||
"sd:/atmosphere/contents/420000000000000B",
|
|
||||||
"sd:/atmosphere/contents/420000000000000E",
|
|
||||||
"sd:/atmosphere/contents/4200000000000010",
|
|
||||||
"sd:/atmosphere/contents/4200000000000FFF",
|
|
||||||
"sd:/atmosphere/contents/420000000007E51A",
|
|
||||||
"sd:/atmosphere/contents/420000000007E51B",
|
|
||||||
"sd:/atmosphere/contents/690000000000000D",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Atmosphere files to delete
|
|
||||||
static const char* clean_atmosphere_files_to_delete[] = {
|
static const char* clean_atmosphere_files_to_delete[] = {
|
||||||
"sd:/atmosphere/config/exosphere.ini",
|
|
||||||
"sd:/atmosphere/config/stratosphere.ini",
|
|
||||||
"sd:/atmosphere/hbl.nsp",
|
|
||||||
"sd:/atmosphere/package3",
|
|
||||||
"sd:/atmosphere/reboot_payload.bin",
|
|
||||||
"sd:/atmosphere/stratosphere.romfs",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -101,7 +38,6 @@ static const char* clean_bootloader_files_to_delete[] = {
|
|||||||
"sd:/bootloader/ArgonNX.bin",
|
"sd:/bootloader/ArgonNX.bin",
|
||||||
"sd:/bootloader/bootlogo.bmp",
|
"sd:/bootloader/bootlogo.bmp",
|
||||||
"sd:/bootloader/hekate_ipl.ini",
|
"sd:/bootloader/hekate_ipl.ini",
|
||||||
"sd:/bootloader/nyx.ini",
|
|
||||||
"sd:/bootloader/patches.ini",
|
"sd:/bootloader/patches.ini",
|
||||||
"sd:/bootloader/update.bin",
|
"sd:/bootloader/update.bin",
|
||||||
"sd:/bootloader/ini/EmuMMC ohne Mods.ini",
|
"sd:/bootloader/ini/EmuMMC ohne Mods.ini",
|
||||||
@@ -114,7 +50,6 @@ static const char* clean_config_dirs_to_delete[] = {
|
|||||||
"sd:/config/blue_pack_updater",
|
"sd:/config/blue_pack_updater",
|
||||||
"sd:/config/kefir-updater",
|
"sd:/config/kefir-updater",
|
||||||
"sd:/config/nx-hbmenu",
|
"sd:/config/nx-hbmenu",
|
||||||
"sd:/config/quickntp",
|
|
||||||
"sd:/config/sys-con",
|
"sd:/config/sys-con",
|
||||||
"sd:/config/sys-patch",
|
"sd:/config/sys-patch",
|
||||||
"sd:/config/uberhand",
|
"sd:/config/uberhand",
|
||||||
@@ -122,121 +57,13 @@ static const char* clean_config_dirs_to_delete[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Switch directories to delete
|
// Entire switch/ tree (clean install recreates sd:/switch after wipe)
|
||||||
static const char* clean_switch_dirs_to_delete[] = {
|
static const char* clean_switch_dirs_to_delete[] = {
|
||||||
"sd:/switch/.overlays",
|
"sd:/switch",
|
||||||
"sd:/switch/.packages",
|
|
||||||
"sd:/switch/90DNS_tester",
|
|
||||||
"sd:/switch/aio-switch-updater",
|
|
||||||
"sd:/switch/amsPLUS-downloader",
|
|
||||||
"sd:/switch/appstore",
|
|
||||||
"sd:/switch/AtmoXL-Titel-Installer",
|
|
||||||
"sd:/switch/breeze",
|
|
||||||
"sd:/switch/checkpoint",
|
|
||||||
"sd:/switch/cheats-updater",
|
|
||||||
"sd:/switch/chiaki",
|
|
||||||
"sd:/switch/ChoiDujourNX",
|
|
||||||
"sd:/switch/crash_ams",
|
|
||||||
"sd:/switch/Daybreak",
|
|
||||||
"sd:/switch/DBI_658_EN",
|
|
||||||
"sd:/switch/DBI_810",
|
|
||||||
"sd:/switch/DBI_810_DE",
|
|
||||||
"sd:/switch/DBI_810_EN",
|
|
||||||
"sd:/switch/DBI_RU",
|
|
||||||
"sd:/switch/DNS_mitm Tester",
|
|
||||||
"sd:/switch/EdiZon",
|
|
||||||
"sd:/switch/Fizeau",
|
|
||||||
"sd:/switch/FTPD",
|
|
||||||
"sd:/switch/fw-downloader",
|
|
||||||
"sd:/switch/gamecard_installer",
|
|
||||||
"sd:/switch/Goldleaf",
|
|
||||||
"sd:/switch/haze",
|
|
||||||
"sd:/switch/JKSV",
|
|
||||||
"sd:/switch/kefir-updater",
|
|
||||||
"sd:/switch/ldnmitm_config",
|
|
||||||
"sd:/switch/Linkalho",
|
|
||||||
"sd:/switch/Moonlight-Switch",
|
|
||||||
"sd:/switch/Neumann",
|
|
||||||
"sd:/switch/NX-Activity-Log",
|
|
||||||
"sd:/switch/NX-Save-Sync",
|
|
||||||
"sd:/switch/NX-Shell",
|
|
||||||
"sd:/switch/NX-Update-Checker ",
|
|
||||||
"sd:/switch/NXGallery",
|
|
||||||
"sd:/switch/NXRemoteLauncher",
|
|
||||||
"sd:/switch/NXThemesInstaller",
|
|
||||||
"sd:/switch/nxdumptool",
|
|
||||||
"sd:/switch/nxmtp",
|
|
||||||
"sd:/switch/Payload_launcher",
|
|
||||||
"sd:/switch/Reboot",
|
|
||||||
"sd:/switch/reboot_to_argonNX",
|
|
||||||
"sd:/switch/reboot_to_hekate",
|
|
||||||
"sd:/switch/Shutdown_System",
|
|
||||||
"sd:/switch/SimpleModDownloader",
|
|
||||||
"sd:/switch/SimpleModManager",
|
|
||||||
"sd:/switch/sphaira",
|
|
||||||
"sd:/switch/studious-pancake",
|
|
||||||
"sd:/switch/Switch-Time",
|
|
||||||
"sd:/switch/SwitchIdent",
|
|
||||||
"sd:/switch/Switch_themes_Installer",
|
|
||||||
"sd:/switch/Switchfin",
|
|
||||||
"sd:/switch/Sys-Clk Manager",
|
|
||||||
"sd:/switch/Sys-Con",
|
|
||||||
"sd:/switch/sys-clk-manager",
|
|
||||||
"sd:/switch/themezer-nx",
|
|
||||||
"sd:/switch/themezernx",
|
|
||||||
"sd:/switch/tinwoo",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// Switch files (NRO) to delete
|
|
||||||
static const char* clean_switch_files_to_delete[] = {
|
static const char* clean_switch_files_to_delete[] = {
|
||||||
"sd:/switch/90DNS_tester/90DNS_tester.nro",
|
|
||||||
"sd:/switch/breeze.nro",
|
|
||||||
"sd:/switch/cheats-updater.nro",
|
|
||||||
"sd:/switch/chiaki.nro",
|
|
||||||
"sd:/switch/ChoiDujourNX.nro",
|
|
||||||
"sd:/switch/daybreak.nro",
|
|
||||||
"sd:/switch/DBI.nro",
|
|
||||||
"sd:/switch/DBI/DBI.nro",
|
|
||||||
"sd:/switch/DBI/DBI_810_DE.nro",
|
|
||||||
"sd:/switch/DBI/DBI_810_EN.nro",
|
|
||||||
"sd:/switch/DBI/DBI_845_DE.nro",
|
|
||||||
"sd:/switch/DBI/DBI_845_EN.nro",
|
|
||||||
"sd:/switch/DBI/DBI_849_DE.nro",
|
|
||||||
"sd:/switch/DBI/DBI_849_EN.nro",
|
|
||||||
"sd:/switch/DBI_810_DE/DBI_810.nro",
|
|
||||||
"sd:/switch/DBI_810_DE/DBI_810_DE.nro",
|
|
||||||
"sd:/switch/DBI_810_EN/DBI_810_EN.nro",
|
|
||||||
"sd:/switch/DBI_RU/DBI_RU.nro",
|
|
||||||
"sd:/switch/DNS_mitm Tester.nro",
|
|
||||||
"sd:/switch/EdiZon.nro",
|
|
||||||
"sd:/switch/Fizeau.nro",
|
|
||||||
"sd:/switch/Goldleaf.nro",
|
|
||||||
"sd:/switch/haze.nro",
|
|
||||||
"sd:/switch/JKSV.nro",
|
|
||||||
"sd:/switch/ldnmitm_config.nro",
|
|
||||||
"sd:/switch/linkalho.nro",
|
|
||||||
"sd:/switch/Moonlight-Switch.nro",
|
|
||||||
"sd:/switch/Neumann.nro",
|
|
||||||
"sd:/switch/NX-Shell.nro",
|
|
||||||
"sd:/switch/NXGallery.nro",
|
|
||||||
"sd:/switch/NXThemesInstaller.nro",
|
|
||||||
"sd:/switch/nxdumptool.nro",
|
|
||||||
"sd:/switch/nxtc.bin",
|
|
||||||
"sd:/switch/reboot_to_payload.nro",
|
|
||||||
"sd:/switch/SimpleModDownloader.nro",
|
|
||||||
"sd:/switch/SimpleModManager.nro",
|
|
||||||
"sd:/switch/sphaira.nro",
|
|
||||||
"sd:/switch/SwitchIdent.nro",
|
|
||||||
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
|
|
||||||
"sd:/switch/Switchfin.nro",
|
|
||||||
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
|
|
||||||
"sd:/switch/Sys-Con.nro",
|
|
||||||
"sd:/switch/sys-clk-manager.nro",
|
|
||||||
"sd:/switch/tinfoil.nro",
|
|
||||||
"sd:/switch/tinfoil/tinfoil.nro",
|
|
||||||
"sd:/switch/tinwoo.nro",
|
|
||||||
"sd:/switch/tinwoo/tinwoo.nro",
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -264,8 +91,10 @@ static const char* clean_misc_dirs_to_delete[] = {
|
|||||||
"sd:/NSPs (Tools)",
|
"sd:/NSPs (Tools)",
|
||||||
"sd:/Patched Apps",
|
"sd:/Patched Apps",
|
||||||
"sd:/SaltySD/flags",
|
"sd:/SaltySD/flags",
|
||||||
|
"sd:/SaltySD/patches",
|
||||||
"sd:/scripts",
|
"sd:/scripts",
|
||||||
"sd:/switch/tinfoil/db",
|
"sd:/TegraExplorer",
|
||||||
|
"sd:/themes/systemData",
|
||||||
"sd:/tools",
|
"sd:/tools",
|
||||||
"sd:/warmboot_mariko",
|
"sd:/warmboot_mariko",
|
||||||
NULL
|
NULL
|
||||||
@@ -284,15 +113,20 @@ static const char* clean_misc_files_to_delete[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// After DBI/prod.keys restore (NiklasCFW: deldir("sd:/switch/tinfoil/db"))
|
||||||
|
static const char* clean_post_restore_dirs_to_delete[] = {
|
||||||
|
"sd:/switch/tinfoil/db",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
// Old version marker files to delete (clean install only)
|
// Old version marker files to delete (clean install only)
|
||||||
static const char* old_version_files_to_delete[] = {
|
static const char* old_version_files_to_delete[] = {
|
||||||
"sd:/1.0.0l",
|
|
||||||
"sd:/1.0.0s",
|
|
||||||
"sd:/1.0.0oc",
|
|
||||||
"sd:/1.4.0-pre",
|
"sd:/1.4.0-pre",
|
||||||
"sd:/1.4.0-pre-c",
|
"sd:/1.4.0-pre-c",
|
||||||
"sd:/1.4.0-pre-d",
|
"sd:/1.4.0-pre-d",
|
||||||
"sd:/1.4.1",
|
"sd:/1.4.1",
|
||||||
"sd:/1.5.0",
|
"sd:/1.5.0",
|
||||||
|
"sd:/1.6.0",
|
||||||
|
"sd:/1.6.1",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ static const char* atmosphere_files_to_delete[] = {
|
|||||||
"sd:/atmosphere/package3",
|
"sd:/atmosphere/package3",
|
||||||
"sd:/atmosphere/reboot_payload.bin",
|
"sd:/atmosphere/reboot_payload.bin",
|
||||||
"sd:/atmosphere/stratosphere.romfs",
|
"sd:/atmosphere/stratosphere.romfs",
|
||||||
|
"sd:/atmosphere/kips/loader.kip",
|
||||||
|
"sd:/atmosphere/kips/hoc.kip",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,8 +125,8 @@ static const char* config_dirs_to_delete[] = {
|
|||||||
|
|
||||||
// Switch directories to delete
|
// Switch directories to delete
|
||||||
static const char* switch_dirs_to_delete[] = {
|
static const char* switch_dirs_to_delete[] = {
|
||||||
"sd:/switch/.overlays",
|
|
||||||
"sd:/switch/.packages",
|
"sd:/switch/.packages",
|
||||||
|
"sd:/switch/.overlays",
|
||||||
"sd:/switch/90DNS_tester",
|
"sd:/switch/90DNS_tester",
|
||||||
"sd:/switch/aio-switch-updater",
|
"sd:/switch/aio-switch-updater",
|
||||||
"sd:/switch/amsPLUS-downloader",
|
"sd:/switch/amsPLUS-downloader",
|
||||||
@@ -137,11 +139,6 @@ static const char* switch_dirs_to_delete[] = {
|
|||||||
"sd:/switch/ChoiDujourNX",
|
"sd:/switch/ChoiDujourNX",
|
||||||
"sd:/switch/crash_ams",
|
"sd:/switch/crash_ams",
|
||||||
"sd:/switch/Daybreak",
|
"sd:/switch/Daybreak",
|
||||||
"sd:/switch/DBI_658_EN",
|
|
||||||
"sd:/switch/DBI_810",
|
|
||||||
"sd:/switch/DBI_810_DE",
|
|
||||||
"sd:/switch/DBI_810_EN",
|
|
||||||
"sd:/switch/DBI_RU",
|
|
||||||
"sd:/switch/DNS_mitm Tester",
|
"sd:/switch/DNS_mitm Tester",
|
||||||
"sd:/switch/EdiZon",
|
"sd:/switch/EdiZon",
|
||||||
"sd:/switch/Fizeau",
|
"sd:/switch/Fizeau",
|
||||||
@@ -177,7 +174,6 @@ static const char* switch_dirs_to_delete[] = {
|
|||||||
"sd:/switch/Switch-Time",
|
"sd:/switch/Switch-Time",
|
||||||
"sd:/switch/SwitchIdent",
|
"sd:/switch/SwitchIdent",
|
||||||
"sd:/switch/Switch_themes_Installer",
|
"sd:/switch/Switch_themes_Installer",
|
||||||
"sd:/switch/Switchfin",
|
|
||||||
"sd:/switch/Sys-Clk Manager",
|
"sd:/switch/Sys-Clk Manager",
|
||||||
"sd:/switch/Sys-Con",
|
"sd:/switch/Sys-Con",
|
||||||
"sd:/switch/sys-clk-manager",
|
"sd:/switch/sys-clk-manager",
|
||||||
@@ -207,6 +203,8 @@ static const char* switch_files_to_delete[] = {
|
|||||||
"sd:/switch/DBI_810_DE/DBI_810_DE.nro",
|
"sd:/switch/DBI_810_DE/DBI_810_DE.nro",
|
||||||
"sd:/switch/DBI_810_EN/DBI_810_EN.nro",
|
"sd:/switch/DBI_810_EN/DBI_810_EN.nro",
|
||||||
"sd:/switch/DBI_RU/DBI_RU.nro",
|
"sd:/switch/DBI_RU/DBI_RU.nro",
|
||||||
|
"sd:/switch/DBI/DBI_EN.nro",
|
||||||
|
"sd:/switch/DBI_DE/DBI_DE.nro",
|
||||||
"sd:/switch/DNS_mitm Tester.nro",
|
"sd:/switch/DNS_mitm Tester.nro",
|
||||||
"sd:/switch/EdiZon.nro",
|
"sd:/switch/EdiZon.nro",
|
||||||
"sd:/switch/Fizeau.nro",
|
"sd:/switch/Fizeau.nro",
|
||||||
@@ -226,9 +224,9 @@ static const char* switch_files_to_delete[] = {
|
|||||||
"sd:/switch/SimpleModDownloader.nro",
|
"sd:/switch/SimpleModDownloader.nro",
|
||||||
"sd:/switch/SimpleModManager.nro",
|
"sd:/switch/SimpleModManager.nro",
|
||||||
"sd:/switch/sphaira.nro",
|
"sd:/switch/sphaira.nro",
|
||||||
|
"sd:/switch/swr-ini-tool/swr-ini-tool.nro",
|
||||||
"sd:/switch/SwitchIdent.nro",
|
"sd:/switch/SwitchIdent.nro",
|
||||||
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
|
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
|
||||||
"sd:/switch/Switchfin.nro",
|
|
||||||
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
|
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
|
||||||
"sd:/switch/Sys-Con.nro",
|
"sd:/switch/Sys-Con.nro",
|
||||||
"sd:/switch/sys-clk-manager.nro",
|
"sd:/switch/sys-clk-manager.nro",
|
||||||
@@ -265,6 +263,7 @@ static const char* misc_dirs_to_delete[] = {
|
|||||||
"sd:/SaltySD/flags",
|
"sd:/SaltySD/flags",
|
||||||
"sd:/scripts",
|
"sd:/scripts",
|
||||||
"sd:/switch/tinfoil/db",
|
"sd:/switch/tinfoil/db",
|
||||||
|
"sd:/themes/systemData",
|
||||||
"sd:/tools",
|
"sd:/tools",
|
||||||
"sd:/warmboot_mariko",
|
"sd:/warmboot_mariko",
|
||||||
NULL
|
NULL
|
||||||
|
|||||||
46
source/dram_fuse.c
Normal file
46
source/dram_fuse.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* DRAM capacity from fuse (SKU), not physical probe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dram_fuse.h"
|
||||||
|
#include <soc/fuse.h>
|
||||||
|
#include <soc/hw_init.h>
|
||||||
|
#include <soc/t210.h>
|
||||||
|
|
||||||
|
static int mariko_dram_mib(u32 dram_id)
|
||||||
|
{
|
||||||
|
switch (dram_id) {
|
||||||
|
case 9:
|
||||||
|
case 13:
|
||||||
|
case 18:
|
||||||
|
case 21:
|
||||||
|
case 23:
|
||||||
|
case 28:
|
||||||
|
return 8192;
|
||||||
|
default:
|
||||||
|
if (dram_id >= 3 && dram_id <= 28)
|
||||||
|
return 4096;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int erista_dram_mib(u32 dram_id)
|
||||||
|
{
|
||||||
|
if (dram_id == 4)
|
||||||
|
return 6144;
|
||||||
|
if (dram_id <= 6)
|
||||||
|
return 4096;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dram_capacity_mib_from_fuse(void)
|
||||||
|
{
|
||||||
|
u32 nid = fuse_read_dramid(false);
|
||||||
|
u32 chip = hw_get_chip_id();
|
||||||
|
|
||||||
|
if (chip == GP_HIDREV_MAJOR_T210)
|
||||||
|
return erista_dram_mib(nid);
|
||||||
|
if (chip == GP_HIDREV_MAJOR_T210B01)
|
||||||
|
return mariko_dram_mib(nid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
6
source/dram_fuse.h
Normal file
6
source/dram_fuse.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/types.h>
|
||||||
|
|
||||||
|
/* DRAM capacity in MiB from fuse DRAM ID + SoC (same table as RAM test payload). */
|
||||||
|
int dram_capacity_mib_from_fuse(void);
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* HATS Installer - Filesystem operations with file logging
|
* OmniNX Installer - Filesystem operations with file logging
|
||||||
|
* Based on HATS Installer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@@ -23,7 +24,7 @@ void log_init(const char *path) {
|
|||||||
int res = f_open(&log_file, path, FA_WRITE | FA_CREATE_ALWAYS);
|
int res = f_open(&log_file, path, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
log_enabled = true;
|
log_enabled = true;
|
||||||
log_write("=== HATS Installer Log ===\n\n");
|
log_write("=== OmniNX Installer Log ===\n\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* HATS Installer - Filesystem operations
|
* OmniNX Installer - Filesystem operations
|
||||||
|
* Based on HATS Installer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|||||||
649
source/install.c
649
source/install.c
@@ -3,12 +3,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
|
#include "backup.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "screenshot.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
|
#include <input/joycon.h>
|
||||||
|
#include <mem/heap.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <utils/btn.h>
|
||||||
|
#include <utils/ini.h>
|
||||||
|
#include <utils/list.h>
|
||||||
#include <utils/sprintf.h>
|
#include <utils/sprintf.h>
|
||||||
|
#include <utils/util.h>
|
||||||
|
|
||||||
|
#define GROUPED_DELETE_MAX_ENTRIES 512
|
||||||
|
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
#define VERSION "1.0.0"
|
#define VERSION "1.0.0"
|
||||||
@@ -29,10 +40,25 @@
|
|||||||
#define COLOR_ORANGE 0xFF00A5FF
|
#define COLOR_ORANGE 0xFF00A5FF
|
||||||
#define COLOR_RED 0xFFFF0000
|
#define COLOR_RED 0xFFFF0000
|
||||||
|
|
||||||
|
static inline bool cancel_combo_pressed(u8 btn)
|
||||||
|
{
|
||||||
|
return (btn & (BTN_VOL_UP | BTN_VOL_DOWN)) == (BTN_VOL_UP | BTN_VOL_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
void install_set_color(u32 color) {
|
void install_set_color(u32 color) {
|
||||||
gfx_con_setcol(color, gfx_con.fillbg, gfx_con.bgcol);
|
gfx_con_setcol(color, gfx_con.fillbg, gfx_con.bgcol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Same top bar as main.c print_header() (without full screen clear). */
|
||||||
|
static void install_print_main_header(void)
|
||||||
|
{
|
||||||
|
install_set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("===================================\n");
|
||||||
|
gfx_printf(" OmniNX Installer Payload v%s\n", VERSION);
|
||||||
|
gfx_printf("===================================\n\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we need to clear screen (when getting close to bottom)
|
// Check if we need to clear screen (when getting close to bottom)
|
||||||
void install_check_and_clear_screen_if_needed(void) {
|
void install_check_and_clear_screen_if_needed(void) {
|
||||||
// In the gfx system:
|
// In the gfx system:
|
||||||
@@ -47,13 +73,7 @@ void install_check_and_clear_screen_if_needed(void) {
|
|||||||
// Clear screen and reset position
|
// Clear screen and reset position
|
||||||
gfx_clear_grey(0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
install_print_main_header();
|
||||||
// Reprint same header as initial launch
|
|
||||||
install_set_color(COLOR_CYAN);
|
|
||||||
gfx_printf("===================================\n");
|
|
||||||
gfx_printf(" OmniNX Installer Payload v%s\n", VERSION);
|
|
||||||
gfx_printf("===================================\n\n");
|
|
||||||
install_set_color(COLOR_WHITE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +130,38 @@ void install_combine_path(char *result, size_t size, const char *base, const cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy every regular file at staging root to dst_root; subdirs and volume labels skipped. */
|
||||||
|
int install_copy_staging_root_files(const char *staging, const char *dst_root) {
|
||||||
|
DIR dir;
|
||||||
|
FILINFO fno;
|
||||||
|
char src_full[256];
|
||||||
|
char dst_full[256];
|
||||||
|
int res = f_opendir(&dir, staging);
|
||||||
|
if (res != FR_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
res = f_readdir(&dir, &fno);
|
||||||
|
if (res != FR_OK || fno.fname[0] == 0)
|
||||||
|
break;
|
||||||
|
if (fno.fname[0] == '.' && (fno.fname[1] == '\0' || (fno.fname[1] == '.' && fno.fname[2] == '\0')))
|
||||||
|
continue;
|
||||||
|
if (fno.fattrib & (AM_DIR | AM_VOL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
install_combine_path(src_full, sizeof(src_full), staging, fno.fname);
|
||||||
|
install_combine_path(dst_full, sizeof(dst_full), dst_root, fno.fname);
|
||||||
|
res = file_copy(src_full, dst_full);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
f_closedir(&dir);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f_closedir(&dir);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Recursive folder copy with progress tracking
|
// Recursive folder copy with progress tracking
|
||||||
static int folder_copy_progress_recursive(const char *src, const char *dst, int *copied, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent) {
|
static int folder_copy_progress_recursive(const char *src, const char *dst, int *copied, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent) {
|
||||||
DIR dir;
|
DIR dir;
|
||||||
@@ -395,6 +447,89 @@ int folder_delete_single_with_progress(const char *path, const char *display_nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete a list of paths with progress tracking
|
// Delete a list of paths with progress tracking
|
||||||
|
// Delete multiple path lists under one label; one progress line "Bereinige: folder/ [p%] (d/t)".
|
||||||
|
// Varargs: path lists (const char**), terminated by NULL.
|
||||||
|
int delete_path_lists_grouped(const char *folder_display_name, ...) {
|
||||||
|
va_list ap;
|
||||||
|
const char *entries[GROUPED_DELETE_MAX_ENTRIES];
|
||||||
|
int n_entries = 0;
|
||||||
|
int deleted = 0;
|
||||||
|
int failed = 0;
|
||||||
|
u32 start_x, start_y;
|
||||||
|
int last_percent = -1;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
va_start(ap, folder_display_name);
|
||||||
|
const char **list;
|
||||||
|
while (n_entries < GROUPED_DELETE_MAX_ENTRIES && (list = va_arg(ap, const char **)) != NULL) {
|
||||||
|
for (int i = 0; list[i] != NULL && n_entries < GROUPED_DELETE_MAX_ENTRIES; i++) {
|
||||||
|
if (install_path_exists(list[i]))
|
||||||
|
entries[n_entries++] = list[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (n_entries == 0)
|
||||||
|
return FR_OK;
|
||||||
|
|
||||||
|
int total_paths = n_entries;
|
||||||
|
gfx_con_getpos(&start_x, &start_y);
|
||||||
|
install_set_color(COLOR_CYAN);
|
||||||
|
gfx_printf(" Bereinige: %s [ 0%%] (0/%d)", folder_display_name, total_paths);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
for (int i = 0; i < n_entries; i++) {
|
||||||
|
const char *path = entries[i];
|
||||||
|
FILINFO fno;
|
||||||
|
if (f_stat(path, &fno) != FR_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char *item_name = strrchr(path, '/');
|
||||||
|
if (item_name) item_name++;
|
||||||
|
else item_name = path;
|
||||||
|
|
||||||
|
if (fno.fattrib & AM_DIR) {
|
||||||
|
int item_count = install_count_directory_items(path);
|
||||||
|
if (item_count > 50) {
|
||||||
|
gfx_printf("\n");
|
||||||
|
res = folder_delete_single_with_progress(path, item_name);
|
||||||
|
} else {
|
||||||
|
res = folder_delete(path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fno.fattrib & AM_RDO)
|
||||||
|
f_chmod(path, fno.fattrib & ~AM_RDO, AM_RDO);
|
||||||
|
res = f_unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == FR_OK || res == FR_NO_FILE)
|
||||||
|
deleted++;
|
||||||
|
else
|
||||||
|
failed++;
|
||||||
|
|
||||||
|
int percent = (deleted * 100) / total_paths;
|
||||||
|
if (percent != last_percent || deleted % 5 == 0) {
|
||||||
|
gfx_con_setpos(start_x, start_y);
|
||||||
|
install_set_color(COLOR_CYAN);
|
||||||
|
gfx_printf(" Bereinige: %s [%3d%%] (%d/%d)", folder_display_name, percent, deleted, total_paths);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
last_percent = percent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_con_setpos(start_x, start_y);
|
||||||
|
if (failed == 0) {
|
||||||
|
install_set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" Bereinige: %s [100%%] (%d/%d) - Fertig!\n", folder_display_name, deleted, total_paths);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf(" Bereinige: %s [%3d%%] (%d/%d) - %d Fehler\n", folder_display_name, last_percent, deleted, total_paths, failed);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
return (failed == 0) ? FR_OK : FR_DISK_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
int delete_path_list(const char* paths[], const char* description) {
|
int delete_path_list(const char* paths[], const char* description) {
|
||||||
int res;
|
int res;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
@@ -500,65 +635,517 @@ int delete_path_list(const char* paths[], const char* description) {
|
|||||||
return (failed == 0) ? FR_OK : FR_DISK_ERR;
|
return (failed == 0) ? FR_OK : FR_DISK_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HEKATE_8GB_SRC "sd:/bootloader/hekate_8gb.bin"
|
||||||
|
#define PAYLOAD_BIN_DST "sd:/payload.bin"
|
||||||
|
#define UPDATE_BIN_DST "sd:/bootloader/update.bin"
|
||||||
|
#define RAM_CONFIG_PATH "sd:/config/omninx/ram_config.ini"
|
||||||
|
|
||||||
|
enum { RAM_READ_OK = 0, RAM_READ_NEED_MENU = 1 };
|
||||||
|
|
||||||
|
static void unlink_ignore_err(const char *path)
|
||||||
|
{
|
||||||
|
FILINFO fno;
|
||||||
|
if (f_stat(path, &fno) != FR_OK)
|
||||||
|
return;
|
||||||
|
if (fno.fattrib & AM_RDO)
|
||||||
|
f_chmod(path, fno.fattrib & ~AM_RDO, AM_RDO);
|
||||||
|
f_unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ram_config_ensure_parent_dirs(void)
|
||||||
|
{
|
||||||
|
f_mkdir("sd:/config");
|
||||||
|
f_mkdir("sd:/config/omninx");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ram_config_write(bool use_8gb)
|
||||||
|
{
|
||||||
|
ram_config_ensure_parent_dirs();
|
||||||
|
FIL f;
|
||||||
|
if (f_open(&f, RAM_CONFIG_PATH, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||||
|
return FR_DISK_ERR;
|
||||||
|
|
||||||
|
static const char sec[] = "[Ram]\n";
|
||||||
|
static const char line0[] = "8gb=0\n";
|
||||||
|
static const char line1[] = "8gb=1\n";
|
||||||
|
UINT bw;
|
||||||
|
f_write(&f, sec, sizeof(sec) - 1, &bw);
|
||||||
|
f_write(&f, use_8gb ? line1 : line0, sizeof(line0) - 1, &bw);
|
||||||
|
f_close(&f);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ram_config_free_sections(link_t *sections)
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, sec, sections, link) {
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
|
||||||
|
if (kv->key) free(kv->key);
|
||||||
|
if (kv->val) free(kv->val);
|
||||||
|
}
|
||||||
|
if (sec->name) free(sec->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Valid [Ram] 8gb=0|1 → silent; missing file or invalid → menu. */
|
||||||
|
static int read_ram_config_silent(const char *path, bool *use_8gb)
|
||||||
|
{
|
||||||
|
if (!install_path_exists(path))
|
||||||
|
return RAM_READ_NEED_MENU;
|
||||||
|
|
||||||
|
link_t sections;
|
||||||
|
list_init(§ions);
|
||||||
|
|
||||||
|
if (ini_parse(§ions, (char *)path, false) != 1) {
|
||||||
|
ram_config_free_sections(§ions);
|
||||||
|
return RAM_READ_NEED_MENU;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
bool eight = false;
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, sec, §ions, link) {
|
||||||
|
if (sec->name && !strcmp(sec->name, "Ram")) {
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
|
||||||
|
if (kv->key && kv->val && !strcmp(kv->key, "8gb")) {
|
||||||
|
if (!strcmp(kv->val, "0")) {
|
||||||
|
found = true;
|
||||||
|
eight = false;
|
||||||
|
} else if (!strcmp(kv->val, "1")) {
|
||||||
|
found = true;
|
||||||
|
eight = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ram_config_free_sections(§ions);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return RAM_READ_NEED_MENU;
|
||||||
|
*use_8gb = eight;
|
||||||
|
return RAM_READ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Same navigation as main.c multi-variant menu; returns false if user aborts (payload/reboot). */
|
||||||
|
static bool install_ram_config_menu(bool *use_8gb)
|
||||||
|
{
|
||||||
|
jc_init_hw();
|
||||||
|
while (btn_read() & BTN_POWER)
|
||||||
|
msleep(50);
|
||||||
|
|
||||||
|
int selected = 0;
|
||||||
|
int prev_selected = 0;
|
||||||
|
bool confirmed = false;
|
||||||
|
const int n = 2;
|
||||||
|
const char *labels[2] = {
|
||||||
|
"4GB Konsole (Standard)",
|
||||||
|
"8GB Konsole",
|
||||||
|
};
|
||||||
|
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
install_print_main_header();
|
||||||
|
|
||||||
|
install_set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Hekate Payload Auswahl:\n\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
gfx_printf("Wenn du einen 8GB RAM-Umbau hast, waehle 8GB Konsole aus.\n");
|
||||||
|
gfx_printf("Alle anderen waehlen 4GB Konsole aus.\n\n");
|
||||||
|
install_set_color(COLOR_RED);
|
||||||
|
gfx_printf("Warnung: Solltest du keinen RAM-Umbau haben, waehle auf keinen\n");
|
||||||
|
gfx_printf("Fall 8GB aus, da du sonst Boot Probleme bekommst!!!\n\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
u32 menu_x, menu_y;
|
||||||
|
gfx_con_getpos(&menu_x, &menu_y);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (i == selected) {
|
||||||
|
install_set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" > %s\n", labels[i]);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
} else {
|
||||||
|
gfx_printf(" %s\n", labels[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gfx_printf("\n");
|
||||||
|
install_set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n");
|
||||||
|
gfx_printf("Vol+ und Vol- gleichzeitig: Abbrechen (Hekate)\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
bool prev_up = false, prev_down = false;
|
||||||
|
bool menu_aborted = false;
|
||||||
|
|
||||||
|
while (!confirmed && !menu_aborted) {
|
||||||
|
if (selected != prev_selected) {
|
||||||
|
gfx_con_setpos(menu_x, menu_y + (u32)prev_selected * 16);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
gfx_printf(" %s\n", labels[prev_selected]);
|
||||||
|
gfx_con_setpos(menu_x, menu_y + (u32)selected * 16);
|
||||||
|
install_set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" > %s\n", labels[selected]);
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
prev_selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
|
u8 btn = btn_read();
|
||||||
|
|
||||||
|
if (jc && jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
|
||||||
|
if (cancel_combo_pressed(btn)) {
|
||||||
|
menu_aborted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cur_up = false, cur_down = false;
|
||||||
|
if (jc) {
|
||||||
|
cur_up = (jc->up != 0) && !jc->down;
|
||||||
|
cur_down = (jc->down != 0) && !jc->up;
|
||||||
|
}
|
||||||
|
if (btn & BTN_VOL_UP)
|
||||||
|
cur_up = true;
|
||||||
|
if (btn & BTN_VOL_DOWN)
|
||||||
|
cur_down = true;
|
||||||
|
|
||||||
|
if (cur_up && !prev_up)
|
||||||
|
selected = (selected - 1 + n) % n;
|
||||||
|
else if (cur_down && !prev_down)
|
||||||
|
selected = (selected + 1) % n;
|
||||||
|
else if (jc && jc->a)
|
||||||
|
confirmed = true;
|
||||||
|
|
||||||
|
prev_up = cur_up;
|
||||||
|
prev_down = cur_down;
|
||||||
|
|
||||||
|
if (btn & BTN_POWER)
|
||||||
|
confirmed = true;
|
||||||
|
|
||||||
|
msleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu_aborted) {
|
||||||
|
gfx_printf("\n");
|
||||||
|
install_set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Abgebrochen. Starte Hekate...\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
msleep(500);
|
||||||
|
installer_launch_hekate_payload();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*use_8gb = (selected == 1);
|
||||||
|
ram_config_write(*use_8gb);
|
||||||
|
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
install_print_main_header();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After pack copy: use ram_config.ini [Ram] 8gb=0|1 if present; else menu, write file, then apply. No fuse autodetect. */
|
||||||
|
static void install_hekate_8gb_post_copy(void)
|
||||||
|
{
|
||||||
|
if (!install_path_exists(HEKATE_8GB_SRC))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool use_8gb;
|
||||||
|
if (read_ram_config_silent(RAM_CONFIG_PATH, &use_8gb) != RAM_READ_OK) {
|
||||||
|
if (!install_ram_config_menu(&use_8gb))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_8gb) {
|
||||||
|
int r1 = file_copy(HEKATE_8GB_SRC, PAYLOAD_BIN_DST);
|
||||||
|
int r2 = file_copy(HEKATE_8GB_SRC, UPDATE_BIN_DST);
|
||||||
|
if (r1 == FR_OK && r2 == FR_OK)
|
||||||
|
unlink_ignore_err(HEKATE_8GB_SRC);
|
||||||
|
} else {
|
||||||
|
unlink_ignore_err(HEKATE_8GB_SRC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INSTALL_DEBUG_INI "sd:/config/omninx/debug.ini"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool active;
|
||||||
|
bool skip_clean_backup;
|
||||||
|
bool skip_clean_wipe;
|
||||||
|
bool skip_clean_restore;
|
||||||
|
bool skip_clean_install;
|
||||||
|
bool skip_clean_staging_cleanup;
|
||||||
|
bool skip_update_cleanup;
|
||||||
|
bool skip_update_install;
|
||||||
|
bool skip_update_staging_cleanup;
|
||||||
|
bool skip_update_horizon_oc;
|
||||||
|
bool skip_hekate_8gb_post_copy;
|
||||||
|
} install_debug_opts_t;
|
||||||
|
|
||||||
|
static bool install_ini_truth(const char *val)
|
||||||
|
{
|
||||||
|
if (!val || !val[0])
|
||||||
|
return false;
|
||||||
|
char c = val[0];
|
||||||
|
return c == '1' || c == 't' || c == 'T' || c == 'y' || c == 'Y';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void install_debug_load(install_debug_opts_t *d)
|
||||||
|
{
|
||||||
|
memset(d, 0, sizeof(*d));
|
||||||
|
if (!install_path_exists(INSTALL_DEBUG_INI))
|
||||||
|
return;
|
||||||
|
|
||||||
|
link_t sections;
|
||||||
|
list_init(§ions);
|
||||||
|
if (ini_parse(§ions, (char *)INSTALL_DEBUG_INI, false) != 1) {
|
||||||
|
ram_config_free_sections(§ions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, sec, §ions, link) {
|
||||||
|
if (!sec->name || strcmp(sec->name, "Debug") != 0)
|
||||||
|
continue;
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
|
||||||
|
if (!kv->key || !kv->val)
|
||||||
|
continue;
|
||||||
|
if (strcmp(kv->key, "skip_clean_backup") == 0)
|
||||||
|
d->skip_clean_backup = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_clean_wipe") == 0)
|
||||||
|
d->skip_clean_wipe = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_clean_restore") == 0)
|
||||||
|
d->skip_clean_restore = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_clean_install") == 0)
|
||||||
|
d->skip_clean_install = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_clean_staging_cleanup") == 0)
|
||||||
|
d->skip_clean_staging_cleanup = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_update_cleanup") == 0)
|
||||||
|
d->skip_update_cleanup = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_update_install") == 0)
|
||||||
|
d->skip_update_install = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_update_staging_cleanup") == 0)
|
||||||
|
d->skip_update_staging_cleanup = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_update_horizon_oc") == 0)
|
||||||
|
d->skip_update_horizon_oc = install_ini_truth(kv->val);
|
||||||
|
else if (strcmp(kv->key, "skip_hekate_8gb_post_copy") == 0)
|
||||||
|
d->skip_hekate_8gb_post_copy = install_ini_truth(kv->val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ram_config_free_sections(§ions);
|
||||||
|
|
||||||
|
d->active = d->skip_clean_backup || d->skip_clean_wipe || d->skip_clean_restore
|
||||||
|
|| d->skip_clean_install || d->skip_clean_staging_cleanup || d->skip_update_cleanup
|
||||||
|
|| d->skip_update_install || d->skip_update_staging_cleanup || d->skip_update_horizon_oc
|
||||||
|
|| d->skip_hekate_8gb_post_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void install_debug_print_banner(const install_debug_opts_t *d)
|
||||||
|
{
|
||||||
|
if (!d->active)
|
||||||
|
return;
|
||||||
|
install_set_color(COLOR_RED);
|
||||||
|
gfx_printf("*** DEBUG-MODUS: %s ***\n", INSTALL_DEBUG_INI);
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
if (d->skip_clean_backup)
|
||||||
|
gfx_printf(" ueberspringe: Clean Schritt 1 (Backup)\n");
|
||||||
|
if (d->skip_clean_wipe)
|
||||||
|
gfx_printf(" ueberspringe: Clean Schritt 2 (Bereinigung)\n");
|
||||||
|
if (d->skip_clean_restore)
|
||||||
|
gfx_printf(" ueberspringe: Clean Schritt 3 (Restore)\n");
|
||||||
|
if (d->skip_clean_install)
|
||||||
|
gfx_printf(" ueberspringe: Clean Schritt 4 (Kopieren)\n");
|
||||||
|
if (d->skip_clean_staging_cleanup)
|
||||||
|
gfx_printf(" ueberspringe: Clean Staging-Aufraeumen\n");
|
||||||
|
if (d->skip_update_cleanup)
|
||||||
|
gfx_printf(" ueberspringe: Update Schritt 1 (Bereinigung)\n");
|
||||||
|
if (d->skip_update_install)
|
||||||
|
gfx_printf(" ueberspringe: Update Schritt 2 (Kopieren)\n");
|
||||||
|
if (d->skip_update_staging_cleanup)
|
||||||
|
gfx_printf(" ueberspringe: Update Staging-Aufraeumen\n");
|
||||||
|
if (d->skip_update_horizon_oc)
|
||||||
|
gfx_printf(" ueberspringe: HorizonOC Update (Backup/Restore)\n");
|
||||||
|
if (d->skip_hekate_8gb_post_copy)
|
||||||
|
gfx_printf(" ueberspringe: hekate 8GB RAM Auswahl / Post-Copy\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
gfx_printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Main installation function
|
// Main installation function
|
||||||
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
|
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
|
||||||
int res;
|
int res;
|
||||||
|
install_debug_opts_t dbg;
|
||||||
|
install_debug_load(&dbg);
|
||||||
|
install_debug_print_banner(&dbg);
|
||||||
|
|
||||||
if (mode == INSTALL_MODE_UPDATE) {
|
if (mode == INSTALL_MODE_UPDATE) {
|
||||||
// Update mode: selective cleanup then install
|
if (pack_variant == VARIANT_OC && !dbg.skip_update_horizon_oc) {
|
||||||
install_set_color(COLOR_YELLOW);
|
bool had_horizon_cfg = install_path_exists(HORIZON_OC_CONFIG_PATH);
|
||||||
gfx_printf("Schritt 1: Bereinigung...\n");
|
install_set_color(COLOR_YELLOW);
|
||||||
install_set_color(COLOR_WHITE);
|
gfx_printf("HorizonOC: Sichere config.ini...\n");
|
||||||
res = update_mode_cleanup(pack_variant);
|
install_set_color(COLOR_WHITE);
|
||||||
if (res != FR_OK) return res;
|
res = backup_horizon_oc_config_for_oc_update();
|
||||||
|
if (res != FR_OK)
|
||||||
|
return res;
|
||||||
|
if (had_horizon_cfg) {
|
||||||
|
install_set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" [OK] Bestehende config.ini gesichert.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
} else if (pack_variant == VARIANT_OC && dbg.skip_update_horizon_oc) {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] HorizonOC Backup uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbg.skip_update_cleanup) {
|
||||||
|
install_set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Schritt 1: Bereinigung...\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
res = update_mode_cleanup(pack_variant);
|
||||||
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 1 (Bereinigung) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
install_check_and_clear_screen_if_needed();
|
||||||
gfx_printf("\n");
|
gfx_printf("\n");
|
||||||
install_set_color(COLOR_YELLOW);
|
|
||||||
gfx_printf("Schritt 2: Dateien kopieren...\n");
|
if (!dbg.skip_update_install) {
|
||||||
install_set_color(COLOR_WHITE);
|
install_set_color(COLOR_YELLOW);
|
||||||
res = update_mode_install(pack_variant);
|
gfx_printf("Schritt 2: Dateien kopieren...\n");
|
||||||
if (res != FR_OK) return res;
|
install_set_color(COLOR_WHITE);
|
||||||
|
res = update_mode_install(pack_variant);
|
||||||
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 2 (Kopieren) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbg.skip_hekate_8gb_post_copy)
|
||||||
|
install_hekate_8gb_post_copy();
|
||||||
|
else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] hekate 8GB Post-Copy uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pack_variant == VARIANT_OC && !dbg.skip_update_horizon_oc) {
|
||||||
|
bool had_horizon_bak = install_path_exists(HORIZON_OC_UPDATE_BACKUP_INI);
|
||||||
|
install_check_and_clear_screen_if_needed();
|
||||||
|
install_set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("HorizonOC: Stelle config.ini wieder her...\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
res = restore_horizon_oc_config_after_oc_update();
|
||||||
|
if (res != FR_OK)
|
||||||
|
return res;
|
||||||
|
install_set_color(COLOR_GREEN);
|
||||||
|
if (had_horizon_bak)
|
||||||
|
gfx_printf(" [OK] Deine HorizonOC-Einstellungen wurden wiederhergestellt.\n");
|
||||||
|
else
|
||||||
|
gfx_printf(" [OK] Keine fruehere config.ini — Standard aus dem Paket bleibt.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
res = cleanup_horizon_oc_update_backup();
|
||||||
|
if (res != FR_OK)
|
||||||
|
return res;
|
||||||
|
} else if (pack_variant == VARIANT_OC && dbg.skip_update_horizon_oc) {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] HorizonOC Restore uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
install_check_and_clear_screen_if_needed();
|
||||||
// Remove staging directory
|
if (!dbg.skip_update_staging_cleanup) {
|
||||||
res = cleanup_staging_directory(pack_variant);
|
res = cleanup_staging_directory(pack_variant);
|
||||||
return res;
|
if (res != FR_OK) return res;
|
||||||
} else {
|
res = cleanup_other_staging_directories(pack_variant);
|
||||||
// Clean mode: backup, wipe, restore, install
|
return res;
|
||||||
|
}
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Staging-Aufraeumen uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dbg.skip_clean_backup) {
|
||||||
install_set_color(COLOR_YELLOW);
|
install_set_color(COLOR_YELLOW);
|
||||||
gfx_printf("Schritt 1: Sichere Benutzerdaten...\n");
|
gfx_printf("Schritt 1: Sichere Benutzerdaten...\n");
|
||||||
install_set_color(COLOR_WHITE);
|
install_set_color(COLOR_WHITE);
|
||||||
res = clean_mode_backup();
|
res = clean_mode_backup();
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 1 (Backup) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
install_check_and_clear_screen_if_needed();
|
||||||
gfx_printf("\n");
|
gfx_printf("\n");
|
||||||
|
|
||||||
|
if (!dbg.skip_clean_wipe) {
|
||||||
install_set_color(COLOR_YELLOW);
|
install_set_color(COLOR_YELLOW);
|
||||||
gfx_printf("Schritt 2: Bereinige alte Installation...\n");
|
gfx_printf("Schritt 2: Bereinige alte Installation...\n");
|
||||||
install_set_color(COLOR_WHITE);
|
install_set_color(COLOR_WHITE);
|
||||||
res = clean_mode_wipe();
|
res = clean_mode_wipe();
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 2 (Bereinigung) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
install_check_and_clear_screen_if_needed();
|
||||||
gfx_printf("\n");
|
gfx_printf("\n");
|
||||||
|
|
||||||
|
if (!dbg.skip_clean_restore) {
|
||||||
install_set_color(COLOR_YELLOW);
|
install_set_color(COLOR_YELLOW);
|
||||||
gfx_printf("Schritt 3: Stelle Benutzerdaten wieder her...\n");
|
gfx_printf("Schritt 3: Stelle Benutzerdaten wieder her...\n");
|
||||||
install_set_color(COLOR_WHITE);
|
install_set_color(COLOR_WHITE);
|
||||||
res = clean_mode_restore();
|
res = clean_mode_restore();
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 3 (Restore) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
install_check_and_clear_screen_if_needed();
|
||||||
gfx_printf("\n");
|
gfx_printf("\n");
|
||||||
|
|
||||||
|
if (!dbg.skip_clean_install) {
|
||||||
install_set_color(COLOR_YELLOW);
|
install_set_color(COLOR_YELLOW);
|
||||||
gfx_printf("Schritt 4: Dateien kopieren...\n");
|
gfx_printf("Schritt 4: Dateien kopieren...\n");
|
||||||
install_set_color(COLOR_WHITE);
|
install_set_color(COLOR_WHITE);
|
||||||
res = clean_mode_install(pack_variant);
|
res = clean_mode_install(pack_variant);
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
|
} else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Schritt 4 (Kopieren) uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
install_check_and_clear_screen_if_needed();
|
if (!dbg.skip_hekate_8gb_post_copy)
|
||||||
// Remove staging directory
|
install_hekate_8gb_post_copy();
|
||||||
|
else {
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] hekate 8GB Post-Copy uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
install_check_and_clear_screen_if_needed();
|
||||||
|
if (!dbg.skip_clean_staging_cleanup) {
|
||||||
res = cleanup_staging_directory(pack_variant);
|
res = cleanup_staging_directory(pack_variant);
|
||||||
|
if (res != FR_OK) return res;
|
||||||
|
res = cleanup_other_staging_directories(pack_variant);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
install_set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("[DEBUG] Staging-Aufraeumen uebersprungen.\n");
|
||||||
|
install_set_color(COLOR_WHITE);
|
||||||
|
return FR_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,18 @@ typedef enum {
|
|||||||
INSTALL_MODE_CLEAN // No OmniNX - selective deletion from clean list
|
INSTALL_MODE_CLEAN // No OmniNX - selective deletion from clean list
|
||||||
} install_mode_t;
|
} install_mode_t;
|
||||||
|
|
||||||
// Main installation function
|
// If a sub-menu aborts to Hekate / update.bin (does not return if launch succeeds)
|
||||||
|
void installer_launch_hekate_payload(void);
|
||||||
|
|
||||||
|
// Main installation function (optional debug: see DEBUG_INI.md in repo root)
|
||||||
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode);
|
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode);
|
||||||
|
|
||||||
// Update mode operations (install_update.c)
|
// Update mode operations (install_update.c)
|
||||||
int update_mode_cleanup(omninx_variant_t variant);
|
int update_mode_cleanup(omninx_variant_t variant);
|
||||||
int update_mode_install(omninx_variant_t variant);
|
int update_mode_install(omninx_variant_t variant);
|
||||||
int cleanup_staging_directory(omninx_variant_t pack_variant);
|
int cleanup_staging_directory(omninx_variant_t pack_variant);
|
||||||
|
// Remove other OmniNX staging directories (Standard/Light/OC) that exist, except the one just installed
|
||||||
|
int cleanup_other_staging_directories(omninx_variant_t installed_variant);
|
||||||
|
|
||||||
// Clean install operations (install_clean.c)
|
// Clean install operations (install_clean.c)
|
||||||
int clean_mode_backup(void);
|
int clean_mode_backup(void);
|
||||||
@@ -33,7 +38,9 @@ void install_check_and_clear_screen_if_needed(void);
|
|||||||
bool install_path_exists(const char *path);
|
bool install_path_exists(const char *path);
|
||||||
int install_count_directory_items(const char *path);
|
int install_count_directory_items(const char *path);
|
||||||
void install_combine_path(char *result, size_t size, const char *base, const char *add);
|
void install_combine_path(char *result, size_t size, const char *base, const char *add);
|
||||||
|
int install_copy_staging_root_files(const char *staging, const char *dst_root);
|
||||||
int delete_path_list(const char* paths[], const char* description);
|
int delete_path_list(const char* paths[], const char* description);
|
||||||
|
int delete_path_lists_grouped(const char *folder_display_name, ...);
|
||||||
int folder_delete_single_with_progress(const char *path, const char *display_name);
|
int folder_delete_single_with_progress(const char *path, const char *display_name);
|
||||||
int folder_delete_progress_recursive(const char *path, int *deleted, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent);
|
int folder_delete_progress_recursive(const char *path, int *deleted, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent);
|
||||||
int folder_copy_with_progress_v2(const char *src, const char *dst, const char *display_name);
|
int folder_copy_with_progress_v2(const char *src, const char *dst, const char *display_name);
|
||||||
|
|||||||
@@ -9,25 +9,32 @@
|
|||||||
#include "deletion_lists_clean.h"
|
#include "deletion_lists_clean.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
#include "version.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#undef COLOR_CYAN
|
#undef COLOR_CYAN
|
||||||
#undef COLOR_WHITE
|
#undef COLOR_WHITE
|
||||||
#undef COLOR_GREEN
|
#undef COLOR_GREEN
|
||||||
#undef COLOR_RED
|
#undef COLOR_RED
|
||||||
|
#undef COLOR_YELLOW
|
||||||
|
#undef COLOR_ORANGE
|
||||||
#define COLOR_CYAN 0xFF00FFFF
|
#define COLOR_CYAN 0xFF00FFFF
|
||||||
#define COLOR_WHITE 0xFFFFFFFF
|
#define COLOR_WHITE 0xFFFFFFFF
|
||||||
#define COLOR_GREEN 0xFF00FF00
|
#define COLOR_GREEN 0xFF00FF00
|
||||||
#define COLOR_RED 0xFFFF0000
|
#define COLOR_RED 0xFFFF0000
|
||||||
|
#define COLOR_YELLOW 0xFFFFDD00
|
||||||
|
#define COLOR_ORANGE 0xFF00A5FF
|
||||||
|
|
||||||
#define set_color install_set_color
|
#define set_color install_set_color
|
||||||
#define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed
|
#define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed
|
||||||
#define path_exists install_path_exists
|
#define path_exists install_path_exists
|
||||||
|
#define count_directory_items install_count_directory_items
|
||||||
|
|
||||||
// Clean mode: Backup user data
|
// Clean mode: Backup user data
|
||||||
int clean_mode_backup(void) {
|
int clean_mode_backup(void) {
|
||||||
set_color(COLOR_CYAN);
|
set_color(COLOR_CYAN);
|
||||||
gfx_printf(" Sichere: DBI, Tinfoil, prod.keys\n");
|
gfx_printf(" Sichere: DBI (dbi.config), prod.keys\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
int res = backup_user_data();
|
int res = backup_user_data();
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
@@ -42,41 +49,36 @@ int clean_mode_backup(void) {
|
|||||||
int clean_mode_wipe(void) {
|
int clean_mode_wipe(void) {
|
||||||
check_and_clear_screen_if_needed();
|
check_and_clear_screen_if_needed();
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
|
||||||
gfx_printf(" Bereinige: atmosphere/\n");
|
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
delete_path_list(clean_atmosphere_dirs_to_delete, "atmosphere subdirs");
|
delete_path_lists_grouped("atmosphere/",
|
||||||
delete_path_list(clean_atmosphere_contents_dirs_to_delete, "atmosphere contents dirs");
|
clean_atmosphere_dirs_to_delete,
|
||||||
delete_path_list(clean_atmosphere_files_to_delete, "atmosphere files");
|
clean_atmosphere_contents_dirs_to_delete,
|
||||||
|
clean_atmosphere_files_to_delete,
|
||||||
|
NULL);
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("bootloader/",
|
||||||
gfx_printf(" Bereinige: bootloader/\n");
|
clean_bootloader_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
clean_bootloader_files_to_delete,
|
||||||
delete_path_list(clean_bootloader_dirs_to_delete, "bootloader dirs");
|
NULL);
|
||||||
delete_path_list(clean_bootloader_files_to_delete, "bootloader files");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("config/",
|
||||||
gfx_printf(" Bereinige: config/\n");
|
clean_config_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
NULL);
|
||||||
delete_path_list(clean_config_dirs_to_delete, "config dirs");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("switch/",
|
||||||
gfx_printf(" Bereinige: switch/\n");
|
clean_switch_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
clean_switch_files_to_delete,
|
||||||
delete_path_list(clean_switch_dirs_to_delete, "switch dirs");
|
NULL);
|
||||||
delete_path_list(clean_switch_files_to_delete, "switch files");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("Root-Dateien",
|
||||||
gfx_printf(" Bereinige: Root-Dateien\n");
|
clean_root_files_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
clean_misc_dirs_to_delete,
|
||||||
delete_path_list(clean_root_files_to_delete, "root files");
|
clean_misc_files_to_delete,
|
||||||
delete_path_list(clean_misc_dirs_to_delete, "misc dirs");
|
NULL);
|
||||||
delete_path_list(clean_misc_files_to_delete, "misc files");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("Alte Versionsmarker",
|
||||||
gfx_printf(" Bereinige: Alte Versionsmarker\n");
|
old_version_files_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
NULL);
|
||||||
delete_path_list(old_version_files_to_delete, "old version markers");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
set_color(COLOR_CYAN);
|
||||||
gfx_printf(" Erstelle: switch/\n");
|
gfx_printf(" Erstelle: switch/\n");
|
||||||
@@ -93,13 +95,14 @@ int clean_mode_wipe(void) {
|
|||||||
// Clean mode: Restore user data
|
// Clean mode: Restore user data
|
||||||
int clean_mode_restore(void) {
|
int clean_mode_restore(void) {
|
||||||
set_color(COLOR_CYAN);
|
set_color(COLOR_CYAN);
|
||||||
gfx_printf(" Stelle wieder her: DBI, Tinfoil, prod.keys\n");
|
gfx_printf(" Stelle wieder her: DBI (dbi.config), prod.keys\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
int res = restore_user_data();
|
int res = restore_user_data();
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK) {
|
||||||
set_color(COLOR_GREEN);
|
set_color(COLOR_GREEN);
|
||||||
gfx_printf(" [OK] Wiederherstellung abgeschlossen\n");
|
gfx_printf(" [OK] Wiederherstellung abgeschlossen\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
|
delete_path_list(clean_post_restore_dirs_to_delete, "switch/ (nach Restore)");
|
||||||
}
|
}
|
||||||
cleanup_backup();
|
cleanup_backup();
|
||||||
return res;
|
return res;
|
||||||
@@ -109,3 +112,55 @@ int clean_mode_restore(void) {
|
|||||||
int clean_mode_install(omninx_variant_t variant) {
|
int clean_mode_install(omninx_variant_t variant) {
|
||||||
return update_mode_install(variant);
|
return update_mode_install(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove other staging directories (OmniNX Standard/Light/OC) that exist on SD
|
||||||
|
int cleanup_other_staging_directories(omninx_variant_t installed_variant) {
|
||||||
|
static const omninx_variant_t all_variants[] = { VARIANT_STANDARD, VARIANT_LIGHT, VARIANT_OC };
|
||||||
|
const int n = sizeof(all_variants) / sizeof(all_variants[0]);
|
||||||
|
int last_res = FR_OK;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
omninx_variant_t v = all_variants[i];
|
||||||
|
if (v == installed_variant)
|
||||||
|
continue;
|
||||||
|
const char *staging = get_staging_path(v);
|
||||||
|
if (!staging || !path_exists(staging))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
check_and_clear_screen_if_needed();
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("\nEntferne weiteren Installationsordner...\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
int total = count_directory_items(staging);
|
||||||
|
u32 start_x, start_y;
|
||||||
|
gfx_con_getpos(&start_x, &start_y);
|
||||||
|
|
||||||
|
const char *folder_name = strrchr(staging, '/');
|
||||||
|
if (folder_name) folder_name++;
|
||||||
|
else folder_name = staging;
|
||||||
|
|
||||||
|
set_color(COLOR_CYAN);
|
||||||
|
gfx_printf(" Loesche: %s [ 0%%] (0/%d)", folder_name, total);
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
int deleted = 0;
|
||||||
|
int last_percent = -1;
|
||||||
|
int res = folder_delete_progress_recursive(staging, &deleted, total, start_x, start_y, folder_name, &last_percent);
|
||||||
|
|
||||||
|
gfx_con_setpos(start_x, start_y);
|
||||||
|
if (res == FR_OK) {
|
||||||
|
set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" Loesche: %s [100%%] (%d/%d) - Fertig!\n", folder_name, deleted, total);
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
} else {
|
||||||
|
set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf(" Loesche: %s - Fehlgeschlagen!\n", folder_name);
|
||||||
|
gfx_printf(" [WARN] Ordner konnte nicht entfernt werden (err=%d)\n", res);
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
}
|
||||||
|
last_res = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return last_res;
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,36 +39,32 @@ int update_mode_cleanup(omninx_variant_t variant) {
|
|||||||
(void)variant;
|
(void)variant;
|
||||||
check_and_clear_screen_if_needed();
|
check_and_clear_screen_if_needed();
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
|
||||||
gfx_printf(" Bereinige: atmosphere/\n");
|
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
delete_path_list(atmosphere_dirs_to_delete, "atmosphere subdirs");
|
delete_path_lists_grouped("atmosphere/",
|
||||||
delete_path_list(atmosphere_contents_dirs_to_delete, "atmosphere contents dirs");
|
atmosphere_dirs_to_delete,
|
||||||
delete_path_list(atmosphere_files_to_delete, "atmosphere files");
|
atmosphere_contents_dirs_to_delete,
|
||||||
|
atmosphere_files_to_delete,
|
||||||
|
NULL);
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("bootloader/",
|
||||||
gfx_printf(" Bereinige: bootloader/\n");
|
bootloader_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
bootloader_files_to_delete,
|
||||||
delete_path_list(bootloader_dirs_to_delete, "bootloader dirs");
|
NULL);
|
||||||
delete_path_list(bootloader_files_to_delete, "bootloader files");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("config/",
|
||||||
gfx_printf(" Bereinige: config/\n");
|
config_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
NULL);
|
||||||
delete_path_list(config_dirs_to_delete, "config dirs");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("switch/",
|
||||||
gfx_printf(" Bereinige: switch/\n");
|
switch_dirs_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
switch_files_to_delete,
|
||||||
delete_path_list(switch_dirs_to_delete, "switch dirs");
|
NULL);
|
||||||
delete_path_list(switch_files_to_delete, "switch files");
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
delete_path_lists_grouped("Root-Dateien",
|
||||||
gfx_printf(" Bereinige: Root-Dateien\n");
|
root_files_to_delete,
|
||||||
set_color(COLOR_WHITE);
|
misc_dirs_to_delete,
|
||||||
delete_path_list(root_files_to_delete, "root files");
|
misc_files_to_delete,
|
||||||
delete_path_list(misc_dirs_to_delete, "misc dirs");
|
NULL);
|
||||||
delete_path_list(misc_files_to_delete, "misc files");
|
|
||||||
|
|
||||||
set_color(COLOR_GREEN);
|
set_color(COLOR_GREEN);
|
||||||
gfx_printf(" Bereinigung abgeschlossen!\n");
|
gfx_printf(" Bereinigung abgeschlossen!\n");
|
||||||
@@ -82,7 +78,6 @@ int update_mode_install(omninx_variant_t variant) {
|
|||||||
int res;
|
int res;
|
||||||
const char* staging = get_staging_path(variant);
|
const char* staging = get_staging_path(variant);
|
||||||
char src_path[256];
|
char src_path[256];
|
||||||
char dst_path[256];
|
|
||||||
|
|
||||||
if (!staging) {
|
if (!staging) {
|
||||||
return FR_INVALID_PARAMETER;
|
return FR_INVALID_PARAMETER;
|
||||||
@@ -110,6 +105,10 @@ int update_mode_install(omninx_variant_t variant) {
|
|||||||
res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/");
|
res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/");
|
||||||
if (res != FR_OK && res != FR_NO_FILE) return res;
|
if (res != FR_OK && res != FR_NO_FILE) return res;
|
||||||
|
|
||||||
|
s_printf(src_path, "%s/themes", staging);
|
||||||
|
res = folder_copy_with_progress_v2(src_path, "sd:/", "themes/");
|
||||||
|
if (res != FR_OK && res != FR_NO_FILE) return res;
|
||||||
|
|
||||||
s_printf(src_path, "%s/warmboot_mariko", staging);
|
s_printf(src_path, "%s/warmboot_mariko", staging);
|
||||||
res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/");
|
res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/");
|
||||||
if (res != FR_OK && res != FR_NO_FILE) return res;
|
if (res != FR_OK && res != FR_NO_FILE) return res;
|
||||||
@@ -124,63 +123,9 @@ int update_mode_install(omninx_variant_t variant) {
|
|||||||
gfx_printf(" Kopiere Root-Dateien...\n");
|
gfx_printf(" Kopiere Root-Dateien...\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
s_printf(src_path, "%s/boot.dat", staging);
|
res = install_copy_staging_root_files(staging, "sd:/");
|
||||||
s_printf(dst_path, "sd:/boot.dat");
|
if (res != FR_OK)
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
return res;
|
||||||
|
|
||||||
s_printf(src_path, "%s/boot.ini", staging);
|
|
||||||
s_printf(dst_path, "sd:/boot.ini");
|
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
|
||||||
|
|
||||||
s_printf(src_path, "%s/exosphere.ini", staging);
|
|
||||||
s_printf(dst_path, "sd:/exosphere.ini");
|
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
|
||||||
|
|
||||||
s_printf(src_path, "%s/hbmenu.nro", staging);
|
|
||||||
s_printf(dst_path, "sd:/hbmenu.nro");
|
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
|
||||||
|
|
||||||
s_printf(src_path, "%s/loader.bin", staging);
|
|
||||||
s_printf(dst_path, "sd:/loader.bin");
|
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
|
||||||
|
|
||||||
s_printf(src_path, "%s/payload.bin", staging);
|
|
||||||
s_printf(dst_path, "sd:/payload.bin");
|
|
||||||
if (path_exists(src_path)) file_copy(src_path, dst_path);
|
|
||||||
|
|
||||||
set_color(COLOR_CYAN);
|
|
||||||
gfx_printf(" Erstelle manifest.ini...\n");
|
|
||||||
set_color(COLOR_WHITE);
|
|
||||||
|
|
||||||
s_printf(dst_path, "sd:/config/omninx");
|
|
||||||
f_mkdir(dst_path);
|
|
||||||
|
|
||||||
const char* pack_name;
|
|
||||||
int update_channel;
|
|
||||||
switch (variant) {
|
|
||||||
case VARIANT_STANDARD: pack_name = "standard"; update_channel = 2; break;
|
|
||||||
case VARIANT_LIGHT: pack_name = "light"; update_channel = 0; break;
|
|
||||||
case VARIANT_OC: pack_name = "oc"; update_channel = 1; break;
|
|
||||||
default: pack_name = "unknown"; update_channel = 0; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_printf(dst_path, "sd:/config/omninx/manifest.ini");
|
|
||||||
FIL fp;
|
|
||||||
if (f_open(&fp, dst_path, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) {
|
|
||||||
f_printf(&fp, "[OmniNX]\n");
|
|
||||||
f_printf(&fp, "current_pack=%s\n", pack_name);
|
|
||||||
f_printf(&fp, "version=%s\n", VERSION);
|
|
||||||
f_printf(&fp, "update_channel=%d\n", update_channel);
|
|
||||||
f_printf(&fp, "channel_pack=%s\n", pack_name);
|
|
||||||
f_close(&fp);
|
|
||||||
set_color(COLOR_GREEN);
|
|
||||||
gfx_printf(" [OK] manifest.ini erstellt\n");
|
|
||||||
set_color(COLOR_WHITE);
|
|
||||||
} else {
|
|
||||||
set_color(COLOR_ORANGE);
|
|
||||||
gfx_printf(" [WARN] manifest.ini konnte nicht erstellt werden\n");
|
|
||||||
set_color(COLOR_WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_color(COLOR_GREEN);
|
set_color(COLOR_GREEN);
|
||||||
gfx_printf(" Kopie abgeschlossen!\n");
|
gfx_printf(" Kopie abgeschlossen!\n");
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* HATS Installer - Simplified disk I/O (SD card only)
|
* OmniNX Installer - Simplified disk I/O (SD card only)
|
||||||
* Based on TegraExplorer diskio.c by shchmue
|
* Based on HATS Installer, TegraExplorer diskio.c by shchmue
|
||||||
*
|
*
|
||||||
* This simplified version removes BIS/eMMC support since the
|
* This simplified version removes BIS/eMMC support since the
|
||||||
* HATS installer only needs SD card access.
|
* OmniNX installer only needs SD card access.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|||||||
352
source/main.c
352
source/main.c
@@ -2,8 +2,8 @@
|
|||||||
* OmniNX Installer Payload
|
* OmniNX Installer Payload
|
||||||
* Minimal payload to install OmniNX CFW Pack files outside of Horizon OS
|
* Minimal payload to install OmniNX CFW Pack files outside of Horizon OS
|
||||||
*
|
*
|
||||||
|
* Based on HATS Installer by sthetix
|
||||||
* Based on TegraExplorer/hekate by CTCaer, naehrwert, shchmue
|
* Based on TegraExplorer/hekate by CTCaer, naehrwert, shchmue
|
||||||
* Based on HATS-Installer-Payload by sthetix
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
#include <mem/heap.h>
|
#include <mem/heap.h>
|
||||||
#include <mem/minerva.h>
|
#include <mem/minerva.h>
|
||||||
#include <power/max77620.h>
|
#include <power/max77620.h>
|
||||||
|
#include <power/max17050.h>
|
||||||
|
#include <power/bq24193.h>
|
||||||
#include <soc/bpmp.h>
|
#include <soc/bpmp.h>
|
||||||
#include <soc/fuse.h>
|
#include <soc/fuse.h>
|
||||||
#include <soc/hw_init.h>
|
#include <soc/hw_init.h>
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
|
#include "screenshot.h"
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
#define PAYLOAD_PATH "sd:/bootloader/update.bin"
|
#define PAYLOAD_PATH "sd:/bootloader/update.bin"
|
||||||
@@ -74,7 +77,9 @@ volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
|||||||
static void *coreboot_addr;
|
static void *coreboot_addr;
|
||||||
static int total_errors = 0;
|
static int total_errors = 0;
|
||||||
|
|
||||||
// Use BDK colors (already defined in types.h)
|
// Use BDK colors (CYAN/WHITE overridden for consistency; GREEN/YELLOW from types.h)
|
||||||
|
#undef COLOR_CYAN
|
||||||
|
#undef COLOR_WHITE
|
||||||
#define COLOR_CYAN 0xFF00FFFF
|
#define COLOR_CYAN 0xFF00FFFF
|
||||||
#define COLOR_WHITE 0xFFFFFFFF
|
#define COLOR_WHITE 0xFFFFFFFF
|
||||||
|
|
||||||
@@ -111,6 +116,12 @@ static void print_header(void) {
|
|||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Console Vol+ and Vol- together (exit / cancel where documented) */
|
||||||
|
static inline bool cancel_combo_pressed(u8 btn)
|
||||||
|
{
|
||||||
|
return (btn & (BTN_VOL_UP | BTN_VOL_DOWN)) == (BTN_VOL_UP | BTN_VOL_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) {
|
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) {
|
||||||
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
|
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
|
||||||
@@ -178,6 +189,12 @@ static int file_exists(const char *path) {
|
|||||||
return (f_stat(path, &fno) == FR_OK);
|
return (f_stat(path, &fno) == FR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void installer_launch_hekate_payload(void) {
|
||||||
|
if (file_exists(PAYLOAD_PATH))
|
||||||
|
launch_payload(PAYLOAD_PATH);
|
||||||
|
power_set_state(POWER_OFF_REBOOT);
|
||||||
|
}
|
||||||
|
|
||||||
extern void pivot_stack(u32 stack_top);
|
extern void pivot_stack(u32 stack_top);
|
||||||
|
|
||||||
void ipl_main(void) {
|
void ipl_main(void) {
|
||||||
@@ -215,10 +232,11 @@ void ipl_main(void) {
|
|||||||
// Detect current OmniNX installation
|
// Detect current OmniNX installation
|
||||||
omninx_status_t current = detect_omninx_installation();
|
omninx_status_t current = detect_omninx_installation();
|
||||||
|
|
||||||
// Detect which pack variant is on SD card
|
// Detect which pack variant(s) are on SD card
|
||||||
omninx_variant_t pack_variant = detect_pack_variant();
|
omninx_variant_t variants_present[3];
|
||||||
|
int num_variants = detect_present_variants(variants_present, 3);
|
||||||
|
|
||||||
if (pack_variant == VARIANT_NONE) {
|
if (num_variants == 0) {
|
||||||
set_color(COLOR_RED);
|
set_color(COLOR_RED);
|
||||||
gfx_printf("FEHLER: Kein OmniNX-Paket auf der SD-Karte gefunden!\n");
|
gfx_printf("FEHLER: Kein OmniNX-Paket auf der SD-Karte gefunden!\n");
|
||||||
gfx_printf("Erwartet wird eines der folgenden:\n");
|
gfx_printf("Erwartet wird eines der folgenden:\n");
|
||||||
@@ -238,11 +256,13 @@ void ipl_main(void) {
|
|||||||
set_color(COLOR_GREEN);
|
set_color(COLOR_GREEN);
|
||||||
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
||||||
gfx_printf("um Hekate zu starten...\n");
|
gfx_printf("um Hekate zu starten...\n");
|
||||||
|
gfx_printf("Oder Vol+ und Vol- (Konsole) gleichzeitig.\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
} else {
|
} else {
|
||||||
set_color(COLOR_GREEN);
|
set_color(COLOR_GREEN);
|
||||||
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
||||||
gfx_printf("um den Neustart zu starten...\n");
|
gfx_printf("um den Neustart zu starten...\n");
|
||||||
|
gfx_printf("Oder Vol+ und Vol- (Konsole) gleichzeitig.\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,9 +279,17 @@ void ipl_main(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check joycon A button
|
// Check joycon A button; Capture = screenshot
|
||||||
jc_gamepad_rpt_t *jc = joycon_poll();
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
if (jc && jc->a) {
|
if (jc) {
|
||||||
|
if (jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
if (jc->a) {
|
||||||
|
button_pressed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancel_combo_pressed(btn_state)) {
|
||||||
button_pressed = true;
|
button_pressed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -283,9 +311,253 @@ void ipl_main(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If multiple variants present, show selection menu; otherwise use the single one
|
||||||
|
omninx_variant_t pack_variant;
|
||||||
|
if (num_variants == 1) {
|
||||||
|
pack_variant = variants_present[0];
|
||||||
|
} else {
|
||||||
|
// Initialize joycons for menu input
|
||||||
|
jc_init_hw();
|
||||||
|
while (btn_read() & BTN_POWER) { msleep(50); }
|
||||||
|
|
||||||
|
// Selection menu (TegraExplorer-style: draw once, then only redraw changed lines)
|
||||||
|
int selected = 0;
|
||||||
|
int prev_selected = 0;
|
||||||
|
bool confirmed = false;
|
||||||
|
|
||||||
|
// Draw menu once and remember start position of variant lines
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
print_header();
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Mehrere OmniNX-Pakete gefunden.\n");
|
||||||
|
gfx_printf("Waehle die zu installierende Variante:\n\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
u32 menu_x, menu_variant_start_y;
|
||||||
|
gfx_con_getpos(&menu_x, &menu_variant_start_y);
|
||||||
|
for (int i = 0; i < num_variants; i++) {
|
||||||
|
if (i == selected) {
|
||||||
|
set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" > %s\n", get_variant_name(variants_present[i]));
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
} else {
|
||||||
|
gfx_printf(" %s\n", get_variant_name(variants_present[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gfx_printf("\n");
|
||||||
|
set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n");
|
||||||
|
gfx_printf("Vol+ und Vol- gleichzeitig: Abbrechen (Hekate)\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
|
// Edge detection: only move on press (not while held)
|
||||||
|
bool prev_up = false, prev_down = false;
|
||||||
|
bool menu_aborted = false;
|
||||||
|
|
||||||
|
while (!confirmed && !menu_aborted) {
|
||||||
|
// On selection change: redraw only the two affected lines (no full clear)
|
||||||
|
if (selected != prev_selected) {
|
||||||
|
gfx_con_setpos(menu_x, menu_variant_start_y + (u32)prev_selected * 16);
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
gfx_printf(" %s\n", get_variant_name(variants_present[prev_selected]));
|
||||||
|
gfx_con_setpos(menu_x, menu_variant_start_y + (u32)selected * 16);
|
||||||
|
set_color(COLOR_GREEN);
|
||||||
|
gfx_printf(" > %s\n", get_variant_name(variants_present[selected]));
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
prev_selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
|
u8 btn = btn_read();
|
||||||
|
|
||||||
|
if (jc && jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
|
||||||
|
if (cancel_combo_pressed(btn)) {
|
||||||
|
menu_aborted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// D-pad or Vol+ / Vol- for selection (Vol+ = up, Vol- = down)
|
||||||
|
bool cur_up = false, cur_down = false;
|
||||||
|
if (jc) {
|
||||||
|
cur_up = (jc->up != 0) && !jc->down;
|
||||||
|
cur_down = (jc->down != 0) && !jc->up;
|
||||||
|
}
|
||||||
|
if (btn & BTN_VOL_UP) cur_up = true;
|
||||||
|
if (btn & BTN_VOL_DOWN) cur_down = true;
|
||||||
|
|
||||||
|
if (cur_up && !prev_up)
|
||||||
|
selected = (selected - 1 + num_variants) % num_variants;
|
||||||
|
else if (cur_down && !prev_down)
|
||||||
|
selected = (selected + 1) % num_variants;
|
||||||
|
else if (jc && jc->a)
|
||||||
|
confirmed = true;
|
||||||
|
prev_up = cur_up;
|
||||||
|
prev_down = cur_down;
|
||||||
|
|
||||||
|
if (btn & BTN_POWER) {
|
||||||
|
confirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
msleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu_aborted) {
|
||||||
|
gfx_printf("\n");
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Abgebrochen. Starte Hekate...\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
msleep(500);
|
||||||
|
if (file_exists(PAYLOAD_PATH)) {
|
||||||
|
launch_payload(PAYLOAD_PATH);
|
||||||
|
} else {
|
||||||
|
power_set_state(POWER_OFF_REBOOT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_variant = variants_present[selected];
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
print_header();
|
||||||
|
}
|
||||||
|
|
||||||
// Determine installation mode
|
// Determine installation mode
|
||||||
install_mode_t mode = current.is_installed ? INSTALL_MODE_UPDATE : INSTALL_MODE_CLEAN;
|
install_mode_t mode = current.is_installed ? INSTALL_MODE_UPDATE : INSTALL_MODE_CLEAN;
|
||||||
|
|
||||||
|
// Battery run protection: below 10% requires charger
|
||||||
|
#define BATT_LOW_THRESHOLD 10
|
||||||
|
int batt_raw = 0;
|
||||||
|
int batt_pct = 100;
|
||||||
|
if (max17050_get_property(MAX17050_RepSOC, &batt_raw) == 0) {
|
||||||
|
batt_pct = batt_raw >> 8; // RepSOC: high byte = percent
|
||||||
|
}
|
||||||
|
while (batt_pct < BATT_LOW_THRESHOLD && !bq24193_charger_connected()) {
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
print_header();
|
||||||
|
set_color(COLOR_RED);
|
||||||
|
gfx_printf("Akkustand zu niedrig! (%d%%)\n\n", batt_pct);
|
||||||
|
gfx_printf("Unter %d%% Akku darf die Installation nur\n", BATT_LOW_THRESHOLD);
|
||||||
|
gfx_printf("mit angeschlossenem Ladegeraet durchgefuehrt werden.\n\n");
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Stecke das Ladegeraet an und warte...\n");
|
||||||
|
gfx_printf("Oder Vol+ und Vol- (Konsole) zum Abbrechen.\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
jc_init_hw();
|
||||||
|
while (btn_read() & BTN_POWER) { msleep(50); }
|
||||||
|
bool user_cancelled = false;
|
||||||
|
while (batt_pct < BATT_LOW_THRESHOLD && !bq24193_charger_connected() && !user_cancelled) {
|
||||||
|
u8 pbtn = btn_read();
|
||||||
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
|
if (jc) {
|
||||||
|
if (jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
}
|
||||||
|
if (cancel_combo_pressed(pbtn)) {
|
||||||
|
user_cancelled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (max17050_get_property(MAX17050_RepSOC, &batt_raw) == 0) {
|
||||||
|
batt_pct = batt_raw >> 8;
|
||||||
|
}
|
||||||
|
msleep(200);
|
||||||
|
}
|
||||||
|
if (user_cancelled) {
|
||||||
|
gfx_printf("\nAbgebrochen. Starte Hekate...\n");
|
||||||
|
msleep(500);
|
||||||
|
if (file_exists(PAYLOAD_PATH)) {
|
||||||
|
launch_payload(PAYLOAD_PATH);
|
||||||
|
} else {
|
||||||
|
power_set_state(POWER_OFF_REBOOT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charger detected or battery OK - clear the low-battery screen before continuing
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
print_header();
|
||||||
|
|
||||||
|
// UHS class check: recommend U2 / V30 / A2 for emuMMC (speed and reliability)
|
||||||
|
#define UHS_U2_MIN 2
|
||||||
|
#define UHS_V30_MIN 30
|
||||||
|
#define UHS_A2_MIN 2
|
||||||
|
bool uhs_ok = (sd_storage.ssr.uhs_grade >= UHS_U2_MIN &&
|
||||||
|
sd_storage.ssr.video_class >= UHS_V30_MIN &&
|
||||||
|
sd_storage.ssr.app_class >= UHS_A2_MIN);
|
||||||
|
if (!uhs_ok) {
|
||||||
|
jc_init_hw();
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
set_color(COLOR_RED);
|
||||||
|
gfx_printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
|
||||||
|
gfx_printf("!! WARNUNG - SD-KARTEN-KLASSE !!\n");
|
||||||
|
gfx_printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
gfx_printf("Diese SD-Karte erfuellt NICHT die empfohlenen\n");
|
||||||
|
gfx_printf("Mindestanforderungen (U2 | V30 | A2).\n\n");
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Aktuelle Werte: UHS%d | V%d | A%d\n\n",
|
||||||
|
(u32)sd_storage.ssr.uhs_grade,
|
||||||
|
(u32)sd_storage.ssr.video_class,
|
||||||
|
(u32)sd_storage.ssr.app_class);
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
gfx_printf("Moegliche Folgen bei schwachen Karten:\n");
|
||||||
|
gfx_printf(" - Langsamere emuMMC / Spiel-Ladezeiten\n");
|
||||||
|
gfx_printf(" - Hoheres Risiko von Korruption oder Abstuerzen\n");
|
||||||
|
gfx_printf(" - Instabilitaet beim Schreiben groesserer Daten\n\n");
|
||||||
|
set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("Empfohlen: U2 | V30 | A2 oder besser.\n");
|
||||||
|
gfx_printf("Empfohlene Karten: Samsung EVO Plus, EVO Select und PRO Plus.\n\n");
|
||||||
|
set_color(COLOR_GREEN);
|
||||||
|
gfx_printf("Druecke A (oder Power), um trotzdem fortzufahren.\n");
|
||||||
|
set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("Vol+ und Vol- (Konsole) gleichzeitig: Abbrechen -> Hekate.\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
while (btn_read() & BTN_POWER) { msleep(50); }
|
||||||
|
bool acknowledged = false;
|
||||||
|
bool uhs_aborted = false;
|
||||||
|
while (!acknowledged && !uhs_aborted) {
|
||||||
|
u8 btn_state = btn_read();
|
||||||
|
if (btn_state & BTN_POWER) acknowledged = true;
|
||||||
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
|
if (jc) {
|
||||||
|
if (jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
if (jc->a) acknowledged = true;
|
||||||
|
}
|
||||||
|
if (cancel_combo_pressed(btn_state)) {
|
||||||
|
uhs_aborted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
msleep(50);
|
||||||
|
}
|
||||||
|
if (uhs_aborted) {
|
||||||
|
gfx_printf("\nAbgebrochen. Starte Hekate...\n");
|
||||||
|
msleep(500);
|
||||||
|
if (file_exists(PAYLOAD_PATH)) {
|
||||||
|
launch_payload(PAYLOAD_PATH);
|
||||||
|
} else {
|
||||||
|
power_set_state(POWER_OFF_REBOOT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Wait for A and Power to be released so the same press doesn't start the install
|
||||||
|
while (btn_read() & BTN_POWER) { msleep(50); }
|
||||||
|
bool released = false;
|
||||||
|
while (!released) {
|
||||||
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
|
released = (!jc || !jc->a) && !(btn_read() & BTN_POWER);
|
||||||
|
if (!released) msleep(50);
|
||||||
|
}
|
||||||
|
msleep(300); // Short delay so the next screen is visible before accepting input
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
print_header();
|
||||||
|
}
|
||||||
|
|
||||||
// Show information
|
// Show information
|
||||||
set_color(COLOR_CYAN);
|
set_color(COLOR_CYAN);
|
||||||
gfx_printf("Installationsmodus: %s\n", mode == INSTALL_MODE_UPDATE ? "Update" : "Saubere Installation");
|
gfx_printf("Installationsmodus: %s\n", mode == INSTALL_MODE_UPDATE ? "Update" : "Saubere Installation");
|
||||||
@@ -310,33 +582,59 @@ void ipl_main(void) {
|
|||||||
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
gfx_printf("Druecke A-Taste (rechter Joy-Con) oder Power-Taste,\n");
|
||||||
gfx_printf("um die Installation zu starten...\n");
|
gfx_printf("um die Installation zu starten...\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
|
set_color(COLOR_CYAN);
|
||||||
|
gfx_printf("Vol+ und Vol- (Konsole) gleichzeitig: Abbrechen -> Hekate.\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
// Wait for either A button or Power button
|
// Wait for A/Power to start, or +/- to cancel
|
||||||
bool button_pressed = false;
|
bool button_pressed = false;
|
||||||
|
bool cancelled = false;
|
||||||
|
|
||||||
// First, wait for power button to be released if it's currently pressed
|
// First, wait for power button to be released if it's currently pressed
|
||||||
while (btn_read() & BTN_POWER) {
|
while (btn_read() & BTN_POWER) {
|
||||||
msleep(50);
|
msleep(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!button_pressed) {
|
while (!button_pressed && !cancelled) {
|
||||||
// Check power button - detect press (transition from not pressed to pressed)
|
// Check power button
|
||||||
u8 btn_state = btn_read();
|
u8 btn_state = btn_read();
|
||||||
if (btn_state & BTN_POWER) {
|
if (btn_state & BTN_POWER) {
|
||||||
button_pressed = true;
|
button_pressed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check joycon A button
|
// Check joycon buttons; Capture = screenshot
|
||||||
jc_gamepad_rpt_t *jc = joycon_poll();
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
if (jc && jc->a) {
|
if (jc) {
|
||||||
button_pressed = true;
|
if (jc->cap)
|
||||||
|
take_screenshot();
|
||||||
|
if (jc->a) {
|
||||||
|
button_pressed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancel_combo_pressed(btn_state)) {
|
||||||
|
cancelled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
msleep(50); // Small delay to avoid busy-waiting
|
msleep(50); // Small delay to avoid busy-waiting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cancelled) {
|
||||||
|
gfx_printf("\n");
|
||||||
|
set_color(COLOR_YELLOW);
|
||||||
|
gfx_printf("Abgebrochen. Starte Hekate...\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
msleep(500);
|
||||||
|
if (file_exists(PAYLOAD_PATH)) {
|
||||||
|
launch_payload(PAYLOAD_PATH);
|
||||||
|
} else {
|
||||||
|
power_set_state(POWER_OFF_REBOOT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear the prompt and start installation
|
// Clear the prompt and start installation
|
||||||
gfx_clear_grey(0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
@@ -344,13 +642,17 @@ void ipl_main(void) {
|
|||||||
|
|
||||||
// Perform the installation
|
// Perform the installation
|
||||||
set_color(COLOR_YELLOW);
|
set_color(COLOR_YELLOW);
|
||||||
gfx_printf("Installation wird gestartet...\n\n");
|
gfx_printf("Installation wird gestartet...\n");
|
||||||
|
set_color(COLOR_WHITE);
|
||||||
|
set_color(COLOR_ORANGE);
|
||||||
|
gfx_printf("Hinweis: Manchmal kann es haengen. Einfach warten.\n\n");
|
||||||
set_color(COLOR_WHITE);
|
set_color(COLOR_WHITE);
|
||||||
|
|
||||||
int result = perform_installation(pack_variant, mode);
|
int result = perform_installation(pack_variant, mode);
|
||||||
|
|
||||||
// Wait 3 seconds before clearing screen to allow errors to be visible
|
// Wait 3 seconds before clearing screen to allow errors to be visible
|
||||||
msleep(3000);
|
msleep(3000);
|
||||||
|
// take_screenshot(); // Take a screenshot of the installation summary
|
||||||
|
|
||||||
// Clear screen for final summary to ensure it's visible
|
// Clear screen for final summary to ensure it's visible
|
||||||
gfx_clear_grey(0x1B);
|
gfx_clear_grey(0x1B);
|
||||||
@@ -403,11 +705,15 @@ void ipl_main(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check joycon A button
|
// Check joycon A button; Capture = screenshot
|
||||||
jc_gamepad_rpt_t *jc = joycon_poll();
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
if (jc && jc->a) {
|
if (jc) {
|
||||||
button_pressed = true;
|
if (jc->cap)
|
||||||
break;
|
take_screenshot();
|
||||||
|
if (jc->a) {
|
||||||
|
button_pressed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msleep(50); // Small delay to avoid busy-waiting
|
msleep(50); // Small delay to avoid busy-waiting
|
||||||
@@ -445,9 +751,13 @@ void ipl_main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jc_gamepad_rpt_t *jc = joycon_poll();
|
jc_gamepad_rpt_t *jc = joycon_poll();
|
||||||
if (jc && jc->a) {
|
if (jc) {
|
||||||
button_pressed = true;
|
if (jc->cap)
|
||||||
break;
|
take_screenshot();
|
||||||
|
if (jc->a) {
|
||||||
|
button_pressed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msleep(50);
|
msleep(50);
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ static void _sd_deinit()
|
|||||||
void sd_unmount() { _sd_deinit(); }
|
void sd_unmount() { _sd_deinit(); }
|
||||||
void sd_end() { _sd_deinit(); }
|
void sd_end() { _sd_deinit(); }
|
||||||
|
|
||||||
|
bool sd_get_card_mounted(void)
|
||||||
|
{
|
||||||
|
return sd_mounted;
|
||||||
|
}
|
||||||
|
|
||||||
void *sd_file_read(const char *path, u32 *fsize)
|
void *sd_file_read(const char *path, u32 *fsize)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
|||||||
111
source/screenshot.c
Normal file
111
source/screenshot.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Screenshot support for OmniNX Installer Payload
|
||||||
|
* Based on TegraExplorer (AllgemeinerProblemLoeser) TakeScreenshot implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "screenshot.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
#include "nx_sd.h"
|
||||||
|
#include <libs/fatfs/ff.h>
|
||||||
|
#include <mem/heap.h>
|
||||||
|
#include <display/di.h>
|
||||||
|
#include <utils/util.h>
|
||||||
|
#include <utils/sprintf.h>
|
||||||
|
#include <rtc/max77620-rtc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* BMP file header (54 bytes), matching TegraExplorer tools.h */
|
||||||
|
typedef struct __attribute__((packed)) _bmp_hdr_t
|
||||||
|
{
|
||||||
|
u16 magic;
|
||||||
|
u32 size;
|
||||||
|
u32 rsvd;
|
||||||
|
u32 data_off;
|
||||||
|
u32 hdr_size;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
u16 planes;
|
||||||
|
u16 pxl_bits;
|
||||||
|
u32 comp;
|
||||||
|
u32 img_size;
|
||||||
|
u32 res_h;
|
||||||
|
u32 res_v;
|
||||||
|
u64 rsvd2;
|
||||||
|
} bmp_hdr_t;
|
||||||
|
|
||||||
|
#define BMP_HEADER_SIZE 0x36
|
||||||
|
#define FB_SIZE 0x384000 /* 1280 * 720 * 4 */
|
||||||
|
#define SCREEN_W 1280
|
||||||
|
#define SCREEN_H 720
|
||||||
|
|
||||||
|
void take_screenshot(void)
|
||||||
|
{
|
||||||
|
static u32 last_timer = 0;
|
||||||
|
|
||||||
|
if (!sd_get_card_mounted())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* 3-second cooldown (same as TegraExplorer) */
|
||||||
|
u32 now = get_tmr_s();
|
||||||
|
if (last_timer != 0 && now < last_timer + 3)
|
||||||
|
return;
|
||||||
|
last_timer = now;
|
||||||
|
|
||||||
|
const char basepath[] = "sd:/switch/screenshot";
|
||||||
|
char name[48];
|
||||||
|
char path[80];
|
||||||
|
rtc_time_t rtc;
|
||||||
|
|
||||||
|
max77620_rtc_get_time(&rtc);
|
||||||
|
s_printf(name, "omninx_installer_%04d%02d%02d_%02d%02d%02d.bmp",
|
||||||
|
(u32)rtc.year, (u32)rtc.month, (u32)rtc.day,
|
||||||
|
(u32)rtc.hour, (u32)rtc.min, (u32)rtc.sec);
|
||||||
|
s_printf(path, "%s/%s", basepath, name);
|
||||||
|
|
||||||
|
f_mkdir("sd:/switch");
|
||||||
|
f_mkdir(basepath);
|
||||||
|
|
||||||
|
const u32 file_size = BMP_HEADER_SIZE + FB_SIZE;
|
||||||
|
u8 *bitmap = (u8 *)malloc(file_size);
|
||||||
|
u32 *fb_copy = (u32 *)malloc(FB_SIZE);
|
||||||
|
if (!bitmap || !fb_copy) {
|
||||||
|
if (bitmap) free(bitmap);
|
||||||
|
if (fb_copy) free(fb_copy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy framebuffer with same coordinate flip as TegraExplorer (BGR layout) */
|
||||||
|
u32 *fb_ptr = gfx_ctxt.fb;
|
||||||
|
for (int x = SCREEN_W - 1; x >= 0; x--) {
|
||||||
|
for (int y = SCREEN_H - 1; y >= 0; y--)
|
||||||
|
fb_copy[y * SCREEN_W + x] = *fb_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(bitmap + BMP_HEADER_SIZE, fb_copy, FB_SIZE);
|
||||||
|
|
||||||
|
bmp_hdr_t *bmp = (bmp_hdr_t *)bitmap;
|
||||||
|
bmp->magic = 0x4D42;
|
||||||
|
bmp->size = file_size;
|
||||||
|
bmp->rsvd = 0;
|
||||||
|
bmp->data_off = BMP_HEADER_SIZE;
|
||||||
|
bmp->hdr_size = 40;
|
||||||
|
bmp->width = SCREEN_W;
|
||||||
|
bmp->height = SCREEN_H;
|
||||||
|
bmp->planes = 1;
|
||||||
|
bmp->pxl_bits = 32;
|
||||||
|
bmp->comp = 0;
|
||||||
|
bmp->img_size = FB_SIZE;
|
||||||
|
bmp->res_h = 2834;
|
||||||
|
bmp->res_v = 2834;
|
||||||
|
bmp->rsvd2 = 0;
|
||||||
|
|
||||||
|
sd_save_to_file(bitmap, file_size, path);
|
||||||
|
|
||||||
|
free(bitmap);
|
||||||
|
free(fb_copy);
|
||||||
|
|
||||||
|
/* Brief backlight flash (same as TegraExplorer) */
|
||||||
|
display_backlight_brightness(255, 1000);
|
||||||
|
msleep(100);
|
||||||
|
display_backlight_brightness(100, 1000);
|
||||||
|
}
|
||||||
13
source/screenshot.h
Normal file
13
source/screenshot.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Screenshot support for OmniNX Installer Payload
|
||||||
|
* Based on TegraExplorer (AllgemeinerProblemLoeser) TakeScreenshot implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/types.h>
|
||||||
|
|
||||||
|
/* Take a screenshot of the current framebuffer and save as BMP to SD.
|
||||||
|
* Triggered by Capture button (jc->cap). Uses 3-second cooldown.
|
||||||
|
* Saves to sd:/switch/screenshot/omninx_installer_YYYYMMDD_HHMMSS.bmp */
|
||||||
|
void take_screenshot(void);
|
||||||
@@ -50,11 +50,11 @@ static omninx_variant_t read_manifest_variant(const char *manifest_path) {
|
|||||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
|
||||||
if (kv->key && !strcmp(kv->key, "current_pack")) {
|
if (kv->key && !strcmp(kv->key, "current_pack")) {
|
||||||
if (kv->val) {
|
if (kv->val) {
|
||||||
if (!strcmp(kv->val, "standard")) {
|
if (!strcmp(kv->val, "Standard")) {
|
||||||
variant = VARIANT_STANDARD;
|
variant = VARIANT_STANDARD;
|
||||||
} else if (!strcmp(kv->val, "light")) {
|
} else if (!strcmp(kv->val, "Light")) {
|
||||||
variant = VARIANT_LIGHT;
|
variant = VARIANT_LIGHT;
|
||||||
} else if (!strcmp(kv->val, "oc")) {
|
} else if (!strcmp(kv->val, "OC")) {
|
||||||
variant = VARIANT_OC;
|
variant = VARIANT_OC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,6 +156,20 @@ omninx_variant_t detect_pack_variant(void) {
|
|||||||
return VARIANT_NONE;
|
return VARIANT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detect all pack variants present on SD card; returns count, fills out_variants[]
|
||||||
|
int detect_present_variants(omninx_variant_t *out_variants, int max_count) {
|
||||||
|
int count = 0;
|
||||||
|
if (max_count <= 0 || !out_variants)
|
||||||
|
return 0;
|
||||||
|
if (file_exists(STAGING_STANDARD) && count < max_count)
|
||||||
|
out_variants[count++] = VARIANT_STANDARD;
|
||||||
|
if (file_exists(STAGING_LIGHT) && count < max_count)
|
||||||
|
out_variants[count++] = VARIANT_LIGHT;
|
||||||
|
if (file_exists(STAGING_OC) && count < max_count)
|
||||||
|
out_variants[count++] = VARIANT_OC;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// Get human-readable variant name
|
// Get human-readable variant name
|
||||||
const char* get_variant_name(omninx_variant_t variant) {
|
const char* get_variant_name(omninx_variant_t variant) {
|
||||||
switch (variant) {
|
switch (variant) {
|
||||||
|
|||||||
@@ -23,9 +23,12 @@ typedef struct {
|
|||||||
// Detect current OmniNX installation status
|
// Detect current OmniNX installation status
|
||||||
omninx_status_t detect_omninx_installation(void);
|
omninx_status_t detect_omninx_installation(void);
|
||||||
|
|
||||||
// Detect which pack variant is present on SD card
|
// Detect which pack variant is present on SD card (first found in fixed order)
|
||||||
omninx_variant_t detect_pack_variant(void);
|
omninx_variant_t detect_pack_variant(void);
|
||||||
|
|
||||||
|
// Detect all pack variants present on SD card; returns count, fills out_variants[] (max max_count)
|
||||||
|
int detect_present_variants(omninx_variant_t *out_variants, int max_count);
|
||||||
|
|
||||||
// Get human-readable variant name
|
// Get human-readable variant name
|
||||||
const char* get_variant_name(omninx_variant_t variant);
|
const char* get_variant_name(omninx_variant_t variant);
|
||||||
|
|
||||||
|
|||||||
70
tools/ram_test_main.c
Normal file
70
tools/ram_test_main.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Minimal RAM info test payload (fuse DRAM ID + SK table -> MiB).
|
||||||
|
* Build: make ram-test -> output/RAM-Test.bin
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <display/di.h>
|
||||||
|
#include <mem/heap.h>
|
||||||
|
#include <mem/minerva.h>
|
||||||
|
#include <memory_map.h>
|
||||||
|
#include <soc/bpmp.h>
|
||||||
|
#include <soc/fuse.h>
|
||||||
|
#include <soc/hw_init.h>
|
||||||
|
#include <soc/t210.h>
|
||||||
|
#include <utils/util.h>
|
||||||
|
|
||||||
|
#include "dram_fuse.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#undef COLOR_CYAN
|
||||||
|
#undef COLOR_WHITE
|
||||||
|
#define COLOR_CYAN 0xFF00FFFF
|
||||||
|
#define COLOR_WHITE 0xFFFFFFFF
|
||||||
|
|
||||||
|
/* Required by BDK */
|
||||||
|
boot_cfg_t __attribute__((section("._boot_cfg"))) b_cfg;
|
||||||
|
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||||
|
|
||||||
|
extern void pivot_stack(u32 stack_top);
|
||||||
|
|
||||||
|
void ipl_main(void)
|
||||||
|
{
|
||||||
|
hw_init();
|
||||||
|
pivot_stack(IPL_STACK_TOP);
|
||||||
|
heap_init(IPL_HEAP_START);
|
||||||
|
|
||||||
|
minerva_init();
|
||||||
|
minerva_change_freq(FREQ_800);
|
||||||
|
|
||||||
|
display_init();
|
||||||
|
u32 *fb = display_init_framebuffer_pitch();
|
||||||
|
gfx_init_ctxt(fb, 720, 1280, 720);
|
||||||
|
gfx_con_init();
|
||||||
|
display_backlight_pwm_init();
|
||||||
|
display_backlight_brightness(100, 1000);
|
||||||
|
|
||||||
|
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
|
||||||
|
|
||||||
|
gfx_clear_grey(0x1B);
|
||||||
|
gfx_con_setpos(0, 0);
|
||||||
|
gfx_con_setcol(COLOR_CYAN, gfx_con.fillbg, gfx_con.bgcol);
|
||||||
|
gfx_printf("RAM test payload\n\n");
|
||||||
|
gfx_con_setcol(COLOR_WHITE, gfx_con.fillbg, gfx_con.bgcol);
|
||||||
|
|
||||||
|
u32 raw = fuse_read_dramid(true);
|
||||||
|
u32 nid = fuse_read_dramid(false);
|
||||||
|
u32 chip = hw_get_chip_id();
|
||||||
|
int mib = dram_capacity_mib_from_fuse();
|
||||||
|
|
||||||
|
gfx_printf("SoC: %s\n", chip == GP_HIDREV_MAJOR_T210B01 ? "Mariko (T210B01)" : "Erista (T210)");
|
||||||
|
gfx_printf("DRAM fuse: raw %d norm %d\n", raw, nid);
|
||||||
|
if (mib > 0)
|
||||||
|
gfx_printf("Table MiB: %d (fuse SKU, not probe)\n", mib);
|
||||||
|
else
|
||||||
|
gfx_printf("Table MiB: (unknown id for this SoC)\n");
|
||||||
|
|
||||||
|
gfx_printf("\nHang — power off or inject payload.\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
msleep(500);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user