mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Cherry-pick improvements from the rewrite-yoga branch.
This commit is contained in:
parent
4453e7950f
commit
4d1b3660c3
14 changed files with 460 additions and 222 deletions
18
Makefile
18
Makefile
|
@ -40,6 +40,11 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
GIT_COMMIT := $(shell git rev-parse --short HEAD)
|
||||
GIT_REV := ${GIT_BRANCH}-${GIT_COMMIT}
|
||||
|
||||
ifneq (, $(strip $(shell git status --porcelain 2>/dev/null)))
|
||||
GIT_REV := $(GIT_REV)-dirty
|
||||
endif
|
||||
|
||||
VERSION_MAJOR := 2
|
||||
VERSION_MINOR := 0
|
||||
|
@ -49,6 +54,7 @@ APP_TITLE := nxdumptool
|
|||
APP_AUTHOR := DarkMatterCore
|
||||
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}
|
||||
|
||||
# TODO: remove this after the PoC builds are no longer needed.
|
||||
ifneq ($(origin BUILD_TYPE),undefined)
|
||||
APP_TITLE := ${BUILD_TYPE}
|
||||
endif
|
||||
|
@ -61,11 +67,11 @@ ICON := romfs/icon/${APP_TITLE}.jpg
|
|||
INCLUDES := include include/core include/fatfs
|
||||
ROMFS := romfs
|
||||
|
||||
USBHSFS_PATH := $(TOPDIR)/libs/libusbhsfs
|
||||
|
||||
BOREALIS_PATH := libs/borealis
|
||||
BOREALIS_RESOURCES := romfs:/
|
||||
|
||||
USBHSFS_PATH := $(TOPDIR)/libs/libusbhsfs
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
@ -74,12 +80,11 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
|||
CFLAGS := -g -Wall -Werror -O2 -ffunction-sections $(ARCH) $(DEFINES) $(INCLUDE) -D__SWITCH__
|
||||
CFLAGS += -DVERSION_MAJOR=${VERSION_MAJOR} -DVERSION_MINOR=${VERSION_MINOR} -DVERSION_MICRO=${VERSION_MICRO}
|
||||
CFLAGS += -DAPP_TITLE=\"${APP_TITLE}\" -DAPP_AUTHOR=\"${APP_AUTHOR}\" -DAPP_VERSION=\"${APP_VERSION}\"
|
||||
CFLAGS += -DGIT_BRANCH=\"${GIT_BRANCH}\" -DGIT_COMMIT=\"${GIT_COMMIT}\"
|
||||
CFLAGS += -DGIT_BRANCH=\"${GIT_BRANCH}\" -DGIT_COMMIT=\"${GIT_COMMIT}\" -DGIT_REV=\"${GIT_REV}\"
|
||||
CFLAGS += -DBOREALIS_RESOURCES="\"${BOREALIS_RESOURCES}\""
|
||||
CFLAGS += `aarch64-none-elf-pkg-config zlib --cflags`
|
||||
CFLAGS += `aarch64-none-elf-pkg-config libxml-2.0 --cflags`
|
||||
CFLAGS += `aarch64-none-elf-pkg-config json-c --cflags`
|
||||
CFLAGS += `aarch64-none-elf-pkg-config libturbojpeg --cflags`
|
||||
#CFLAGS += `aarch64-none-elf-pkg-config json-c --cflags`
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20 -O2 -Wno-volatile -Wno-unused-parameter
|
||||
|
||||
|
@ -87,6 +92,7 @@ ASFLAGS := -g $(ARCH)
|
|||
LDFLAGS := -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -lxml2 -lz -lusbhsfs -lntfs-3g -llwext4 -lnx
|
||||
#LIBS += -ljson-c
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
|
@ -183,7 +189,7 @@ ifneq ($(ROMFS),)
|
|||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean clean_all all
|
||||
.PHONY: $(BUILD) all clean clean_all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
|
|
@ -264,7 +264,7 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
|
|||
consolePrint("%s #%u initialize nca ctx succeeded\n", titleGetNcmContentTypeName(content_info->content_type), content_info->id_offset);
|
||||
|
||||
// don't go any further with this nca if we can't access its fs data because it's pointless
|
||||
// to do: add preload warning
|
||||
// TODO: add preload warning
|
||||
if (cur_nca_ctx->rights_id_available && !cur_nca_ctx->titlekey_retrieved)
|
||||
{
|
||||
j++;
|
||||
|
|
|
@ -254,7 +254,7 @@ static void dump_thread_func(void *arg)
|
|||
consolePrint("%s #%u initialize nca ctx succeeded\n", titleGetNcmContentTypeName(content_info->content_type), content_info->id_offset);
|
||||
|
||||
// don't go any further with this nca if we can't access its fs data because it's pointless
|
||||
// to do: add preload warning
|
||||
// TODO: add preload warning
|
||||
if (cur_nca_ctx->rights_id_available && !cur_nca_ctx->titlekey_retrieved)
|
||||
{
|
||||
j++;
|
||||
|
|
44
include/core/nxdt_bfsar.h
Normal file
44
include/core/nxdt_bfsar.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* nxdt_bfsar.h
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __NXDT_BFSAR_H__
|
||||
#define __NXDT_BFSAR_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Initializes the BFSAR interface.
|
||||
bool bfsarInitialize(void);
|
||||
|
||||
/// Closes the BFSAR interface.
|
||||
void bfsarExit(void);
|
||||
|
||||
/// Returns a pointer to the BFSAR file path.
|
||||
const char *bfsarGetFilePath(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NXDT_BFSAR_H__ */
|
|
@ -61,6 +61,7 @@
|
|||
#define SPL_SYSMODULE_TID (u64)0x0100000000000028
|
||||
#define ES_SYSMODULE_TID (u64)0x0100000000000033
|
||||
#define SYSTEM_UPDATE_TID (u64)0x0100000000000816
|
||||
#define QLAUNCH_TID (u64)0x0100000000001000
|
||||
|
||||
#define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */
|
||||
|
||||
|
|
|
@ -33,18 +33,18 @@ namespace nxdt::views
|
|||
private:
|
||||
bool applet_mode = false;
|
||||
|
||||
brls::Label *applet_mode_lbl = nullptr;
|
||||
brls::Label *time_lbl = nullptr;
|
||||
brls::Label *battery_icon = nullptr, *battery_percentage = nullptr;
|
||||
brls::Label *connection_icon = nullptr, *connection_status_lbl = nullptr;
|
||||
|
||||
nxdt::tasks::StatusInfoTask *status_info_task = nullptr;
|
||||
nxdt::tasks::GameCardTask *gc_status_task = nullptr;
|
||||
nxdt::tasks::TitleTask *title_task = nullptr;
|
||||
nxdt::tasks::UmsTask *ums_task = nullptr;
|
||||
nxdt::tasks::UsbHostTask *usb_host_task = nullptr;
|
||||
|
||||
nxdt::tasks::VoidEvent::Subscription status_info_task_sub;
|
||||
|
||||
brls::Label *applet_mode_lbl = nullptr;
|
||||
brls::Label *time_lbl = nullptr;
|
||||
brls::Label *battery_icon = nullptr, *battery_percentage = nullptr;
|
||||
brls::Label *connection_icon = nullptr, *connection_status_lbl = nullptr;
|
||||
nxdt::tasks::StatusInfoEvent::Subscription status_info_task_sub;
|
||||
|
||||
protected:
|
||||
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
|
||||
|
|
|
@ -33,32 +33,35 @@
|
|||
|
||||
namespace nxdt::tasks
|
||||
{
|
||||
/* Custom event types used by the tasks defined below. */
|
||||
typedef brls::Event<GameCardStatus> GameCardStatusEvent;
|
||||
typedef brls::VoidEvent VoidEvent;
|
||||
typedef brls::Event<bool> BooleanEvent;
|
||||
/* Used to hold status info data. */
|
||||
typedef struct {
|
||||
struct tm *timeinfo;
|
||||
u32 charge_percentage;
|
||||
PsmChargerType charger_type;
|
||||
NifmInternetConnectionType connection_type;
|
||||
char *ip_addr;
|
||||
} StatusInfoData;
|
||||
|
||||
/* Custom vector type used to hold pointers to application metadata entries. */
|
||||
/* Used to hold pointers to application metadata entries. */
|
||||
typedef std::vector<TitleApplicationMetadata*> TitleApplicationMetadataVector;
|
||||
|
||||
/* Custom vector type used to hold UMS devices. */
|
||||
/* Used to hold UMS devices. */
|
||||
typedef std::vector<UsbHsFsDevice> UmsDeviceVector;
|
||||
|
||||
/* Custom event types. */
|
||||
typedef brls::Event<const StatusInfoData*> StatusInfoEvent;
|
||||
typedef brls::Event<GameCardStatus> GameCardStatusEvent;
|
||||
typedef brls::Event<const TitleApplicationMetadataVector*> TitleEvent;
|
||||
typedef brls::Event<const UmsDeviceVector*> UmsEvent;
|
||||
typedef brls::Event<bool> UsbHostEvent;
|
||||
|
||||
/* Status info task. */
|
||||
/* Its event returns a pointer to a StatusInfoData struct. */
|
||||
class StatusInfoTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
VoidEvent status_info_event;
|
||||
|
||||
std::string cur_time = "";
|
||||
|
||||
u32 charge_percentage = 0;
|
||||
PsmChargerType charger_type = PsmChargerType_Unconnected;
|
||||
|
||||
NifmInternetConnectionType connection_type = (NifmInternetConnectionType)0;
|
||||
u32 signal_strength = 0;
|
||||
NifmInternetConnectionStatus connection_status = (NifmInternetConnectionStatus)0;
|
||||
char *ip_addr = NULL;
|
||||
StatusInfoEvent status_info_event;
|
||||
StatusInfoData status_info_data = {0};
|
||||
|
||||
protected:
|
||||
void run(retro_time_t current_time) override;
|
||||
|
@ -67,27 +70,23 @@ namespace nxdt::tasks
|
|||
StatusInfoTask(void);
|
||||
~StatusInfoTask(void);
|
||||
|
||||
std::string GetCurrentTimeString(void);
|
||||
void GetBatteryStats(u32 *out_charge_percentage, PsmChargerType *out_charger_type);
|
||||
void GetNetworkStats(NifmInternetConnectionType *out_connection_type, u32 *out_signal_strength, NifmInternetConnectionStatus *out_connection_status, char **out_ip_addr);
|
||||
|
||||
ALWAYS_INLINE VoidEvent::Subscription RegisterListener(VoidEvent::Callback cb)
|
||||
ALWAYS_INLINE StatusInfoEvent::Subscription RegisterListener(StatusInfoEvent::Callback cb)
|
||||
{
|
||||
return this->status_info_event.subscribe(cb);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnregisterListener(VoidEvent::Subscription subscription)
|
||||
ALWAYS_INLINE void UnregisterListener(StatusInfoEvent::Subscription subscription)
|
||||
{
|
||||
this->status_info_event.unsubscribe(subscription);
|
||||
}
|
||||
};
|
||||
|
||||
/* Gamecard task. */
|
||||
/* Its event returns a GameCardStatus value. */
|
||||
class GameCardTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
GameCardStatusEvent gc_status_event;
|
||||
|
||||
GameCardStatus cur_gc_status = GameCardStatus_NotInserted;
|
||||
GameCardStatus prev_gc_status = GameCardStatus_NotInserted;
|
||||
|
||||
|
@ -110,10 +109,11 @@ namespace nxdt::tasks
|
|||
};
|
||||
|
||||
/* Title task. */
|
||||
/* Its event returns a pointer to a TitleApplicationMetadataVector with metadata for user titles (system titles don't change at runtime). */
|
||||
class TitleTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
VoidEvent title_event;
|
||||
TitleEvent title_event;
|
||||
|
||||
TitleApplicationMetadataVector system_metadata;
|
||||
TitleApplicationMetadataVector user_metadata;
|
||||
|
@ -127,24 +127,26 @@ namespace nxdt::tasks
|
|||
TitleTask(void);
|
||||
~TitleTask(void);
|
||||
|
||||
/* Intentionally left here to let system titles views retrieve metadata. */
|
||||
TitleApplicationMetadataVector* GetApplicationMetadata(bool is_system);
|
||||
|
||||
ALWAYS_INLINE VoidEvent::Subscription RegisterListener(VoidEvent::Callback cb)
|
||||
ALWAYS_INLINE TitleEvent::Subscription RegisterListener(TitleEvent::Callback cb)
|
||||
{
|
||||
return this->title_event.subscribe(cb);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnregisterListener(VoidEvent::Subscription subscription)
|
||||
ALWAYS_INLINE void UnregisterListener(TitleEvent::Subscription subscription)
|
||||
{
|
||||
this->title_event.unsubscribe(subscription);
|
||||
}
|
||||
};
|
||||
|
||||
/* USB Mass Storage task. */
|
||||
/* Its event returns a pointer to a UmsDeviceVector. */
|
||||
class UmsTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
VoidEvent ums_event;
|
||||
UmsEvent ums_event;
|
||||
|
||||
UmsDeviceVector ums_devices;
|
||||
|
||||
|
@ -157,14 +159,12 @@ namespace nxdt::tasks
|
|||
UmsTask(void);
|
||||
~UmsTask(void);
|
||||
|
||||
UmsDeviceVector* GetUmsDevices(void);
|
||||
|
||||
ALWAYS_INLINE VoidEvent::Subscription RegisterListener(VoidEvent::Callback cb)
|
||||
ALWAYS_INLINE UmsEvent::Subscription RegisterListener(UmsEvent::Callback cb)
|
||||
{
|
||||
return this->ums_event.subscribe(cb);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnregisterListener(VoidEvent::Subscription subscription)
|
||||
ALWAYS_INLINE void UnregisterListener(UmsEvent::Subscription subscription)
|
||||
{
|
||||
this->ums_event.unsubscribe(subscription);
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ namespace nxdt::tasks
|
|||
class UsbHostTask: public brls::RepeatingTask
|
||||
{
|
||||
private:
|
||||
BooleanEvent usb_host_event;
|
||||
UsbHostEvent usb_host_event;
|
||||
|
||||
bool cur_usb_host_status = false;
|
||||
bool prev_usb_host_status = false;
|
||||
|
@ -186,12 +186,12 @@ namespace nxdt::tasks
|
|||
UsbHostTask(void);
|
||||
~UsbHostTask(void);
|
||||
|
||||
ALWAYS_INLINE BooleanEvent::Subscription RegisterListener(BooleanEvent::Callback cb)
|
||||
ALWAYS_INLINE UsbHostEvent::Subscription RegisterListener(UsbHostEvent::Callback cb)
|
||||
{
|
||||
return this->usb_host_event.subscribe(cb);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnregisterListener(BooleanEvent::Subscription subscription)
|
||||
ALWAYS_INLINE void UnregisterListener(UsbHostEvent::Subscription subscription)
|
||||
{
|
||||
this->usb_host_event.unsubscribe(subscription);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
{
|
||||
"__comment__": "Comments about how specific fields work use keys that follow the '__{field}_comment__' format. These don't have to be replicated in your translation files.",
|
||||
|
||||
"applet_mode": "\uE8B2 Applet Mode \uE8B2",
|
||||
|
||||
"time_format": "12",
|
||||
"__time_format_comment__": "Use 12 for a 12-hour clock, or 24 for a 24-hour clock",
|
||||
|
||||
"date": "{1:02d}/{2:02d}/{0} {3:02d}:{4:02d}:{5:02d} {6}",
|
||||
"__date_comment__": "{0} = Year, {1} = Month, {2} = Day, {3} = Hour, {4} = Minute, {5} = Second, {6} = AM/PM (if time_format is set to 12)",
|
||||
|
||||
"not_connected": "Not connected",
|
||||
|
||||
|
|
204
source/core/nxdt_bfsar.c
Normal file
204
source/core/nxdt_bfsar.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* nxdt_bfsar.c
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "nxdt_utils.h"
|
||||
#include "nxdt_bfsar.h"
|
||||
#include "romfs.h"
|
||||
#include "title.h"
|
||||
|
||||
#define BFSAR_FILENAME "qlaunch.bfsar"
|
||||
#define BFSAR_ROMFS_PATH "/sound/" BFSAR_FILENAME
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static Mutex g_bfsarMutex = 0;
|
||||
static bool g_bfsarInterfaceInit = false;
|
||||
|
||||
static char g_bfsarPath[FS_MAX_PATH] = {0};
|
||||
|
||||
bool bfsarInitialize(void)
|
||||
{
|
||||
bool use_root = true;
|
||||
const char *launch_path = utilsGetLaunchPath();
|
||||
char *ptr1 = NULL, *ptr2 = NULL;
|
||||
|
||||
TitleInfo *title_info = NULL;
|
||||
|
||||
NcaContext *nca_ctx = NULL;
|
||||
|
||||
RomFileSystemContext romfs_ctx = {0};
|
||||
RomFileSystemFileEntry *romfs_file_entry = NULL;
|
||||
|
||||
FILE *bfsar_file = NULL;
|
||||
u8 *bfsar_data = NULL;
|
||||
size_t bfsar_size = 0, wr = 0;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
SCOPED_LOCK(&g_bfsarMutex)
|
||||
{
|
||||
ret = g_bfsarInterfaceInit;
|
||||
if (ret) break;
|
||||
|
||||
/* Generate BFSAR file path. */
|
||||
if (launch_path)
|
||||
{
|
||||
ptr1 = strchr(launch_path, '/');
|
||||
ptr2 = strrchr(launch_path, '/');
|
||||
|
||||
if (ptr1 && ptr2 && ptr1 != ptr2)
|
||||
{
|
||||
/* Create BFSAR file in the current working directory. */
|
||||
snprintf(g_bfsarPath, sizeof(g_bfsarPath), "%.*s" BFSAR_FILENAME, (int)((ptr2 - ptr1) + 1), ptr1);
|
||||
use_root = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create BFSAR file in the SD card root directory. */
|
||||
if (use_root) sprintf(g_bfsarPath, "/" BFSAR_FILENAME);
|
||||
|
||||
LOG_MSG("BFSAR path: \"%s\".", g_bfsarPath);
|
||||
|
||||
/* Check if the BFSAR file is already available and not empty. */
|
||||
bfsar_file = fopen(g_bfsarPath, "rb");
|
||||
if (bfsar_file)
|
||||
{
|
||||
fseek(bfsar_file, 0, SEEK_END);
|
||||
bfsar_size = ftell(bfsar_file);
|
||||
if (bfsar_size)
|
||||
{
|
||||
ret = g_bfsarInterfaceInit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get title info. */
|
||||
if (!(title_info = titleGetInfoFromStorageByTitleId(NcmStorageId_BuiltInSystem, QLAUNCH_TID)))
|
||||
{
|
||||
LOG_MSG("Failed to get title info for qlaunch!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate memory for a temporary NCA context. */
|
||||
nca_ctx = calloc(1, sizeof(NcaContext));
|
||||
if (!nca_ctx)
|
||||
{
|
||||
LOG_MSG("Failed to allocate memory for temporary NCA context!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize NCA context. */
|
||||
if (!ncaInitializeContext(nca_ctx, NcmStorageId_BuiltInSystem, 0, titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Program, 0), NULL))
|
||||
{
|
||||
LOG_MSG("Failed to initialize qlaunch Program NCA context!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize RomFS context. */
|
||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[1])))
|
||||
{
|
||||
LOG_MSG("Failed to initialize RomFS context for qlaunch Program NCA!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get RomFS file entry. */
|
||||
if (!(romfs_file_entry = romfsGetFileEntryByPath(&romfs_ctx, BFSAR_ROMFS_PATH)))
|
||||
{
|
||||
LOG_MSG("Failed to retrieve RomFS file entry for \"" BFSAR_ROMFS_PATH "\"!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check file size. */
|
||||
bfsar_size = romfs_file_entry->size;
|
||||
if (!bfsar_size)
|
||||
{
|
||||
LOG_MSG("File size for qlaunch's \"" BFSAR_ROMFS_PATH "\" is zero!");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate memory for BFSAR data. */
|
||||
if (!(bfsar_data = malloc(bfsar_size)))
|
||||
{
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for qlaunch's \"" BFSAR_ROMFS_PATH "\"!", bfsar_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read BFSAR data. */
|
||||
if (!romfsReadFileEntryData(&romfs_ctx, romfs_file_entry, bfsar_data, bfsar_size, 0))
|
||||
{
|
||||
LOG_MSG("Failed to read 0x%lX bytes long \"" BFSAR_ROMFS_PATH "\" from qlaunch!", bfsar_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create BFSAR file. */
|
||||
bfsar_file = fopen(g_bfsarPath, "wb");
|
||||
if (!bfsar_file)
|
||||
{
|
||||
LOG_MSG("Failed to open \"%s\" for writing!", g_bfsarPath);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write BFSAR data. */
|
||||
wr = fwrite(bfsar_data, 1, bfsar_size, bfsar_file);
|
||||
if (wr != bfsar_size)
|
||||
{
|
||||
LOG_MSG("Failed to write 0x%lX bytes block to \"%s\"!", bfsar_size, g_bfsarPath);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update flags. */
|
||||
ret = g_bfsarInterfaceInit = true;
|
||||
}
|
||||
|
||||
if (bfsar_file) fclose(bfsar_file);
|
||||
|
||||
if (bfsar_data) free(bfsar_data);
|
||||
|
||||
romfsFreeContext(&romfs_ctx);
|
||||
|
||||
if (nca_ctx) free(nca_ctx);
|
||||
|
||||
titleFreeTitleInfo(&title_info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bfsarExit(void)
|
||||
{
|
||||
SCOPED_LOCK(&g_bfsarMutex)
|
||||
{
|
||||
/* Clear BFSAR file path. */
|
||||
*g_bfsarPath = '\0';
|
||||
g_bfsarInterfaceInit = false;
|
||||
}
|
||||
}
|
||||
|
||||
const char *bfsarGetFilePath(void)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
|
||||
SCOPED_TRY_LOCK(&g_bfsarMutex)
|
||||
{
|
||||
if (g_bfsarInterfaceInit) ret = (const char*)g_bfsarPath;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
#include "usb.h"
|
||||
#include "title.h"
|
||||
#include "bfttf.h"
|
||||
#include "nxdt_bfsar.h"
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
/* Reference: https://docs.microsoft.com/en-us/windows/win32/fileio/filesystem-functionality-comparison#limits. */
|
||||
|
@ -86,7 +87,7 @@ static size_t utilsGetUtf8CodepointCount(const char *str, size_t str_size, size_
|
|||
bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
||||
{
|
||||
Result rc = 0;
|
||||
bool ret = false;
|
||||
bool ret = false, flag = false;
|
||||
|
||||
SCOPED_LOCK(&g_resourcesMutex)
|
||||
{
|
||||
|
@ -105,7 +106,7 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
|||
|
||||
/* Create logfile. */
|
||||
logWriteStringToLogFile("________________________________________________________________\r\n");
|
||||
LOG_MSG(APP_TITLE " v%u.%u.%u starting (" GIT_COMMIT "). Built on " __DATE__ " - " __TIME__ ".", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||
LOG_MSG(APP_TITLE " v%u.%u.%u starting (" GIT_REV "). Built on " __DATE__ " - " __TIME__ ".", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||
if (g_appLaunchPath) LOG_MSG("Launch path: \"%s\".", g_appLaunchPath);
|
||||
|
||||
/* Log Horizon OS version. */
|
||||
|
@ -153,10 +154,18 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
|||
/* Initialize BFTTF interface. */
|
||||
if (!bfttfInitialize()) break;
|
||||
|
||||
/* Initialize BFSAR interface. */
|
||||
//if (!bfsarInitialize()) break;
|
||||
|
||||
/* Mount eMMC BIS System partition. */
|
||||
if (!utilsMountEmmcBisSystemPartitionStorage()) break;
|
||||
|
||||
/* Enable video recording. */
|
||||
rc = appletIsGamePlayRecordingSupported(&flag);
|
||||
if (R_SUCCEEDED(rc) && flag) appletInitializeGamePlayRecording();
|
||||
|
||||
/* Disable screen dimming and auto sleep. */
|
||||
/* TODO: only use this function right before starting a dump procedure - make sure to handle power button presses as well. */
|
||||
appletSetMediaPlaybackState(true);
|
||||
|
||||
/* Overclock system. */
|
||||
|
@ -212,6 +221,9 @@ void utilsCloseResources(void)
|
|||
/* Unmount eMMC BIS System partition. */
|
||||
utilsUnmountEmmcBisSystemPartitionStorage();
|
||||
|
||||
/* Deinitialize BFSAR interface. */
|
||||
bfsarExit();
|
||||
|
||||
/* Deinitialize BFTTF interface. */
|
||||
bfttfExit();
|
||||
|
||||
|
|
|
@ -972,17 +972,21 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
TitleInfo **titles = title_storage->titles;
|
||||
u32 title_count = title_storage->title_count;
|
||||
|
||||
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || !titles || !title_count || name_convention > TitleFileNameConvention_IdAndVersionOnly || \
|
||||
GameCardHeader gc_header = {0};
|
||||
size_t cur_filename_len = 0;
|
||||
char app_name[0x400] = {0};
|
||||
bool error = false;
|
||||
|
||||
if (!g_titleInterfaceInit || !g_titleGameCardAvailable || name_convention > TitleFileNameConvention_IdAndVersionOnly || \
|
||||
(name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
break;
|
||||
}
|
||||
|
||||
GameCardHeader gc_header = {0};
|
||||
size_t cur_filename_len = 0;
|
||||
char app_name[0x400] = {0};
|
||||
bool error = false;
|
||||
/* Check if the gamecard title storage is empty. */
|
||||
/* This is especially true for Kiosk / Quest gamecards. */
|
||||
if (!titles || !title_count) goto fallback;
|
||||
|
||||
for(u32 i = 0; i < title_count; i++)
|
||||
{
|
||||
|
@ -1058,12 +1062,12 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
cur_filename_len += app_name_len;
|
||||
}
|
||||
|
||||
fallback:
|
||||
if (!filename && !error)
|
||||
{
|
||||
LOG_MSG("Error: the inserted gamecard doesn't hold any user applications!");
|
||||
|
||||
/* Fallback string if no applications can be found. */
|
||||
/* This function is guaranteed to fail with Kiosk / Quest gamecards, so that's why this is needed. */
|
||||
sprintf(app_name, "gamecard");
|
||||
|
||||
if (gamecardGetHeader(&gc_header))
|
||||
|
@ -1074,6 +1078,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
}
|
||||
|
||||
filename = strdup(app_name);
|
||||
if (!filename) LOG_MSG("Failed to duplicate fallback filename!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1093,11 +1098,16 @@ const char *titleGetNcmContentMetaTypeName(u8 content_meta_type)
|
|||
|
||||
NX_INLINE void titleFreeApplicationMetadata(void)
|
||||
{
|
||||
if (g_systemMetadata)
|
||||
for(u8 i = 0; i < 2; i++)
|
||||
{
|
||||
for(u32 i = 0; i < g_systemMetadataCount; i++)
|
||||
TitleApplicationMetadata **cached_app_metadata = (i == 0 ? g_systemMetadata : g_userMetadata);
|
||||
u32 cached_app_metadata_count = (i == 0 ? g_systemMetadataCount : g_userMetadataCount);
|
||||
|
||||
if (cached_app_metadata)
|
||||
{
|
||||
TitleApplicationMetadata *cur_app_metadata = g_systemMetadata[i];
|
||||
for(u32 j = 0; j < cached_app_metadata_count; j++)
|
||||
{
|
||||
TitleApplicationMetadata *cur_app_metadata = cached_app_metadata[j];
|
||||
if (cur_app_metadata)
|
||||
{
|
||||
if (cur_app_metadata->icon) free(cur_app_metadata->icon);
|
||||
|
@ -1105,29 +1115,12 @@ NX_INLINE void titleFreeApplicationMetadata(void)
|
|||
}
|
||||
}
|
||||
|
||||
free(g_systemMetadata);
|
||||
g_systemMetadata = NULL;
|
||||
}
|
||||
|
||||
g_systemMetadataCount = 0;
|
||||
|
||||
if (g_userMetadata)
|
||||
{
|
||||
for(u32 i = 0; i < g_userMetadataCount; i++)
|
||||
{
|
||||
TitleApplicationMetadata *cur_app_metadata = g_userMetadata[i];
|
||||
if (cur_app_metadata)
|
||||
{
|
||||
if (cur_app_metadata->icon) free(cur_app_metadata->icon);
|
||||
free(cur_app_metadata);
|
||||
free(cached_app_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
free(g_userMetadata);
|
||||
g_userMetadata = NULL;
|
||||
}
|
||||
|
||||
g_userMetadataCount = 0;
|
||||
g_systemMetadata = g_userMetadata = NULL;
|
||||
g_systemMetadataCount = g_userMetadataCount = 0;
|
||||
}
|
||||
|
||||
static bool titleReallocateApplicationMetadata(u32 extra_app_count, bool is_system, bool free_entries)
|
||||
|
|
|
@ -27,12 +27,18 @@
|
|||
//#include <options_tab.hpp>
|
||||
#include <about_tab.hpp>
|
||||
|
||||
using namespace brls::i18n::literals; /* For _i18n. */
|
||||
namespace i18n = brls::i18n; /* For getStr(). */
|
||||
using namespace i18n::literals; /* For _i18n. */
|
||||
|
||||
namespace nxdt::views
|
||||
{
|
||||
RootView::RootView(void) : brls::TabFrame()
|
||||
{
|
||||
/* Set UI properties. */
|
||||
this->setTitle(APP_TITLE);
|
||||
this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
|
||||
this->setFooterText("v" APP_VERSION);
|
||||
|
||||
/* Check if we're running under applet mode. */
|
||||
this->applet_mode = utilsAppletModeCheck();
|
||||
|
||||
|
@ -65,11 +71,6 @@ namespace nxdt::views
|
|||
this->ums_task = new nxdt::tasks::UmsTask();
|
||||
this->usb_host_task = new nxdt::tasks::UsbHostTask();
|
||||
|
||||
/* Set UI properties. */
|
||||
this->setTitle(APP_TITLE);
|
||||
this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
|
||||
this->setFooterText("v" APP_VERSION);
|
||||
|
||||
/* Add tabs. */
|
||||
this->addTab("root_view/tabs/gamecard"_i18n, new GameCardTab(this->gc_status_task));
|
||||
this->addSeparator();
|
||||
|
@ -81,20 +82,34 @@ namespace nxdt::views
|
|||
this->addTab("root_view/tabs/about"_i18n, new AboutTab());
|
||||
|
||||
/* Subscribe to status info event. */
|
||||
this->status_info_task_sub = this->status_info_task->RegisterListener([this](void) {
|
||||
u32 charge_percentage = 0;
|
||||
PsmChargerType charger_type = PsmChargerType_Unconnected;
|
||||
|
||||
NifmInternetConnectionType connection_type = (NifmInternetConnectionType)0;
|
||||
u32 signal_strength = 0;
|
||||
NifmInternetConnectionStatus connection_status = (NifmInternetConnectionStatus)0;
|
||||
char *ip_addr = NULL;
|
||||
|
||||
this->status_info_task_sub = this->status_info_task->RegisterListener([this](const nxdt::tasks::StatusInfoData *status_info_data) {
|
||||
/* Update time label. */
|
||||
this->time_lbl->setText(this->status_info_task->GetCurrentTimeString());
|
||||
bool is_am = true;
|
||||
struct tm *timeinfo = status_info_data->timeinfo;
|
||||
|
||||
timeinfo->tm_mon++;
|
||||
timeinfo->tm_year += 1900;
|
||||
|
||||
if ("root_view/time_format"_i18n.compare("12") == 0)
|
||||
{
|
||||
/* Adjust time for 12-hour clock. */
|
||||
if (timeinfo->tm_hour > 12)
|
||||
{
|
||||
timeinfo->tm_hour -= 12;
|
||||
is_am = false;
|
||||
} else
|
||||
if (!timeinfo->tm_hour)
|
||||
{
|
||||
timeinfo->tm_hour = 12;
|
||||
}
|
||||
}
|
||||
|
||||
this->time_lbl->setText(i18n::getStr("root_view/date"_i18n, timeinfo->tm_year, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, \
|
||||
is_am ? "AM" : "PM"));
|
||||
|
||||
/* Update battery labels. */
|
||||
this->status_info_task->GetBatteryStats(&charge_percentage, &charger_type);
|
||||
u32 charge_percentage = status_info_data->charge_percentage;
|
||||
PsmChargerType charger_type = status_info_data->charger_type;
|
||||
|
||||
this->battery_icon->setText(charger_type != PsmChargerType_Unconnected ? "\uE1A3" : (charge_percentage <= 15 ? "\uE19C" : "\uE1A4"));
|
||||
this->battery_icon->setColor(charger_type != PsmChargerType_Unconnected ? nvgRGB(0, 255, 0) : (charge_percentage <= 15 ? nvgRGB(255, 0, 0) : brls::Application::getTheme()->textColor));
|
||||
|
@ -102,7 +117,8 @@ namespace nxdt::views
|
|||
this->battery_percentage->setText(fmt::format("{}%", charge_percentage));
|
||||
|
||||
/* Update network label. */
|
||||
this->status_info_task->GetNetworkStats(&connection_type, &signal_strength, &connection_status, &ip_addr);
|
||||
NifmInternetConnectionType connection_type = status_info_data->connection_type;
|
||||
char *ip_addr = status_info_data->ip_addr;
|
||||
|
||||
this->connection_icon->setText(!connection_type ? "\uE195" : (connection_type == NifmInternetConnectionType_WiFi ? "\uE63E" : "\uE8BE"));
|
||||
this->connection_status_lbl->setText(ip_addr ? std::string(ip_addr) : "root_view/not_connected"_i18n);
|
||||
|
@ -117,6 +133,12 @@ namespace nxdt::views
|
|||
/* Unregister status info task listener. */
|
||||
this->status_info_task->UnregisterListener(this->status_info_task_sub);
|
||||
|
||||
/* Stop background tasks. */
|
||||
this->gc_status_task->stop();
|
||||
this->title_task->stop();
|
||||
this->ums_task->stop();
|
||||
this->usb_host_task->stop();
|
||||
|
||||
/* Destroy labels. */
|
||||
delete this->applet_mode_lbl;
|
||||
delete this->time_lbl;
|
||||
|
@ -124,16 +146,12 @@ namespace nxdt::views
|
|||
delete this->battery_percentage;
|
||||
delete this->connection_icon;
|
||||
delete this->connection_status_lbl;
|
||||
|
||||
/* Stop background tasks. */
|
||||
this->gc_status_task->stop();
|
||||
this->title_task->stop();
|
||||
this->ums_task->stop();
|
||||
this->usb_host_task->stop();
|
||||
}
|
||||
|
||||
void RootView::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
|
||||
{
|
||||
brls::AppletFrame::draw(vg, x, y, width, height, style, ctx);
|
||||
|
||||
if (this->applet_mode) this->applet_mode_lbl->frame(ctx);
|
||||
|
||||
this->time_lbl->frame(ctx);
|
||||
|
@ -143,8 +161,6 @@ namespace nxdt::views
|
|||
|
||||
this->connection_icon->frame(ctx);
|
||||
this->connection_status_lbl->frame(ctx);
|
||||
|
||||
brls::AppletFrame::draw(vg, x, y, width, height, style, ctx);
|
||||
}
|
||||
|
||||
void RootView::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
|
||||
|
|
168
source/tasks.cpp
168
source/tasks.cpp
|
@ -23,16 +23,13 @@
|
|||
#include <tasks.hpp>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define NXDT_TASK_INTERVAL 100 /* 100 ms. */
|
||||
|
||||
namespace i18n = brls::i18n; /* For getStr(). */
|
||||
using namespace i18n::literals; /* For _i18n. */
|
||||
#define NXDT_TASK_INTERVAL 250 /* 250 ms. */
|
||||
|
||||
namespace nxdt::tasks
|
||||
{
|
||||
/* Status info task. */
|
||||
|
||||
StatusInfoTask::StatusInfoTask(void) : brls::RepeatingTask(1000)
|
||||
StatusInfoTask::StatusInfoTask(void) : brls::RepeatingTask(NXDT_TASK_INTERVAL)
|
||||
{
|
||||
brls::RepeatingTask::start();
|
||||
brls::Logger::debug("Status info task started.");
|
||||
|
@ -40,9 +37,6 @@ namespace nxdt::tasks
|
|||
|
||||
StatusInfoTask::~StatusInfoTask(void)
|
||||
{
|
||||
/* Clear current time string. */
|
||||
this->cur_time.clear();
|
||||
|
||||
brls::Logger::debug("Status info task stopped.");
|
||||
}
|
||||
|
||||
|
@ -50,72 +44,37 @@ namespace nxdt::tasks
|
|||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
||||
StatusInfoData *status_info_data = &(this->status_info_data);
|
||||
|
||||
/* Get current time. */
|
||||
bool is_am = true;
|
||||
time_t unix_time = time(NULL);
|
||||
struct tm *timeinfo = localtime(&unix_time);
|
||||
|
||||
if (timeinfo->tm_hour > 12)
|
||||
{
|
||||
timeinfo->tm_hour -= 12;
|
||||
is_am = false;
|
||||
} else
|
||||
if (!timeinfo->tm_hour)
|
||||
{
|
||||
timeinfo->tm_hour = 12;
|
||||
}
|
||||
|
||||
timeinfo->tm_mon++;
|
||||
timeinfo->tm_year += 1900;
|
||||
|
||||
this->cur_time.clear();
|
||||
this->cur_time = i18n::getStr("root_view/date"_i18n, timeinfo->tm_year, timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, is_am ? "AM" : "PM");
|
||||
status_info_data->timeinfo = localtime(&unix_time);
|
||||
|
||||
/* Get battery stats. */
|
||||
psmGetBatteryChargePercentage(&(this->charge_percentage));
|
||||
psmGetChargerType(&(this->charger_type));
|
||||
psmGetBatteryChargePercentage(&(status_info_data->charge_percentage));
|
||||
psmGetChargerType(&(status_info_data->charger_type));
|
||||
|
||||
/* Get network connection status. */
|
||||
Result rc = nifmGetInternetConnectionStatus(&(this->connection_type), &(this->signal_strength), &(this->connection_status));
|
||||
u32 signal_strength = 0;
|
||||
NifmInternetConnectionStatus connection_status = (NifmInternetConnectionStatus)0;
|
||||
|
||||
Result rc = nifmGetInternetConnectionStatus(&(status_info_data->connection_type), &signal_strength, &connection_status);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
if (this->connection_type && this->connection_status == NifmInternetConnectionStatus_Connected)
|
||||
if (status_info_data->connection_type && connection_status == NifmInternetConnectionStatus_Connected)
|
||||
{
|
||||
struct in_addr addr = { .s_addr = 0 };
|
||||
nifmGetCurrentIpAddress(&(addr.s_addr));
|
||||
this->ip_addr = inet_ntoa(addr);
|
||||
status_info_data->ip_addr = inet_ntoa(addr);
|
||||
} else {
|
||||
this->ip_addr = NULL;
|
||||
status_info_data->ip_addr = NULL;
|
||||
}
|
||||
} else {
|
||||
this->connection_type = (NifmInternetConnectionType)0;
|
||||
this->signal_strength = 0;
|
||||
this->connection_status = (NifmInternetConnectionStatus)0;
|
||||
this->ip_addr = NULL;
|
||||
status_info_data->connection_type = (NifmInternetConnectionType)0;
|
||||
status_info_data->ip_addr = NULL;
|
||||
}
|
||||
|
||||
this->status_info_event.fire();
|
||||
}
|
||||
|
||||
std::string StatusInfoTask::GetCurrentTimeString(void)
|
||||
{
|
||||
return this->cur_time;
|
||||
}
|
||||
|
||||
void StatusInfoTask::GetBatteryStats(u32 *out_charge_percentage, PsmChargerType *out_charger_type)
|
||||
{
|
||||
if (!out_charge_percentage || !out_charger_type) return;
|
||||
*out_charge_percentage = this->charge_percentage;
|
||||
*out_charger_type = this->charger_type;
|
||||
}
|
||||
|
||||
void StatusInfoTask::GetNetworkStats(NifmInternetConnectionType *out_connection_type, u32 *out_signal_strength, NifmInternetConnectionStatus *out_connection_status, char **out_ip_addr)
|
||||
{
|
||||
if (!out_connection_type || !out_signal_strength || !out_connection_status || !out_ip_addr) return;
|
||||
*out_connection_type = this->connection_type;
|
||||
*out_signal_strength = this->signal_strength;
|
||||
*out_connection_status = this->connection_status;
|
||||
*out_ip_addr = this->ip_addr;
|
||||
this->status_info_event.fire(status_info_data);
|
||||
}
|
||||
|
||||
/* Gamecard task. */
|
||||
|
@ -168,28 +127,6 @@ namespace nxdt::tasks
|
|||
brls::Logger::debug("Title task stopped.");
|
||||
}
|
||||
|
||||
void TitleTask::PopulateApplicationMetadataVector(bool is_system)
|
||||
{
|
||||
TitleApplicationMetadata **app_metadata = NULL;
|
||||
u32 app_metadata_count = 0;
|
||||
|
||||
/* Get pointer to output vector. */
|
||||
TitleApplicationMetadataVector *vector = (is_system ? &(this->system_metadata) : &(this->user_metadata));
|
||||
if (vector->size()) vector->clear();
|
||||
|
||||
/* Get application metadata entries. */
|
||||
app_metadata = titleGetApplicationMetadataEntries(is_system, &app_metadata_count);
|
||||
if (!app_metadata) return;
|
||||
|
||||
/* Fill output vector. */
|
||||
for(u32 i = 0; i < app_metadata_count; i++) vector->push_back(app_metadata[i]);
|
||||
|
||||
/* Free application metadata array. */
|
||||
free(app_metadata);
|
||||
|
||||
brls::Logger::debug("Retrieved {} {} metadata {}.", app_metadata_count, is_system ? "system" : "user", app_metadata_count == 1 ? "entry" : "entries");
|
||||
}
|
||||
|
||||
void TitleTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
@ -200,7 +137,7 @@ namespace nxdt::tasks
|
|||
this->PopulateApplicationMetadataVector(false);
|
||||
|
||||
/* Fire task event. */
|
||||
this->title_event.fire();
|
||||
this->title_event.fire(&(this->user_metadata));
|
||||
brls::Logger::debug("Title info updated.");
|
||||
}
|
||||
}
|
||||
|
@ -210,6 +147,29 @@ namespace nxdt::tasks
|
|||
return (is_system ? &(this->system_metadata) : &(this->user_metadata));
|
||||
}
|
||||
|
||||
void TitleTask::PopulateApplicationMetadataVector(bool is_system)
|
||||
{
|
||||
TitleApplicationMetadata **app_metadata = NULL;
|
||||
u32 app_metadata_count = 0;
|
||||
|
||||
/* Get pointer to output vector. */
|
||||
TitleApplicationMetadataVector *vector = (is_system ? &(this->system_metadata) : &(this->user_metadata));
|
||||
vector->clear();
|
||||
|
||||
/* Get application metadata entries. */
|
||||
app_metadata = titleGetApplicationMetadataEntries(is_system, &app_metadata_count);
|
||||
if (app_metadata)
|
||||
{
|
||||
/* Fill output vector. */
|
||||
for(u32 i = 0; i < app_metadata_count; i++) vector->push_back(app_metadata[i]);
|
||||
|
||||
/* Free application metadata array. */
|
||||
free(app_metadata);
|
||||
}
|
||||
|
||||
brls::Logger::debug("Retrieved {} {} metadata {}.", app_metadata_count, is_system ? "system" : "user", app_metadata_count == 1 ? "entry" : "entries");
|
||||
}
|
||||
|
||||
/* USB Mass Storage task. */
|
||||
|
||||
UmsTask::UmsTask(void) : brls::RepeatingTask(NXDT_TASK_INTERVAL)
|
||||
|
@ -226,27 +186,6 @@ namespace nxdt::tasks
|
|||
brls::Logger::debug("UMS task stopped.");
|
||||
}
|
||||
|
||||
void UmsTask::PopulateUmsDeviceVector(void)
|
||||
{
|
||||
UsbHsFsDevice *ums_devices = NULL;
|
||||
u32 ums_device_count = 0;
|
||||
|
||||
/* Clear UMS device vector (if needed). */
|
||||
if (this->ums_devices.size()) this->ums_devices.clear();
|
||||
|
||||
/* Get UMS devices. */
|
||||
ums_devices = umsGetDevices(&ums_device_count);
|
||||
if (!ums_devices) return;
|
||||
|
||||
/* Fill UMS device vector. */
|
||||
for(u32 i = 0; i < ums_device_count; i++) this->ums_devices.push_back(ums_devices[i]);
|
||||
|
||||
/* Free UMS devices array. */
|
||||
free(ums_devices);
|
||||
|
||||
brls::Logger::debug("Retrieved info for {} UMS {}.", ums_device_count, ums_device_count == 1 ? "device" : "devices");
|
||||
}
|
||||
|
||||
void UmsTask::run(retro_time_t current_time)
|
||||
{
|
||||
brls::RepeatingTask::run(current_time);
|
||||
|
@ -257,14 +196,31 @@ namespace nxdt::tasks
|
|||
this->PopulateUmsDeviceVector();
|
||||
|
||||
/* Fire task event. */
|
||||
this->ums_event.fire();
|
||||
this->ums_event.fire(&(this->ums_devices));
|
||||
brls::Logger::debug("UMS device info updated.");
|
||||
}
|
||||
}
|
||||
|
||||
UmsDeviceVector* UmsTask::GetUmsDevices(void)
|
||||
void UmsTask::PopulateUmsDeviceVector(void)
|
||||
{
|
||||
return &(this->ums_devices);
|
||||
UsbHsFsDevice *ums_devices = NULL;
|
||||
u32 ums_device_count = 0;
|
||||
|
||||
/* Clear UMS device vector. */
|
||||
this->ums_devices.clear();
|
||||
|
||||
/* Get UMS devices. */
|
||||
ums_devices = umsGetDevices(&ums_device_count);
|
||||
if (ums_devices)
|
||||
{
|
||||
/* Fill UMS device vector. */
|
||||
for(u32 i = 0; i < ums_device_count; i++) this->ums_devices.push_back(ums_devices[i]);
|
||||
|
||||
/* Free UMS devices array. */
|
||||
free(ums_devices);
|
||||
}
|
||||
|
||||
brls::Logger::debug("Retrieved info for {} UMS {}.", ums_device_count, ums_device_count == 1 ? "device" : "devices");
|
||||
}
|
||||
|
||||
/* USB host device connection task. */
|
||||
|
@ -287,8 +243,8 @@ namespace nxdt::tasks
|
|||
this->cur_usb_host_status = usbIsReady();
|
||||
if (this->cur_usb_host_status != this->prev_usb_host_status)
|
||||
{
|
||||
this->usb_host_event.fire(this->cur_usb_host_status);
|
||||
this->prev_usb_host_status = this->cur_usb_host_status;
|
||||
this->usb_host_event.fire(this->cur_usb_host_status);
|
||||
brls::Logger::debug("USB host status change triggered: {}.", this->cur_usb_host_status);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue