Compare commits

...

34 Commits

Author SHA1 Message Date
726ef77194 update: delete atmosphere kips loader.kip and hoc.kip on OmniNX update
All checks were successful
Build / Build (push) Successful in 15s
Made-with: Cursor
2026-04-09 22:11:31 +02:00
13c35400a1 install: backup and restore HorizonOC config.ini on OC pack update
- Copy sd:/config/horizon-oc/config.ini to sd:/.omninx_oc_update before
  update cleanup/copy; restore after Hekate step, then remove the scratch dir.
- Only when INSTALL_MODE_UPDATE and VARIANT_OC.

Made-with: Cursor
2026-04-09 22:11:30 +02:00
f71b6ab629 install: clarify Hekate RAM menu copy (4GB/8GB labels and warnings)
All checks were successful
Build / Build (push) Successful in 16s
Made-with: Cursor
2026-04-09 20:48:50 +02:00
9b559eb7e6 clean: delete TegraExplorer repair .te scripts on clean install
All checks were successful
Build / Build (push) Successful in 16s
Made-with: Cursor
2026-04-07 23:54:54 +02:00
d3735d17ee install: RAM config ini, selection menu, and silent Hekate 8GB step
- Read sd:/config/omninx/ram_config.ini [Ram] 8gb=0|1 when present;
  otherwise show 4 GB / 8 GB menu, write ini, same input as variant menu.
- Replace fuse-based DRAM autodetect for hekate_8gb.bin handling.
- Reprint installer top bar after RAM menu confirm.

Made-with: Cursor
2026-04-07 23:54:53 +02:00
db7d83304f main: add installer_launch_hekate_payload (update.bin or reboot)
Made-with: Cursor
2026-04-07 23:54:51 +02:00
113542f7fb install: declare installer_launch_hekate_payload for sub-menu exit
Made-with: Cursor
2026-04-07 23:54:50 +02:00
72a2083d76 Updated Deletion list
All checks were successful
Build / Build (push) Successful in 16s
2026-04-05 15:38:32 +02:00
3f6bbc0752 Input: console Vol+/- combo only before install; Joy-Con +/- exit removed
All checks were successful
Build / Build (push) Successful in 16s
- cancel_combo_pressed uses only hardware volume buttons
- After installation summary and payload-missing screen: A or Power only

Made-with: Cursor
2026-03-31 13:18:06 +02:00
d1fc24dae8 Install: Hekate 8GB after copy (fuse >4GiB), dram_fuse helper, RAM test target
All checks were successful
Build / Build (push) Successful in 14s
- Add dram_fuse.c/h for shared fuse-to-MiB mapping
- After successful update/clean install copy: if hekate_8gb.bin exists and
  fuse reports more than 4 GiB, copy to sd:/payload.bin and
  sd:/bootloader/update.bin, then remove source; otherwise remove helper only
- Makefile: make ram-test builds output/RAM-Test.bin (tools/ram_test_main.c)

Made-with: Cursor
2026-03-31 00:05:30 +02:00
ef104bce41 Update deletions: keep Switchfin, remove swr-ini-tool nro
Made-with: Cursor
2026-03-30 20:27:39 +02:00
0015c7e8ac Install: copy all staging root files via directory iteration
All checks were successful
Build / Build (push) Successful in 18s
Made-with: Cursor
2026-03-30 17:49:52 +02:00
6dde73f39e Install: copy themes/ in stage 2 (update and clean)
All checks were successful
Build / Build (push) Successful in 11s
Made-with: Cursor
2026-03-06 23:46:40 +01:00
97e8c3d965 Remove outdated UltraHand comment from deletion_lists_update.h
All checks were successful
Build / Build (push) Successful in 13s
Made-with: Cursor
2026-03-06 22:10:32 +01:00
586afc2f56 Revert "Update: preserve UltraHand .offload state (overlays/packages)"
This reverts commit e71fb13bfc.
2026-03-05 17:24:37 +01:00
f943887b39 Revert "Clean install: use normal switch copy, not .offload-aware"
This reverts commit 335ea03b05.
2026-03-05 17:24:26 +01:00
335ea03b05 Clean install: use normal switch copy, not .offload-aware
All checks were successful
Build / Build (push) Successful in 14s
- update_mode_install(variant, offload_aware_switch): true = update (preserve .offload), false = clean
- Update path calls with true; clean_mode_install calls with false so switch/ is copied normally on fresh install

Made-with: Cursor
2026-03-01 15:15:45 +01:00
b0523ada6c nx_sd: add sd_get_card_mounted() for screenshot and other callers
Made-with: Cursor
2026-03-01 14:44:37 +01:00
9a2307a8ee Add screenshot capture via Joy-Con Capture button
- source/screenshot.c, screenshot.h: take_screenshot() saves framebuffer as BMP
- Path: sd:/switch/screenshot/omninx_installer_YYYYMMDD_HHMMSS.bmp (RTC timestamp)
- 3s cooldown, backlight flash on capture; TegraExplorer-style BGR flip
- main.c: call take_screenshot() when jc->cap in all joycon poll loops

Made-with: Cursor
2026-03-01 14:43:58 +01:00
e71fb13bfc Update: preserve UltraHand .offload state (overlays/packages)
All checks were successful
Build / Build (push) Successful in 10s
- Add folder_copy_switch_update_offload_aware() for update-only switch copy
- If item exists in .overlays/.offload or .packages/.offload, update in place; else copy to main
- Remove sd:/switch/.overlays from update delete list so .offload survives
- Fresh install unchanged (no offload logic)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 21:01:36 +01:00
5bcd3987a2 UHS warning: recommend Samsung EVO Plus, EVO Select, PRO Plus
All checks were successful
Build / Build (push) Successful in 11s
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 20:28:15 +01:00
15b7cb1f4c Add battery run protection: require charger below 10%
All checks were successful
Build / Build (push) Successful in 10s
- Add bq24193_charger_connected() for charger detection
- Block install when battery < 10% and charger not plugged in
- Show clear screen after charger detected before continuing
- User can cancel with + and - to return to Hekate

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 15:12:06 +01:00
4b124a9998 Add + and - simultaneously to cancel and return to Hekate before install
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 15:03:58 +01:00
89279e27d5 Updated CI
All checks were successful
Build / Build (push) Successful in 10s
2026-02-13 22:13:29 +01:00
4ae286d21a Updated CI
All checks were successful
Build / Build (push) Successful in 11s
2026-02-13 22:11:42 +01:00
880a9af105 Updated CI
Some checks failed
Build / build (push) Failing after 3s
2026-02-13 22:09:31 +01:00
7fac0e50bb Updated CI
Some checks failed
Build / build (push) Failing after 3s
2026-02-13 22:08:40 +01:00
2c32f19262 Removed .packages from Update to be deleted 2026-02-11 17:58:32 +01:00
4effcf513b Updated Notice 2026-02-11 17:56:31 +01:00
6b04eb5d89 Fixed typo 2026-02-11 17:47:00 +01:00
ed93c32131 Updated Readme
- Added notice for proper use of this payload\n- Fixed some explenations
2026-02-11 17:17:37 +01:00
bae5ecebf1 Updated CI
All checks were successful
Build and Release / build-and-release (push) Successful in 10s
2026-02-11 17:11:18 +01:00
ef16df416b Updated CI
All checks were successful
Build and Release / build-and-release (push) Successful in 9s
2026-02-11 17:09:04 +01:00
f81cd8e381 Updated CI
Some checks failed
Build and Release / build-and-release (push) Failing after 13s
2026-02-11 17:07:40 +01:00
20 changed files with 1839 additions and 1025 deletions

32
.github/workflows/build.yml vendored Normal file
View 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

View File

@@ -1,71 +0,0 @@
name: Build and Release
on:
push:
tags:
- 'v*'
jobs:
build-and-release:
runs-on: ubuntu-latest
container:
image: devkitpro/devkitarm:20251231
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build payload
env:
DEVKITARM: /opt/devkitpro/devkitARM
run: make
- name: Create release and upload asset
env:
SERVER_URL: ${{ github.server_url }}
API_URL: ${{ github.api_url }}
REPOSITORY: ${{ github.repository }}
GITHUB_REF: ${{ github.ref }}
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${GITHUB_REF#refs/tags/}"
BIN_PATH="output/OmniNX-Installer.bin"
# API URL: GitHub uses api.github.com, Gitea uses server_url/api/v1
if [[ "$API_URL" != "" ]]; then
API_BASE="$API_URL"
else
API_BASE="$SERVER_URL/api/v1"
fi
# Create release
RELEASE_RESPONSE=$(curl -s -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"tag_name\": \"$TAG\", \"name\": \"$TAG\", \"body\": \"OmniNX Installer Payload $TAG\"}" \
"$API_BASE/repos/$REPOSITORY/releases")
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
UPLOAD_URL=$(echo "$RELEASE_RESPONSE" | grep -o '"upload_url":"[^"]*' | head -1 | cut -d'"' -f4)
if [ -z "$RELEASE_ID" ]; then
echo "Failed to create release. Response: $RELEASE_RESPONSE"
exit 1
fi
# Upload asset (GitHub uses upload_url; Gitea uses assets endpoint)
if [[ -n "$UPLOAD_URL" ]]; then
UPLOAD_URL="${UPLOAD_URL%%\{*}"
curl -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$BIN_PATH" \
"${UPLOAD_URL}?name=OmniNX-Installer.bin"
else
curl -X POST \
-H "Authorization: token $TOKEN" \
-F "attachment=@$BIN_PATH" \
"$API_BASE/repos/$REPOSITORY/releases/$RELEASE_ID/assets?name=OmniNX-Installer.bin"
fi

199
Makefile
View File

@@ -1,90 +1,109 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),) ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM") $(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif endif
include $(DEVKITARM)/base_rules include $(DEVKITARM)/base_rules
################################################################################ ################################################################################
IPL_LOAD_ADDR := 0x40008000 IPL_LOAD_ADDR := 0x40008000
VERSION := $(shell cat VERSION) VERSION := $(shell cat VERSION)
################################################################################ ################################################################################
TARGET := omninx-installer TARGET := omninx-installer
OUTPUT_NAME := OmniNX-Installer.bin OUTPUT_NAME := OmniNX-Installer.bin
BUILDDIR := build BUILDDIR := build
OUTPUTDIR := output OUTPUTDIR := output
SOURCEDIR := source SOURCEDIR := source
BDKDIR := bdk BDKDIR := bdk
BDKINC := -I./$(BDKDIR) BDKINC := -I./$(BDKDIR)
VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/))
# All source files # All source files
OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ OBJS = $(patsubst $(SOURCEDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \
$(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \ $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/$(TARGET)/%.o, \
$(call rwildcard, $(SOURCEDIR), *.S *.c))) $(call rwildcard, $(SOURCEDIR), *.S *.c)))
OBJS += $(patsubst $(BDKDIR)/%.S, $(BUILDDIR)/$(TARGET)/%.o, \ 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)))
GFX_INC := '"../$(SOURCEDIR)/gfx.h"' GFX_INC := '"../$(SOURCEDIR)/gfx.h"'
FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"' FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
################################################################################ ################################################################################
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC) CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
CUSTOMDEFINES += -DVERSION='"$(VERSION)"' CUSTOMDEFINES += -DVERSION='"$(VERSION)"'
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall -Wno-missing-braces $(CUSTOMDEFINES) CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11 -Wall -Wno-missing-braces $(CUSTOMDEFINES)
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR) LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections -Xlinker --defsym=IPL_LOAD_ADDR=$(IPL_LOAD_ADDR)
################################################################################ ################################################################################
.PHONY: all clean release RAMTEST_BIN := $(OUTPUTDIR)/RAM-Test.bin
OBJS_RAMTEST := $(filter-out $(BUILDDIR)/$(TARGET)/main.o,$(OBJS)) \
all: $(OUTPUTDIR)/$(OUTPUT_NAME) $(BUILDDIR)/$(TARGET)/ram_test_main.o
$(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
@echo "Payload size is $(BIN_SIZE) bytes" .PHONY: all clean release ram-test
@echo "Max size is 126296 bytes."
all: $(OUTPUTDIR)/$(OUTPUT_NAME)
clean: $(eval BIN_SIZE = $(shell wc -c < $(OUTPUTDIR)/$(OUTPUT_NAME)))
@rm -rf $(BUILDDIR) @echo "Payload size is $(BIN_SIZE) bytes"
@rm -rf $(OUTPUTDIR) @echo "Max size is 126296 bytes."
@rm -rf release
@rm -f $(TARGET)-*.zip clean:
@rm -rf $(BUILDDIR)
$(OUTPUTDIR)/$(OUTPUT_NAME): $(BUILDDIR)/$(TARGET)/$(TARGET).elf @rm -rf $(OUTPUTDIR)
@mkdir -p "$(@D)" @rm -f $(RAMTEST_BIN)
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(TARGET).bin @rm -rf release
@mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(OUTPUT_NAME) @rm -f $(TARGET)-*.zip
$(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) $(OUTPUTDIR)/$(OUTPUT_NAME): $(BUILDDIR)/$(TARGET)/$(TARGET).elf
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ @mkdir -p "$(@D)"
$(OBJCOPY) -S -O binary $< $(OUTPUTDIR)/$(TARGET).bin
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c @mv $(OUTPUTDIR)/$(TARGET).bin $(OUTPUTDIR)/$(OUTPUT_NAME)
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.S
@mkdir -p "$(@D)" $(BUILDDIR)/$(TARGET)/ram_test_main.o: tools/ram_test_main.c
$(CC) $(CFLAGS) -c $< -o $@ @mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c
@mkdir -p "$(@D)" $(BUILDDIR)/$(TARGET)/ram_test.elf: $(OBJS_RAMTEST)
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@ $(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S $(RAMTEST_BIN): $(BUILDDIR)/$(TARGET)/ram_test.elf
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(CC) $(CFLAGS) -c $< -o $@ $(OBJCOPY) -S -O binary $< $@
@echo "RAM-Test payload: $(RAMTEST_BIN) ($$(wc -c < $@) bytes)"
release: $(OUTPUTDIR)/$(OUTPUT_NAME)
@mkdir -p release/bootloader/payloads ram-test: $(RAMTEST_BIN)
@cp $(OUTPUTDIR)/$(OUTPUT_NAME) release/bootloader/payloads/$(OUTPUT_NAME)
@cd release && zip -r ../$(TARGET)-$(VERSION).zip bootloader $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
@echo "Release package created: $(TARGET)-$(VERSION).zip" @mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.S
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) -c $< -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.c
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) $(BDKINC) -I$(SOURCEDIR) -c $< -o $@
$(BUILDDIR)/$(TARGET)/%.o: $(BDKDIR)/%.S
@mkdir -p "$(@D)"
$(CC) $(CFLAGS) -c $< -o $@
release: $(OUTPUTDIR)/$(OUTPUT_NAME)
@mkdir -p release/bootloader/payloads
@cp $(OUTPUTDIR)/$(OUTPUT_NAME) release/bootloader/payloads/$(OUTPUT_NAME)
@cd release && zip -r ../$(TARGET)-$(VERSION).zip bootloader
@echo "Release package created: $(TARGET)-$(VERSION).zip"

View File

@@ -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.
@@ -56,11 +58,7 @@ The built payload will be output to `output/OmniNX-Installer.bin`.
### CI / GitHub Actions ### CI / GitHub Actions
Pushing a version tag (e.g. `v1.0.0`) triggers a build and creates a release with the `.bin` file attached. Every push triggers a build. The `.bin` file is produced and attached as a workflow artifact (Actions tab → select run → Artifacts).
**GitHub:** Uses the built-in `GITHUB_TOKEN` automatically.
**Gitea:** Add a `GITHUB_TOKEN` secret (Settings → Secrets and Variables → Actions) with a token that has permission to create releases.
## Usage ## Usage
@@ -119,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

View File

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

View File

@@ -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_ */

View File

@@ -101,3 +101,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);
}

View File

@@ -8,6 +8,12 @@
#define TEMP_BACKUP_PATH "sd:/temp_backup" #define TEMP_BACKUP_PATH "sd:/temp_backup"
/** 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, Tinfoil, prod.keys) before clean install // Backup user data (DBI, Tinfoil, prod.keys) before clean install
int backup_user_data(void); int backup_user_data(void);
@@ -16,3 +22,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);

View File

@@ -1,295 +1,300 @@
/* /*
* OmniNX Installer - Deletion Lists for Clean Install Mode * OmniNX Installer - Deletion Lists for Clean Install Mode
* Selective deletion when no OmniNX install was found. * Selective deletion when no OmniNX install was found.
* Only listed paths are removed; does not wipe whole card or user configs. * Only listed paths are removed; does not wipe whole card or user configs.
*/ */
#pragma once #pragma once
// Atmosphere subdirectories to delete // Atmosphere subdirectories to delete
static const char* clean_atmosphere_dirs_to_delete[] = { static const char* clean_atmosphere_dirs_to_delete[] = {
"sd:/atmosphere/config", "sd:/atmosphere/config",
"sd:/atmosphere/crash_reports", "sd:/atmosphere/crash_reports",
"sd:/atmosphere/erpt_reports", "sd:/atmosphere/erpt_reports",
"sd:/atmosphere/exefs_patches/CrunchPatch", "sd:/atmosphere/exefs_patches/CrunchPatch",
"sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0", "sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0",
"sd:/atmosphere/exefs_patches/bluetooth_patches", "sd:/atmosphere/exefs_patches/bluetooth_patches",
"sd:/atmosphere/exefs_patches/bootlogo", "sd:/atmosphere/exefs_patches/bootlogo",
"sd:/atmosphere/exefs_patches/btm_patches", "sd:/atmosphere/exefs_patches/btm_patches",
"sd:/atmosphere/exefs_patches/es_patches", "sd:/atmosphere/exefs_patches/es_patches",
"sd:/atmosphere/exefs_patches/hid_patches", "sd:/atmosphere/exefs_patches/hid_patches",
"sd:/atmosphere/exefs_patches/logo1", "sd:/atmosphere/exefs_patches/logo1",
"sd:/atmosphere/exefs_patches/nfim_ctest", "sd:/atmosphere/exefs_patches/nfim_ctest",
"sd:/atmosphere/exefs_patches/nim_ctest", "sd:/atmosphere/exefs_patches/nim_ctest",
"sd:/atmosphere/exefs_patches/nvnflinger_cmu", "sd:/atmosphere/exefs_patches/nvnflinger_cmu",
"sd:/atmosphere/extrazz", "sd:/atmosphere/extrazz",
"sd:/atmosphere/fatal_errors", "sd:/atmosphere/fatal_errors",
"sd:/atmosphere/fatal_reports", "sd:/atmosphere/fatal_reports",
"sd:/atmosphere/flags", "sd:/atmosphere/flags",
"sd:/atmosphere/hbl_html", "sd:/atmosphere/hbl_html",
"sd:/atmosphere/hosts", "sd:/atmosphere/hosts",
"sd:/atmosphere/kips", "sd:/atmosphere/kips",
"sd:/atmosphere/kip1", "sd:/atmosphere/kip1",
"sd:/atmosphere/kip_patches", "sd:/atmosphere/kip_patches",
"sd:/atmosphere/logs", "sd:/atmosphere/logs",
NULL NULL
}; };
// Atmosphere contents directories (title IDs; only under atmosphere/contents/) // 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/0000000000534C56",
"sd:/atmosphere/contents/00FF0000B378D640", "sd:/atmosphere/contents/00FF0000B378D640",
"sd:/atmosphere/contents/00FF0000636C6BFF", "sd:/atmosphere/contents/00FF0000636C6BFF",
"sd:/atmosphere/contents/00FF0000A53BB665", "sd:/atmosphere/contents/00FF0000A53BB665",
"sd:/atmosphere/contents/0100000000000008", "sd:/atmosphere/contents/0100000000000008",
"sd:/atmosphere/contents/010000000000000D", "sd:/atmosphere/contents/010000000000000D",
"sd:/atmosphere/contents/010000000000002B", "sd:/atmosphere/contents/010000000000002B",
"sd:/atmosphere/contents/0100000000000032", "sd:/atmosphere/contents/0100000000000032",
"sd:/atmosphere/contents/0100000000000034", "sd:/atmosphere/contents/0100000000000034",
"sd:/atmosphere/contents/0100000000000036", "sd:/atmosphere/contents/0100000000000036",
"sd:/atmosphere/contents/0100000000000037", "sd:/atmosphere/contents/0100000000000037",
"sd:/atmosphere/contents/010000000000003C", "sd:/atmosphere/contents/010000000000003C",
"sd:/atmosphere/contents/0100000000000042", "sd:/atmosphere/contents/0100000000000042",
"sd:/atmosphere/contents/0100000000000895", "sd:/atmosphere/contents/0100000000000895",
"sd:/atmosphere/contents/0100000000000F12", "sd:/atmosphere/contents/0100000000000F12",
"sd:/atmosphere/contents/0100000000001000", "sd:/atmosphere/contents/0100000000001000",
"sd:/atmosphere/contents/0100000000001007", "sd:/atmosphere/contents/0100000000001007",
"sd:/atmosphere/contents/0100000000001013", "sd:/atmosphere/contents/0100000000001013",
"sd:/atmosphere/contents/010000000000DA7A", "sd:/atmosphere/contents/010000000000DA7A",
"sd:/atmosphere/contents/010000000000bd00", "sd:/atmosphere/contents/010000000000bd00",
"sd:/atmosphere/contents/01006a800016e000", "sd:/atmosphere/contents/01006a800016e000",
"sd:/atmosphere/contents/01009D901BC56000", "sd:/atmosphere/contents/01009D901BC56000",
"sd:/atmosphere/contents/0100A3900C3E2000", "sd:/atmosphere/contents/0100A3900C3E2000",
"sd:/atmosphere/contents/0100F43008C44000", "sd:/atmosphere/contents/0100F43008C44000",
"sd:/atmosphere/contents/050000BADDAD0000", "sd:/atmosphere/contents/050000BADDAD0000",
"sd:/atmosphere/contents/4200000000000000", "sd:/atmosphere/contents/4200000000000000",
"sd:/atmosphere/contents/420000000000000B", "sd:/atmosphere/contents/420000000000000B",
"sd:/atmosphere/contents/420000000000000E", "sd:/atmosphere/contents/420000000000000E",
"sd:/atmosphere/contents/4200000000000010", "sd:/atmosphere/contents/4200000000000010",
"sd:/atmosphere/contents/4200000000000FFF", "sd:/atmosphere/contents/4200000000000FFF",
"sd:/atmosphere/contents/420000000007E51A", "sd:/atmosphere/contents/420000000007E51A",
"sd:/atmosphere/contents/420000000007E51B", "sd:/atmosphere/contents/420000000007E51B",
"sd:/atmosphere/contents/690000000000000D", "sd:/atmosphere/contents/690000000000000D",
NULL NULL
}; };
// Atmosphere files to delete // 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/exosphere.ini",
"sd:/atmosphere/config/stratosphere.ini", "sd:/atmosphere/config/stratosphere.ini",
"sd:/atmosphere/hbl.nsp", "sd:/atmosphere/hbl.nsp",
"sd:/atmosphere/package3", "sd:/atmosphere/package3",
"sd:/atmosphere/reboot_payload.bin", "sd:/atmosphere/reboot_payload.bin",
"sd:/atmosphere/stratosphere.romfs", "sd:/atmosphere/stratosphere.romfs",
NULL NULL
}; };
// Bootloader directories to delete // Bootloader directories to delete
static const char* clean_bootloader_dirs_to_delete[] = { static const char* clean_bootloader_dirs_to_delete[] = {
"sd:/bootloader/boot", "sd:/bootloader/boot",
"sd:/bootloader/bootlogo", "sd:/bootloader/bootlogo",
"sd:/bootloader/ini2", "sd:/bootloader/ini2",
"sd:/bootloader/payloads", "sd:/bootloader/payloads",
"sd:/bootloader/reboot", "sd:/bootloader/reboot",
"sd:/bootloader/res", "sd:/bootloader/res",
"sd:/bootloader/sys", "sd:/bootloader/sys",
NULL NULL
}; };
// Bootloader files to delete // Bootloader files to delete
static const char* clean_bootloader_files_to_delete[] = { 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/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",
NULL NULL
}; };
// Config directories to delete // Config directories to delete
static const char* clean_config_dirs_to_delete[] = { static const char* clean_config_dirs_to_delete[] = {
"sd:/config/aio-switch-updater", "sd:/config/aio-switch-updater",
"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/quickntp",
"sd:/config/sys-con", "sd:/config/sys-con",
"sd:/config/sys-patch", "sd:/config/sys-patch",
"sd:/config/uberhand", "sd:/config/uberhand",
"sd:/config/ultrahand", "sd:/config/ultrahand",
NULL NULL
}; };
// Switch directories to delete // Switch directories to delete
static const char* clean_switch_dirs_to_delete[] = { static const char* clean_switch_dirs_to_delete[] = {
"sd:/switch/.overlays", "sd:/switch/.overlays",
"sd:/switch/.packages", "sd:/switch/.packages",
"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",
"sd:/switch/appstore", "sd:/switch/appstore",
"sd:/switch/AtmoXL-Titel-Installer", "sd:/switch/AtmoXL-Titel-Installer",
"sd:/switch/breeze", "sd:/switch/breeze",
"sd:/switch/checkpoint", "sd:/switch/checkpoint",
"sd:/switch/cheats-updater", "sd:/switch/cheats-updater",
"sd:/switch/chiaki", "sd:/switch/chiaki",
"sd:/switch/ChoiDujourNX", "sd:/switch/ChoiDujourNX",
"sd:/switch/crash_ams", "sd:/switch/crash_ams",
"sd:/switch/Daybreak", "sd:/switch/Daybreak",
"sd:/switch/DNS_mitm Tester", "sd:/switch/DNS_mitm Tester",
"sd:/switch/EdiZon", "sd:/switch/EdiZon",
"sd:/switch/Fizeau", "sd:/switch/Fizeau",
"sd:/switch/FTPD", "sd:/switch/FTPD",
"sd:/switch/fw-downloader", "sd:/switch/fw-downloader",
"sd:/switch/gamecard_installer", "sd:/switch/gamecard_installer",
"sd:/switch/Goldleaf", "sd:/switch/Goldleaf",
"sd:/switch/haze", "sd:/switch/haze",
"sd:/switch/JKSV", "sd:/switch/JKSV",
"sd:/switch/kefir-updater", "sd:/switch/kefir-updater",
"sd:/switch/ldnmitm_config", "sd:/switch/ldnmitm_config",
"sd:/switch/Linkalho", "sd:/switch/Linkalho",
"sd:/switch/Moonlight-Switch", "sd:/switch/Moonlight-Switch",
"sd:/switch/Neumann", "sd:/switch/Neumann",
"sd:/switch/NX-Activity-Log", "sd:/switch/NX-Activity-Log",
"sd:/switch/NX-Save-Sync", "sd:/switch/NX-Save-Sync",
"sd:/switch/NX-Shell", "sd:/switch/NX-Shell",
"sd:/switch/NX-Update-Checker ", "sd:/switch/NX-Update-Checker ",
"sd:/switch/NXGallery", "sd:/switch/NXGallery",
"sd:/switch/NXRemoteLauncher", "sd:/switch/NXRemoteLauncher",
"sd:/switch/NXThemesInstaller", "sd:/switch/NXThemesInstaller",
"sd:/switch/nxdumptool", "sd:/switch/nxdumptool",
"sd:/switch/nxmtp", "sd:/switch/nxmtp",
"sd:/switch/Payload_launcher", "sd:/switch/Payload_launcher",
"sd:/switch/Reboot", "sd:/switch/Reboot",
"sd:/switch/reboot_to_argonNX", "sd:/switch/reboot_to_argonNX",
"sd:/switch/reboot_to_hekate", "sd:/switch/reboot_to_hekate",
"sd:/switch/Shutdown_System", "sd:/switch/Shutdown_System",
"sd:/switch/SimpleModDownloader", "sd:/switch/SimpleModDownloader",
"sd:/switch/SimpleModManager", "sd:/switch/SimpleModManager",
"sd:/switch/sphaira", "sd:/switch/sphaira",
"sd:/switch/studious-pancake", "sd:/switch/studious-pancake",
"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/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",
"sd:/switch/themezer-nx", "sd:/switch/themezer-nx",
"sd:/switch/themezernx", "sd:/switch/themezernx",
"sd:/switch/tinwoo", "sd:/switch/tinwoo",
NULL NULL
}; };
// Switch files (NRO) to delete // 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/90DNS_tester/90DNS_tester.nro",
"sd:/switch/breeze.nro", "sd:/switch/breeze.nro",
"sd:/switch/cheats-updater.nro", "sd:/switch/cheats-updater.nro",
"sd:/switch/chiaki.nro", "sd:/switch/chiaki.nro",
"sd:/switch/ChoiDujourNX.nro", "sd:/switch/ChoiDujourNX.nro",
"sd:/switch/daybreak.nro", "sd:/switch/daybreak.nro",
"sd:/switch/DBI.nro", "sd:/switch/DBI.nro",
"sd:/switch/DBI/DBI.nro", "sd:/switch/DBI/DBI.nro",
"sd:/switch/DBI/DBI_810_DE.nro", "sd:/switch/DBI/DBI_810_DE.nro",
"sd:/switch/DBI/DBI_810_EN.nro", "sd:/switch/DBI/DBI_810_EN.nro",
"sd:/switch/DBI/DBI_845_DE.nro", "sd:/switch/DBI/DBI_845_DE.nro",
"sd:/switch/DBI/DBI_845_EN.nro", "sd:/switch/DBI/DBI_845_EN.nro",
"sd:/switch/DBI/DBI_849_DE.nro", "sd:/switch/DBI/DBI_849_DE.nro",
"sd:/switch/DBI/DBI_849_EN.nro", "sd:/switch/DBI/DBI_849_EN.nro",
"sd:/switch/DBI_810_DE/DBI_810.nro", "sd:/switch/DBI/DBI_874_DE.nro",
"sd:/switch/DBI_810_DE/DBI_810_DE.nro", "sd:/switch/DBI/DBI_874_EN.nro",
"sd:/switch/DBI_810_EN/DBI_810_EN.nro", "sd:/switch/DBI_810_DE/DBI_810.nro",
"sd:/switch/DBI_RU/DBI_RU.nro", "sd:/switch/DBI_810_DE/DBI_810_DE.nro",
"sd:/switch/DBI/DBI_EN.nro", "sd:/switch/DBI_810_EN/DBI_810_EN.nro",
"sd:/switch/DBI_DE/DBI_DE.nro", "sd:/switch/DBI_RU/DBI_RU.nro",
"sd:/switch/DNS_mitm Tester.nro", "sd:/switch/DBI/DBI_EN.nro",
"sd:/switch/EdiZon.nro", "sd:/switch/DBI_DE/DBI_DE.nro",
"sd:/switch/Fizeau.nro", "sd:/switch/DNS_mitm Tester.nro",
"sd:/switch/Goldleaf.nro", "sd:/switch/EdiZon.nro",
"sd:/switch/haze.nro", "sd:/switch/Fizeau.nro",
"sd:/switch/JKSV.nro", "sd:/switch/Goldleaf.nro",
"sd:/switch/ldnmitm_config.nro", "sd:/switch/haze.nro",
"sd:/switch/linkalho.nro", "sd:/switch/JKSV.nro",
"sd:/switch/Moonlight-Switch.nro", "sd:/switch/ldnmitm_config.nro",
"sd:/switch/Neumann.nro", "sd:/switch/linkalho.nro",
"sd:/switch/NX-Shell.nro", "sd:/switch/Moonlight-Switch.nro",
"sd:/switch/NXGallery.nro", "sd:/switch/Neumann.nro",
"sd:/switch/NXThemesInstaller.nro", "sd:/switch/NX-Shell.nro",
"sd:/switch/nxdumptool.nro", "sd:/switch/NXGallery.nro",
"sd:/switch/nxtc.bin", "sd:/switch/NXThemesInstaller.nro",
"sd:/switch/reboot_to_payload.nro", "sd:/switch/nxdumptool.nro",
"sd:/switch/SimpleModDownloader.nro", "sd:/switch/nxtc.bin",
"sd:/switch/SimpleModManager.nro", "sd:/switch/reboot_to_payload.nro",
"sd:/switch/sphaira.nro", "sd:/switch/SimpleModDownloader.nro",
"sd:/switch/SwitchIdent.nro", "sd:/switch/SimpleModManager.nro",
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro", "sd:/switch/sphaira.nro",
"sd:/switch/Switchfin.nro", "sd:/switch/SwitchIdent.nro",
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro", "sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
"sd:/switch/Sys-Con.nro", "sd:/switch/Switchfin.nro",
"sd:/switch/sys-clk-manager.nro", "sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
"sd:/switch/tinfoil.nro", "sd:/switch/Sys-Con.nro",
"sd:/switch/tinfoil/tinfoil.nro", "sd:/switch/sys-clk-manager.nro",
"sd:/switch/tinwoo.nro", "sd:/switch/tinfoil.nro",
"sd:/switch/tinwoo/tinwoo.nro", "sd:/switch/tinfoil/tinfoil.nro",
NULL "sd:/switch/tinwoo.nro",
}; "sd:/switch/tinwoo/tinwoo.nro",
NULL
// Root CFW files to delete };
static const char* clean_root_files_to_delete[] = {
"sd:/boot.dat", // Root CFW files to delete
"sd:/boot.ini", static const char* clean_root_files_to_delete[] = {
"sd:/exosphere.bin", "sd:/boot.dat",
"sd:/exosphere.ini", "sd:/boot.ini",
"sd:/hbmenu.nro", "sd:/exosphere.bin",
"sd:/install.bat", "sd:/exosphere.ini",
"sd:/license", "sd:/hbmenu.nro",
"sd:/loader.bin", "sd:/install.bat",
"sd:/mc-mitm.log", "sd:/license",
"sd:/payload.bin", "sd:/loader.bin",
"sd:/update.bin", "sd:/mc-mitm.log",
"sd:/version", "sd:/payload.bin",
NULL "sd:/update.bin",
}; "sd:/version",
NULL
// Miscellaneous directories to delete };
static const char* clean_misc_dirs_to_delete[] = {
"sd:/argon", // Miscellaneous directories to delete
"sd:/games", static const char* clean_misc_dirs_to_delete[] = {
"sd:/NSPs (Tools)", "sd:/argon",
"sd:/Patched Apps", "sd:/games",
"sd:/SaltySD/flags", "sd:/NSPs (Tools)",
"sd:/scripts", "sd:/Patched Apps",
"sd:/switch/tinfoil/db", "sd:/SaltySD/flags",
"sd:/tools", "sd:/scripts",
"sd:/warmboot_mariko", "sd:/switch/tinfoil/db",
NULL "sd:/tools",
}; "sd:/warmboot_mariko",
NULL
// Miscellaneous files to delete };
static const char* clean_misc_files_to_delete[] = {
"sd:/fusee-primary.bin", // Miscellaneous files to delete
"sd:/fusee.bin", static const char* clean_misc_files_to_delete[] = {
"sd:/SaltySD/exceptions.txt", "sd:/TegraExplorer/scripts/Reparatur Skript fuer error 010000000000BD00.te",
"sd:/SaltySD/saltysd_bootstrap.elf", "sd:/TegraExplorer/scripts/Reparatur Skript fuer error 0100000000001000.te",
"sd:/SaltySD/saltysd_bootstrap32_3k.elf", "sd:/TegraExplorer/scripts/Reparatur Skript fuer error 690000000000000D.te",
"sd:/SaltySD/saltysd_bootstrap32_5k.elf", "sd:/TegraExplorer/scripts/Reparatur Skript fuer error 4200000000000010.te",
"sd:/SaltySD/saltysd_core.elf", "sd:/fusee-primary.bin",
"sd:/SaltySD/saltysd_core32.elf", "sd:/fusee.bin",
NULL "sd:/SaltySD/exceptions.txt",
}; "sd:/SaltySD/saltysd_bootstrap.elf",
"sd:/SaltySD/saltysd_bootstrap32_3k.elf",
// Old version marker files to delete (clean install only) "sd:/SaltySD/saltysd_bootstrap32_5k.elf",
static const char* old_version_files_to_delete[] = { "sd:/SaltySD/saltysd_core.elf",
"sd:/1.0.0l", "sd:/SaltySD/saltysd_core32.elf",
"sd:/1.0.0s", NULL
"sd:/1.0.0oc", };
"sd:/1.4.0-pre",
"sd:/1.4.0-pre-c", // Old version marker files to delete (clean install only)
"sd:/1.4.0-pre-d", static const char* old_version_files_to_delete[] = {
"sd:/1.4.1", "sd:/1.4.0-pre",
"sd:/1.5.0", "sd:/1.4.0-pre-c",
NULL "sd:/1.4.0-pre-d",
}; "sd:/1.4.1",
"sd:/1.5.0",
"sd:/1.6.0",
"sd:/1.6.1",
NULL
};

View File

@@ -1,280 +1,282 @@
/* /*
* OmniNX Installer - Deletion Lists for Update Mode * OmniNX Installer - Deletion Lists for Update Mode
* Selective deletion when OmniNX is already installed. * Selective deletion when OmniNX is already installed.
*/ */
#pragma once #pragma once
// Atmosphere subdirectories to delete // Atmosphere subdirectories to delete
static const char* atmosphere_dirs_to_delete[] = { static const char* atmosphere_dirs_to_delete[] = {
"sd:/atmosphere/config", "sd:/atmosphere/config",
"sd:/atmosphere/crash_reports", "sd:/atmosphere/crash_reports",
"sd:/atmosphere/erpt_reports", "sd:/atmosphere/erpt_reports",
"sd:/atmosphere/exefs_patches/CrunchPatch", "sd:/atmosphere/exefs_patches/CrunchPatch",
"sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0", "sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0",
"sd:/atmosphere/exefs_patches/bluetooth_patches", "sd:/atmosphere/exefs_patches/bluetooth_patches",
"sd:/atmosphere/exefs_patches/bootlogo", "sd:/atmosphere/exefs_patches/bootlogo",
"sd:/atmosphere/exefs_patches/btm_patches", "sd:/atmosphere/exefs_patches/btm_patches",
"sd:/atmosphere/exefs_patches/es_patches", "sd:/atmosphere/exefs_patches/es_patches",
"sd:/atmosphere/exefs_patches/hid_patches", "sd:/atmosphere/exefs_patches/hid_patches",
"sd:/atmosphere/exefs_patches/logo1", "sd:/atmosphere/exefs_patches/logo1",
"sd:/atmosphere/exefs_patches/nfim_ctest", "sd:/atmosphere/exefs_patches/nfim_ctest",
"sd:/atmosphere/exefs_patches/nim_ctest", "sd:/atmosphere/exefs_patches/nim_ctest",
"sd:/atmosphere/exefs_patches/nvnflinger_cmu", "sd:/atmosphere/exefs_patches/nvnflinger_cmu",
"sd:/atmosphere/extrazz", "sd:/atmosphere/extrazz",
"sd:/atmosphere/fatal_errors", "sd:/atmosphere/fatal_errors",
"sd:/atmosphere/fatal_reports", "sd:/atmosphere/fatal_reports",
"sd:/atmosphere/flags", "sd:/atmosphere/flags",
"sd:/atmosphere/hbl_html", "sd:/atmosphere/hbl_html",
"sd:/atmosphere/hosts", "sd:/atmosphere/hosts",
"sd:/atmosphere/kips", "sd:/atmosphere/kips",
"sd:/atmosphere/kip1", "sd:/atmosphere/kip1",
"sd:/atmosphere/kip_patches", "sd:/atmosphere/kip_patches",
"sd:/atmosphere/logs", "sd:/atmosphere/logs",
NULL NULL
}; };
// Atmosphere contents directories (title IDs; only under atmosphere/contents/) // Atmosphere contents directories (title IDs; only under atmosphere/contents/)
static const char* atmosphere_contents_dirs_to_delete[] = { static const char* atmosphere_contents_dirs_to_delete[] = {
"sd:/atmosphere/contents/0000000000534C56", "sd:/atmosphere/contents/0000000000534C56",
"sd:/atmosphere/contents/00FF0000B378D640", "sd:/atmosphere/contents/00FF0000B378D640",
"sd:/atmosphere/contents/00FF0000636C6BFF", "sd:/atmosphere/contents/00FF0000636C6BFF",
"sd:/atmosphere/contents/00FF0000A53BB665", "sd:/atmosphere/contents/00FF0000A53BB665",
"sd:/atmosphere/contents/0100000000000008", "sd:/atmosphere/contents/0100000000000008",
"sd:/atmosphere/contents/010000000000000D", "sd:/atmosphere/contents/010000000000000D",
"sd:/atmosphere/contents/010000000000002B", "sd:/atmosphere/contents/010000000000002B",
"sd:/atmosphere/contents/0100000000000032", "sd:/atmosphere/contents/0100000000000032",
"sd:/atmosphere/contents/0100000000000034", "sd:/atmosphere/contents/0100000000000034",
"sd:/atmosphere/contents/0100000000000036", "sd:/atmosphere/contents/0100000000000036",
"sd:/atmosphere/contents/0100000000000037", "sd:/atmosphere/contents/0100000000000037",
"sd:/atmosphere/contents/010000000000003C", "sd:/atmosphere/contents/010000000000003C",
"sd:/atmosphere/contents/0100000000000042", "sd:/atmosphere/contents/0100000000000042",
"sd:/atmosphere/contents/0100000000000895", "sd:/atmosphere/contents/0100000000000895",
"sd:/atmosphere/contents/0100000000000F12", "sd:/atmosphere/contents/0100000000000F12",
"sd:/atmosphere/contents/0100000000001000", "sd:/atmosphere/contents/0100000000001000",
"sd:/atmosphere/contents/0100000000001007", "sd:/atmosphere/contents/0100000000001007",
"sd:/atmosphere/contents/0100000000001013", "sd:/atmosphere/contents/0100000000001013",
"sd:/atmosphere/contents/010000000000DA7A", "sd:/atmosphere/contents/010000000000DA7A",
"sd:/atmosphere/contents/010000000000bd00", "sd:/atmosphere/contents/010000000000bd00",
"sd:/atmosphere/contents/01006a800016e000", "sd:/atmosphere/contents/01006a800016e000",
"sd:/atmosphere/contents/01009D901BC56000", "sd:/atmosphere/contents/01009D901BC56000",
"sd:/atmosphere/contents/0100A3900C3E2000", "sd:/atmosphere/contents/0100A3900C3E2000",
"sd:/atmosphere/contents/0100F43008C44000", "sd:/atmosphere/contents/0100F43008C44000",
"sd:/atmosphere/contents/050000BADDAD0000", "sd:/atmosphere/contents/050000BADDAD0000",
"sd:/atmosphere/contents/4200000000000000", "sd:/atmosphere/contents/4200000000000000",
"sd:/atmosphere/contents/420000000000000B", "sd:/atmosphere/contents/420000000000000B",
"sd:/atmosphere/contents/420000000000000E", "sd:/atmosphere/contents/420000000000000E",
"sd:/atmosphere/contents/4200000000000010", "sd:/atmosphere/contents/4200000000000010",
"sd:/atmosphere/contents/4200000000000FFF", "sd:/atmosphere/contents/4200000000000FFF",
"sd:/atmosphere/contents/420000000007E51A", "sd:/atmosphere/contents/420000000007E51A",
"sd:/atmosphere/contents/420000000007E51B", "sd:/atmosphere/contents/420000000007E51B",
"sd:/atmosphere/contents/690000000000000D", "sd:/atmosphere/contents/690000000000000D",
NULL NULL
}; };
// Atmosphere files to delete // Atmosphere files to delete
static const char* atmosphere_files_to_delete[] = { static const char* atmosphere_files_to_delete[] = {
"sd:/atmosphere/config/exosphere.ini", "sd:/atmosphere/config/exosphere.ini",
"sd:/atmosphere/config/stratosphere.ini", "sd:/atmosphere/config/stratosphere.ini",
"sd:/atmosphere/hbl.nsp", "sd:/atmosphere/hbl.nsp",
"sd:/atmosphere/package3", "sd:/atmosphere/package3",
"sd:/atmosphere/reboot_payload.bin", "sd:/atmosphere/reboot_payload.bin",
"sd:/atmosphere/stratosphere.romfs", "sd:/atmosphere/stratosphere.romfs",
NULL "sd:/atmosphere/kips/loader.kip",
}; "sd:/atmosphere/kips/hoc.kip",
NULL
// Bootloader directories to delete };
static const char* bootloader_dirs_to_delete[] = {
"sd:/bootloader/boot", // Bootloader directories to delete
"sd:/bootloader/bootlogo", static const char* bootloader_dirs_to_delete[] = {
"sd:/bootloader/ini2", "sd:/bootloader/boot",
"sd:/bootloader/payloads", "sd:/bootloader/bootlogo",
"sd:/bootloader/reboot", "sd:/bootloader/ini2",
"sd:/bootloader/res", "sd:/bootloader/payloads",
"sd:/bootloader/sys", "sd:/bootloader/reboot",
NULL "sd:/bootloader/res",
}; "sd:/bootloader/sys",
NULL
// Bootloader files to delete };
static const char* bootloader_files_to_delete[] = {
"sd:/bootloader/ArgonNX.bin", // Bootloader files to delete
"sd:/bootloader/bootlogo.bmp", static const char* bootloader_files_to_delete[] = {
"sd:/bootloader/hekate_ipl.ini", "sd:/bootloader/ArgonNX.bin",
"sd:/bootloader/nyx.ini", "sd:/bootloader/bootlogo.bmp",
"sd:/bootloader/patches.ini", "sd:/bootloader/hekate_ipl.ini",
"sd:/bootloader/update.bin", "sd:/bootloader/nyx.ini",
"sd:/bootloader/ini/EmuMMC ohne Mods.ini", "sd:/bootloader/patches.ini",
NULL "sd:/bootloader/update.bin",
}; "sd:/bootloader/ini/EmuMMC ohne Mods.ini",
NULL
// Config directories to delete };
static const char* config_dirs_to_delete[] = {
"sd:/config/aio-switch-updater", // Config directories to delete
"sd:/config/blue_pack_updater", static const char* config_dirs_to_delete[] = {
"sd:/config/kefir-updater", "sd:/config/aio-switch-updater",
"sd:/config/nx-hbmenu", "sd:/config/blue_pack_updater",
"sd:/config/quickntp", "sd:/config/kefir-updater",
"sd:/config/sys-con", "sd:/config/nx-hbmenu",
"sd:/config/sys-patch", "sd:/config/quickntp",
"sd:/config/uberhand", "sd:/config/sys-con",
"sd:/config/ultrahand", "sd:/config/sys-patch",
NULL "sd:/config/uberhand",
}; "sd:/config/ultrahand",
NULL
// Switch directories to delete };
static const char* switch_dirs_to_delete[] = {
"sd:/switch/.overlays", // Switch directories to delete
"sd:/switch/90DNS_tester", static const char* switch_dirs_to_delete[] = {
"sd:/switch/aio-switch-updater", "sd:/switch/.packages",
"sd:/switch/amsPLUS-downloader", "sd:/switch/.overlays",
"sd:/switch/appstore", "sd:/switch/90DNS_tester",
"sd:/switch/AtmoXL-Titel-Installer", "sd:/switch/aio-switch-updater",
"sd:/switch/breeze", "sd:/switch/amsPLUS-downloader",
"sd:/switch/checkpoint", "sd:/switch/appstore",
"sd:/switch/cheats-updater", "sd:/switch/AtmoXL-Titel-Installer",
"sd:/switch/chiaki", "sd:/switch/breeze",
"sd:/switch/ChoiDujourNX", "sd:/switch/checkpoint",
"sd:/switch/crash_ams", "sd:/switch/cheats-updater",
"sd:/switch/Daybreak", "sd:/switch/chiaki",
"sd:/switch/DNS_mitm Tester", "sd:/switch/ChoiDujourNX",
"sd:/switch/EdiZon", "sd:/switch/crash_ams",
"sd:/switch/Fizeau", "sd:/switch/Daybreak",
"sd:/switch/FTPD", "sd:/switch/DNS_mitm Tester",
"sd:/switch/fw-downloader", "sd:/switch/EdiZon",
"sd:/switch/gamecard_installer", "sd:/switch/Fizeau",
"sd:/switch/Goldleaf", "sd:/switch/FTPD",
"sd:/switch/haze", "sd:/switch/fw-downloader",
"sd:/switch/JKSV", "sd:/switch/gamecard_installer",
"sd:/switch/kefir-updater", "sd:/switch/Goldleaf",
"sd:/switch/ldnmitm_config", "sd:/switch/haze",
"sd:/switch/Linkalho", "sd:/switch/JKSV",
"sd:/switch/Moonlight-Switch", "sd:/switch/kefir-updater",
"sd:/switch/Neumann", "sd:/switch/ldnmitm_config",
"sd:/switch/NX-Activity-Log", "sd:/switch/Linkalho",
"sd:/switch/NX-Save-Sync", "sd:/switch/Moonlight-Switch",
"sd:/switch/NX-Shell", "sd:/switch/Neumann",
"sd:/switch/NX-Update-Checker ", "sd:/switch/NX-Activity-Log",
"sd:/switch/NXGallery", "sd:/switch/NX-Save-Sync",
"sd:/switch/NXRemoteLauncher", "sd:/switch/NX-Shell",
"sd:/switch/NXThemesInstaller", "sd:/switch/NX-Update-Checker ",
"sd:/switch/nxdumptool", "sd:/switch/NXGallery",
"sd:/switch/nxmtp", "sd:/switch/NXRemoteLauncher",
"sd:/switch/Payload_launcher", "sd:/switch/NXThemesInstaller",
"sd:/switch/Reboot", "sd:/switch/nxdumptool",
"sd:/switch/reboot_to_argonNX", "sd:/switch/nxmtp",
"sd:/switch/reboot_to_hekate", "sd:/switch/Payload_launcher",
"sd:/switch/Shutdown_System", "sd:/switch/Reboot",
"sd:/switch/SimpleModDownloader", "sd:/switch/reboot_to_argonNX",
"sd:/switch/SimpleModManager", "sd:/switch/reboot_to_hekate",
"sd:/switch/sphaira", "sd:/switch/Shutdown_System",
"sd:/switch/studious-pancake", "sd:/switch/SimpleModDownloader",
"sd:/switch/Switch-Time", "sd:/switch/SimpleModManager",
"sd:/switch/SwitchIdent", "sd:/switch/sphaira",
"sd:/switch/Switch_themes_Installer", "sd:/switch/studious-pancake",
"sd:/switch/Switchfin", "sd:/switch/Switch-Time",
"sd:/switch/Sys-Clk Manager", "sd:/switch/SwitchIdent",
"sd:/switch/Sys-Con", "sd:/switch/Switch_themes_Installer",
"sd:/switch/sys-clk-manager", "sd:/switch/Sys-Clk Manager",
"sd:/switch/themezer-nx", "sd:/switch/Sys-Con",
"sd:/switch/themezernx", "sd:/switch/sys-clk-manager",
"sd:/switch/tinwoo", "sd:/switch/themezer-nx",
NULL "sd:/switch/themezernx",
}; "sd:/switch/tinwoo",
NULL
// Switch files (NRO) to delete };
static const char* switch_files_to_delete[] = {
"sd:/switch/90DNS_tester/90DNS_tester.nro", // Switch files (NRO) to delete
"sd:/switch/breeze.nro", static const char* switch_files_to_delete[] = {
"sd:/switch/cheats-updater.nro", "sd:/switch/90DNS_tester/90DNS_tester.nro",
"sd:/switch/chiaki.nro", "sd:/switch/breeze.nro",
"sd:/switch/ChoiDujourNX.nro", "sd:/switch/cheats-updater.nro",
"sd:/switch/daybreak.nro", "sd:/switch/chiaki.nro",
"sd:/switch/DBI.nro", "sd:/switch/ChoiDujourNX.nro",
"sd:/switch/DBI/DBI.nro", "sd:/switch/daybreak.nro",
"sd:/switch/DBI/DBI_810_DE.nro", "sd:/switch/DBI.nro",
"sd:/switch/DBI/DBI_810_EN.nro", "sd:/switch/DBI/DBI.nro",
"sd:/switch/DBI/DBI_845_DE.nro", "sd:/switch/DBI/DBI_810_DE.nro",
"sd:/switch/DBI/DBI_845_EN.nro", "sd:/switch/DBI/DBI_810_EN.nro",
"sd:/switch/DBI/DBI_849_DE.nro", "sd:/switch/DBI/DBI_845_DE.nro",
"sd:/switch/DBI/DBI_849_EN.nro", "sd:/switch/DBI/DBI_845_EN.nro",
"sd:/switch/DBI_810_DE/DBI_810.nro", "sd:/switch/DBI/DBI_849_DE.nro",
"sd:/switch/DBI_810_DE/DBI_810_DE.nro", "sd:/switch/DBI/DBI_849_EN.nro",
"sd:/switch/DBI_810_EN/DBI_810_EN.nro", "sd:/switch/DBI_810_DE/DBI_810.nro",
"sd:/switch/DBI_RU/DBI_RU.nro", "sd:/switch/DBI_810_DE/DBI_810_DE.nro",
"sd:/switch/DBI/DBI_EN.nro", "sd:/switch/DBI_810_EN/DBI_810_EN.nro",
"sd:/switch/DBI_DE/DBI_DE.nro", "sd:/switch/DBI_RU/DBI_RU.nro",
"sd:/switch/DNS_mitm Tester.nro", "sd:/switch/DBI/DBI_EN.nro",
"sd:/switch/EdiZon.nro", "sd:/switch/DBI_DE/DBI_DE.nro",
"sd:/switch/Fizeau.nro", "sd:/switch/DNS_mitm Tester.nro",
"sd:/switch/Goldleaf.nro", "sd:/switch/EdiZon.nro",
"sd:/switch/haze.nro", "sd:/switch/Fizeau.nro",
"sd:/switch/JKSV.nro", "sd:/switch/Goldleaf.nro",
"sd:/switch/ldnmitm_config.nro", "sd:/switch/haze.nro",
"sd:/switch/linkalho.nro", "sd:/switch/JKSV.nro",
"sd:/switch/Moonlight-Switch.nro", "sd:/switch/ldnmitm_config.nro",
"sd:/switch/Neumann.nro", "sd:/switch/linkalho.nro",
"sd:/switch/NX-Shell.nro", "sd:/switch/Moonlight-Switch.nro",
"sd:/switch/NXGallery.nro", "sd:/switch/Neumann.nro",
"sd:/switch/NXThemesInstaller.nro", "sd:/switch/NX-Shell.nro",
"sd:/switch/nxdumptool.nro", "sd:/switch/NXGallery.nro",
"sd:/switch/nxtc.bin", "sd:/switch/NXThemesInstaller.nro",
"sd:/switch/reboot_to_payload.nro", "sd:/switch/nxdumptool.nro",
"sd:/switch/SimpleModDownloader.nro", "sd:/switch/nxtc.bin",
"sd:/switch/SimpleModManager.nro", "sd:/switch/reboot_to_payload.nro",
"sd:/switch/sphaira.nro", "sd:/switch/SimpleModDownloader.nro",
"sd:/switch/SwitchIdent.nro", "sd:/switch/SimpleModManager.nro",
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro", "sd:/switch/sphaira.nro",
"sd:/switch/Switchfin.nro", "sd:/switch/swr-ini-tool/swr-ini-tool.nro",
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro", "sd:/switch/SwitchIdent.nro",
"sd:/switch/Sys-Con.nro", "sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
"sd:/switch/sys-clk-manager.nro", "sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
"sd:/switch/tinfoil.nro", "sd:/switch/Sys-Con.nro",
"sd:/switch/tinfoil/tinfoil.nro", "sd:/switch/sys-clk-manager.nro",
"sd:/switch/tinwoo.nro", "sd:/switch/tinfoil.nro",
"sd:/switch/tinwoo/tinwoo.nro", "sd:/switch/tinfoil/tinfoil.nro",
NULL "sd:/switch/tinwoo.nro",
}; "sd:/switch/tinwoo/tinwoo.nro",
NULL
// Root CFW files to delete };
static const char* root_files_to_delete[] = {
"sd:/boot.dat", // Root CFW files to delete
"sd:/boot.ini", static const char* root_files_to_delete[] = {
"sd:/exosphere.bin", "sd:/boot.dat",
"sd:/exosphere.ini", "sd:/boot.ini",
"sd:/hbmenu.nro", "sd:/exosphere.bin",
"sd:/install.bat", "sd:/exosphere.ini",
"sd:/license", "sd:/hbmenu.nro",
"sd:/loader.bin", "sd:/install.bat",
"sd:/mc-mitm.log", "sd:/license",
"sd:/payload.bin", "sd:/loader.bin",
"sd:/update.bin", "sd:/mc-mitm.log",
"sd:/version", "sd:/payload.bin",
NULL "sd:/update.bin",
}; "sd:/version",
NULL
// Miscellaneous directories to delete };
static const char* misc_dirs_to_delete[] = {
"sd:/argon", // Miscellaneous directories to delete
"sd:/games", static const char* misc_dirs_to_delete[] = {
"sd:/NSPs (Tools)", "sd:/argon",
"sd:/Patched Apps", "sd:/games",
"sd:/SaltySD/flags", "sd:/NSPs (Tools)",
"sd:/scripts", "sd:/Patched Apps",
"sd:/switch/tinfoil/db", "sd:/SaltySD/flags",
"sd:/tools", "sd:/scripts",
"sd:/warmboot_mariko", "sd:/switch/tinfoil/db",
NULL "sd:/tools",
}; "sd:/warmboot_mariko",
NULL
// Miscellaneous files to delete };
static const char* misc_files_to_delete[] = {
"sd:/fusee-primary.bin", // Miscellaneous files to delete
"sd:/fusee.bin", static const char* misc_files_to_delete[] = {
"sd:/SaltySD/exceptions.txt", "sd:/fusee-primary.bin",
"sd:/SaltySD/saltysd_bootstrap.elf", "sd:/fusee.bin",
"sd:/SaltySD/saltysd_bootstrap32_3k.elf", "sd:/SaltySD/exceptions.txt",
"sd:/SaltySD/saltysd_bootstrap32_5k.elf", "sd:/SaltySD/saltysd_bootstrap.elf",
"sd:/SaltySD/saltysd_core.elf", "sd:/SaltySD/saltysd_bootstrap32_3k.elf",
"sd:/SaltySD/saltysd_core32.elf", "sd:/SaltySD/saltysd_bootstrap32_5k.elf",
NULL "sd:/SaltySD/saltysd_core.elf",
}; "sd:/SaltySD/saltysd_core32.elf",
NULL
};

46
source/dram_fuse.c Normal file
View 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
View 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);

View File

@@ -3,13 +3,21 @@
*/ */
#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 <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 #define GROUPED_DELETE_MAX_ENTRIES 512
@@ -32,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:
@@ -50,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);
} }
} }
@@ -113,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;
@@ -586,11 +635,259 @@ 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(&sections);
if (ini_parse(&sections, (char *)path, false) != 1) {
ram_config_free_sections(&sections);
return RAM_READ_NEED_MENU;
}
bool found = false;
bool eight = false;
LIST_FOREACH_ENTRY(ini_sec_t, sec, &sections, 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(&sections);
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);
}
}
// 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;
if (mode == INSTALL_MODE_UPDATE) { if (mode == INSTALL_MODE_UPDATE) {
if (pack_variant == VARIANT_OC) {
bool had_horizon_cfg = install_path_exists(HORIZON_OC_CONFIG_PATH);
install_set_color(COLOR_YELLOW);
gfx_printf("HorizonOC: Sichere config.ini...\n");
install_set_color(COLOR_WHITE);
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);
}
}
// Update mode: selective cleanup then install // Update mode: selective cleanup then install
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 1: Bereinigung...\n"); gfx_printf("Schritt 1: Bereinigung...\n");
@@ -605,7 +902,29 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = update_mode_install(pack_variant); res = update_mode_install(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
install_hekate_8gb_post_copy();
if (pack_variant == VARIANT_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;
}
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory (installed pack) // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);
@@ -644,7 +963,9 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
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;
install_hekate_8gb_post_copy();
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory (installed pack) // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);

View File

@@ -13,6 +13,9 @@ 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;
// If a sub-menu aborts to Hekate / update.bin (does not return if launch succeeds)
void installer_launch_hekate_payload(void);
// 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);
@@ -35,6 +38,7 @@ 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 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);

View File

@@ -78,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;
@@ -106,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;
@@ -120,29 +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_GREEN); set_color(COLOR_GREEN);
gfx_printf(" Kopie abgeschlossen!\n"); gfx_printf(" Kopie abgeschlossen!\n");

View File

@@ -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"
@@ -113,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);
@@ -180,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) {
@@ -241,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);
} }
@@ -262,13 +279,21 @@ 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;
} }
msleep(50); // Small delay to avoid busy-waiting msleep(50); // Small delay to avoid busy-waiting
} }
@@ -322,12 +347,14 @@ void ipl_main(void) {
gfx_printf("\n"); gfx_printf("\n");
set_color(COLOR_CYAN); set_color(COLOR_CYAN);
gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n"); gfx_printf("D-Pad / Vol+/-: Auswahl | A oder Power: Bestaetigen\n");
gfx_printf("Vol+ und Vol- gleichzeitig: Abbrechen (Hekate)\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
// Edge detection: only move on press (not while held) // Edge detection: only move on press (not while held)
bool prev_up = false, prev_down = false; bool prev_up = false, prev_down = false;
bool menu_aborted = false;
while (!confirmed) { while (!confirmed && !menu_aborted) {
// On selection change: redraw only the two affected lines (no full clear) // On selection change: redraw only the two affected lines (no full clear)
if (selected != prev_selected) { if (selected != prev_selected) {
gfx_con_setpos(menu_x, menu_variant_start_y + (u32)prev_selected * 16); gfx_con_setpos(menu_x, menu_variant_start_y + (u32)prev_selected * 16);
@@ -343,6 +370,14 @@ void ipl_main(void) {
jc_gamepad_rpt_t *jc = joycon_poll(); jc_gamepad_rpt_t *jc = joycon_poll();
u8 btn = btn_read(); 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) // D-pad or Vol+ / Vol- for selection (Vol+ = up, Vol- = down)
bool cur_up = false, cur_down = false; bool cur_up = false, cur_down = false;
if (jc) { if (jc) {
@@ -367,6 +402,20 @@ void ipl_main(void) {
msleep(50); 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]; pack_variant = variants_present[selected];
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
@@ -376,6 +425,139 @@ void ipl_main(void) {
// 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");
@@ -400,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);
@@ -437,14 +645,15 @@ void ipl_main(void) {
gfx_printf("Installation wird gestartet...\n"); gfx_printf("Installation wird gestartet...\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
set_color(COLOR_ORANGE); set_color(COLOR_ORANGE);
gfx_printf("Hinweis: Manchmal könnte es hängen. Einfach warten.\n\n"); 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);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
@@ -496,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
@@ -538,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);

View File

@@ -1,228 +1,233 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018-2019 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation. * version 2, as published by the Free Software Foundation.
* *
* This program is distributed in the hope it will be useful, but WITHOUT * This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <storage/nx_sd.h> #include <storage/nx_sd.h>
#include <storage/sdmmc.h> #include <storage/sdmmc.h>
#include <storage/sdmmc_driver.h> #include <storage/sdmmc_driver.h>
#include <gfx_utils.h> #include <gfx_utils.h>
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <mem/heap.h> #include <mem/heap.h>
bool sd_mounted = false; bool sd_mounted = false;
static u16 sd_errors[3] = { 0 }; // Init and Read/Write errors. static u16 sd_errors[3] = { 0 }; // Init and Read/Write errors.
static u32 sd_mode = SD_UHS_SDR82; static u32 sd_mode = SD_UHS_SDR82;
sdmmc_t sd_sdmmc; sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage; sdmmc_storage_t sd_storage;
FATFS sd_fs; FATFS sd_fs;
void sd_error_count_increment(u8 type) void sd_error_count_increment(u8 type)
{ {
switch (type) switch (type)
{ {
case SD_ERROR_INIT_FAIL: case SD_ERROR_INIT_FAIL:
sd_errors[0]++; sd_errors[0]++;
break; break;
case SD_ERROR_RW_FAIL: case SD_ERROR_RW_FAIL:
sd_errors[1]++; sd_errors[1]++;
break; break;
case SD_ERROR_RW_RETRY: case SD_ERROR_RW_RETRY:
sd_errors[2]++; sd_errors[2]++;
break; break;
} }
} }
u16 *sd_get_error_count() u16 *sd_get_error_count()
{ {
return sd_errors; return sd_errors;
} }
bool sd_get_card_removed() bool sd_get_card_removed()
{ {
if (!sdmmc_get_sd_inserted()) if (!sdmmc_get_sd_inserted())
return true; return true;
return false; return false;
} }
u32 sd_get_mode() u32 sd_get_mode()
{ {
return sd_mode; return sd_mode;
} }
int sd_init_retry(bool power_cycle) int sd_init_retry(bool power_cycle)
{ {
u32 bus_width = SDMMC_BUS_WIDTH_4; u32 bus_width = SDMMC_BUS_WIDTH_4;
u32 type = SDHCI_TIMING_UHS_SDR82; u32 type = SDHCI_TIMING_UHS_SDR82;
// Power cycle SD card. // Power cycle SD card.
if (power_cycle) if (power_cycle)
{ {
sd_mode--; sd_mode--;
sdmmc_storage_end(&sd_storage); sdmmc_storage_end(&sd_storage);
} }
// Get init parameters. // Get init parameters.
switch (sd_mode) switch (sd_mode)
{ {
case SD_INIT_FAIL: // Reset to max. case SD_INIT_FAIL: // Reset to max.
return 0; return 0;
case SD_1BIT_HS25: case SD_1BIT_HS25:
bus_width = SDMMC_BUS_WIDTH_1; bus_width = SDMMC_BUS_WIDTH_1;
type = SDHCI_TIMING_SD_HS25; type = SDHCI_TIMING_SD_HS25;
break; break;
case SD_4BIT_HS25: case SD_4BIT_HS25:
type = SDHCI_TIMING_SD_HS25; type = SDHCI_TIMING_SD_HS25;
break; break;
case SD_UHS_SDR82: case SD_UHS_SDR82:
type = SDHCI_TIMING_UHS_SDR82; type = SDHCI_TIMING_UHS_SDR82;
break; break;
default: default:
sd_mode = SD_UHS_SDR82; sd_mode = SD_UHS_SDR82;
} }
return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type); return sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, bus_width, type);
} }
bool sd_initialize(bool power_cycle) bool sd_initialize(bool power_cycle)
{ {
if (power_cycle) if (power_cycle)
sdmmc_storage_end(&sd_storage); sdmmc_storage_end(&sd_storage);
int res = !sd_init_retry(false); int res = !sd_init_retry(false);
while (true) while (true)
{ {
if (!res) if (!res)
return true; return true;
else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted. else if (!sdmmc_get_sd_inserted()) // SD Card is not inserted.
{ {
sd_mode = SD_UHS_SDR82; sd_mode = SD_UHS_SDR82;
break; break;
} }
else else
{ {
sd_errors[SD_ERROR_INIT_FAIL]++; sd_errors[SD_ERROR_INIT_FAIL]++;
if (sd_mode == SD_INIT_FAIL) if (sd_mode == SD_INIT_FAIL)
break; break;
else else
res = !sd_init_retry(true); res = !sd_init_retry(true);
} }
} }
sdmmc_storage_end(&sd_storage); sdmmc_storage_end(&sd_storage);
return false; return false;
} }
bool is_sd_inited = false; bool is_sd_inited = false;
bool sd_mount() bool sd_mount()
{ {
if (sd_mounted) if (sd_mounted)
return true; return true;
int res = !sd_initialize(false); int res = !sd_initialize(false);
is_sd_inited = !res; is_sd_inited = !res;
if (res) if (res)
{ {
gfx_con.mute = false; gfx_con.mute = false;
EPRINTF("Failed to init SD card."); EPRINTF("Failed to init SD card.");
if (!sdmmc_get_sd_inserted()) if (!sdmmc_get_sd_inserted())
EPRINTF("Make sure that it is inserted."); EPRINTF("Make sure that it is inserted.");
else else
EPRINTF("SD Card Reader is not properly seated!"); EPRINTF("SD Card Reader is not properly seated!");
} }
else else
{ {
res = f_mount(&sd_fs, "", 1); res = f_mount(&sd_fs, "", 1);
if (res == FR_OK) if (res == FR_OK)
{ {
sd_mounted = true; sd_mounted = true;
return true; return true;
} }
else else
{ {
gfx_con.mute = false; gfx_con.mute = false;
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res); EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
} }
} }
return false; return false;
} }
static void _sd_deinit() static void _sd_deinit()
{ {
if (sd_mode == SD_INIT_FAIL) if (sd_mode == SD_INIT_FAIL)
sd_mode = SD_UHS_SDR82; sd_mode = SD_UHS_SDR82;
if (sd_mounted) if (sd_mounted)
{ {
f_mount(NULL, "", 1); f_mount(NULL, "", 1);
sdmmc_storage_end(&sd_storage); sdmmc_storage_end(&sd_storage);
sd_mounted = false; sd_mounted = false;
is_sd_inited = false; is_sd_inited = false;
} }
} }
void sd_unmount() { _sd_deinit(); } void sd_unmount() { _sd_deinit(); }
void sd_end() { _sd_deinit(); } void sd_end() { _sd_deinit(); }
void *sd_file_read(const char *path, u32 *fsize) bool sd_get_card_mounted(void)
{ {
FIL fp; return sd_mounted;
if (f_open(&fp, path, FA_READ) != FR_OK) }
return NULL;
void *sd_file_read(const char *path, u32 *fsize)
u32 size = f_size(&fp); {
if (fsize) FIL fp;
*fsize = size; if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
char *buf = malloc(size + 1);
buf[size] = '\0'; u32 size = f_size(&fp);
if (fsize)
if (f_read(&fp, buf, size, NULL) != FR_OK) *fsize = size;
{
free(buf); char *buf = malloc(size + 1);
f_close(&fp); buf[size] = '\0';
return NULL; if (f_read(&fp, buf, size, NULL) != FR_OK)
} {
free(buf);
f_close(&fp); f_close(&fp);
return buf; return NULL;
} }
int sd_save_to_file(void *buf, u32 size, const char *filename) f_close(&fp);
{
FIL fp; return buf;
u32 res = 0; }
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res) int sd_save_to_file(void *buf, u32 size, const char *filename)
{ {
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename); FIL fp;
return res; u32 res = 0;
} res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
f_write(&fp, buf, size, NULL); {
f_close(&fp); EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
return 0; }
}
f_write(&fp, buf, size, NULL);
f_close(&fp);
return 0;
}

111
source/screenshot.c Normal file
View 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
View 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);

70
tools/ram_test_main.c Normal file
View 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);
}