2020-04-16 01:06:41 +01:00
/*
* Copyright ( c ) 2020 DarkMatterCore
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope 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 < http : //www.gnu.org/licenses/>.
*/
2020-04-15 21:50:07 +01:00
# include <stdio.h>
2020-04-17 22:59:05 +01:00
# include <stdlib.h>
2020-04-15 21:50:07 +01:00
# include <string.h>
# include <stdarg.h>
2020-05-03 00:40:50 +01:00
# include <ctype.h>
2020-04-15 21:50:07 +01:00
# include <time.h>
# include <switch.h>
//#include "freetype_helper.h"
//#include "lvgl_helper.h"
2020-04-16 11:13:11 +01:00
# include "keys.h"
2020-04-15 21:50:07 +01:00
# include "gamecard.h"
2020-04-16 11:13:11 +01:00
# include "services.h"
2020-04-15 21:50:07 +01:00
# include "utils.h"
2020-04-21 11:23:33 +01:00
# include "nca.h"
2020-05-05 16:22:16 +01:00
# include "usb.h"
2020-04-17 22:59:05 +01:00
# include "fatfs/ff.h"
2020-04-15 21:50:07 +01:00
/* Global variables. */
2020-05-03 00:40:50 +01:00
static bool g_resourcesInitialized = false ;
static Mutex g_resourcesMutex = 0 ;
static FsFileSystem * g_sdCardFileSystem = NULL ;
static FsStorage g_emmcBisSystemPartitionStorage = { 0 } ;
static FATFS * g_emmcBisSystemPartitionFatFsObj = NULL ;
static AppletType g_programAppletType = 0 ;
static bool g_homeButtonBlocked = false ;
static Mutex g_homeButtonMutex = 0 ;
2020-04-16 11:13:11 +01:00
static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown ;
2020-04-15 21:50:07 +01:00
static AppletHookCookie g_systemOverclockCookie = { 0 } ;
static Mutex g_logfileMutex = 0 ;
/* Function prototypes. */
2020-05-03 00:40:50 +01:00
static bool utilsMountEmmcBisSystemPartitionStorage ( void ) ;
static void utilsUnmountEmmcBisSystemPartitionStorage ( void ) ;
2020-04-16 11:13:11 +01:00
static void _utilsGetCustomFirmwareType ( void ) ;
2020-04-15 21:50:07 +01:00
static void utilsOverclockSystemAppletHook ( AppletHookType hook , void * param ) ;
2020-05-03 00:40:50 +01:00
bool utilsInitializeResources ( void )
{
mutexLock ( & g_resourcesMutex ) ;
bool ret = g_resourcesInitialized ;
if ( ret ) goto exit ;
/* Initialize needed services */
if ( ! servicesInitialize ( ) )
{
LOGFILE ( " Failed to initialize needed services! " ) ;
goto exit ;
}
2020-05-05 16:22:16 +01:00
/* Initialize USB interface */
if ( ! usbInitialize ( ) )
{
LOGFILE ( " Failed to initialize USB interface! " ) ;
goto exit ;
}
2020-05-03 00:40:50 +01:00
/* Load NCA keyset */
if ( ! keysLoadNcaKeyset ( ) )
{
LOGFILE ( " Failed to load NCA keyset! " ) ;
goto exit ;
}
/* Allocate NCA crypto buffer */
if ( ! ncaAllocateCryptoBuffer ( ) )
{
LOGFILE ( " Unable to allocate memory for NCA crypto buffer! " ) ;
goto exit ;
}
/* Initialize gamecard interface */
if ( ! gamecardInitialize ( ) )
{
LOGFILE ( " Failed to initialize gamecard interface! " ) ;
goto exit ;
}
/* Retrieve SD card FsFileSystem */
if ( ! ( g_sdCardFileSystem = fsdevGetDeviceFileSystem ( " sdmc: " ) ) )
{
LOGFILE ( " fsdevGetDeviceFileSystem failed! " ) ;
goto exit ;
}
/* Mount eMMC BIS System partition */
if ( ! utilsMountEmmcBisSystemPartitionStorage ( ) ) goto exit ;
/* Get applet type */
g_programAppletType = appletGetAppletType ( ) ;
/* Disable screen dimming and auto sleep */
appletSetMediaPlaybackState ( true ) ;
/* Retrieve custom firmware type */
_utilsGetCustomFirmwareType ( ) ;
/* Overclock system */
utilsOverclockSystem ( true ) ;
/* Setup an applet hook to change the hardware clocks after a system mode change (docked <-> undocked) */
appletHook ( & g_systemOverclockCookie , utilsOverclockSystemAppletHook , NULL ) ;
/* Initialize FreeType */
//if (!freeTypeHelperInitialize()) return false;
/* Initialize LVGL */
//if (!lvglHelperInitialize()) return false;
ret = g_resourcesInitialized = true ;
exit :
mutexUnlock ( & g_resourcesMutex ) ;
return ret ;
}
void utilsCloseResources ( void )
{
mutexLock ( & g_resourcesMutex ) ;
/* Free LVGL resources */
//lvglHelperExit();
/* Free FreeType resouces */
//freeTypeHelperExit();
/* Unset our overclock applet hook */
appletUnhook ( & g_systemOverclockCookie ) ;
/* Restore hardware clocks */
utilsOverclockSystem ( false ) ;
/* Enable screen dimming and auto sleep */
appletSetMediaPlaybackState ( false ) ;
/* Unblock HOME button presses */
utilsChangeHomeButtonBlockStatus ( false ) ;
/* Unmount eMMC BIS System partition */
utilsUnmountEmmcBisSystemPartitionStorage ( ) ;
/* Deinitialize gamecard interface */
gamecardExit ( ) ;
/* Free NCA crypto buffer */
ncaFreeCryptoBuffer ( ) ;
2020-05-05 16:22:16 +01:00
/* Close USB interface */
usbExit ( ) ;
2020-05-03 00:40:50 +01:00
/* Close initialized services */
servicesClose ( ) ;
g_resourcesInitialized = false ;
mutexUnlock ( & g_resourcesMutex ) ;
}
2020-04-17 22:59:05 +01:00
2020-04-15 21:50:07 +01:00
u64 utilsHidKeysAllDown ( void )
{
u8 controller ;
u64 keys_down = 0 ;
for ( controller = 0 ; controller < ( u8 ) CONTROLLER_P1_AUTO ; controller + + ) keys_down | = hidKeysDown ( ( HidControllerID ) controller ) ;
return keys_down ;
}
u64 utilsHidKeysAllHeld ( void )
{
u8 controller ;
u64 keys_held = 0 ;
for ( controller = 0 ; controller < ( u8 ) CONTROLLER_P1_AUTO ; controller + + ) keys_held | = hidKeysHeld ( ( HidControllerID ) controller ) ;
return keys_held ;
}
void utilsWaitForButtonPress ( void )
{
u64 flag , keys_down ;
/* Don't consider touch screen presses nor stick movement as button inputs */
flag = ~ ( KEY_TOUCH | KEY_LSTICK_LEFT | KEY_LSTICK_RIGHT | KEY_LSTICK_UP | KEY_LSTICK_DOWN | KEY_RSTICK_LEFT | KEY_RSTICK_RIGHT | KEY_RSTICK_UP | KEY_RSTICK_DOWN ) ;
while ( appletMainLoop ( ) )
{
hidScanInput ( ) ;
keys_down = utilsHidKeysAllDown ( ) ;
if ( keys_down & flag ) break ;
}
}
void utilsWriteLogMessage ( const char * func_name , const char * fmt , . . . )
{
mutexLock ( & g_logfileMutex ) ;
va_list args ;
FILE * logfile = NULL ;
2020-05-04 19:15:03 +01:00
logfile = fopen ( LOGFILE_PATH , " a+ " ) ;
2020-04-15 21:50:07 +01:00
if ( ! logfile ) goto out ;
time_t now = time ( NULL ) ;
struct tm * ts = localtime ( & now ) ;
2020-04-16 01:06:41 +01:00
fprintf ( logfile , " %d/%d/%d %d:%02d:%02d -> %s: " , ts - > tm_year + 1900 , ts - > tm_mon + 1 , ts - > tm_mday , ts - > tm_hour , ts - > tm_min , ts - > tm_sec , func_name ) ;
2020-04-15 21:50:07 +01:00
va_start ( args , fmt ) ;
vfprintf ( logfile , fmt , args ) ;
va_end ( args ) ;
fprintf ( logfile , " \r \n " ) ;
fclose ( logfile ) ;
out :
mutexUnlock ( & g_logfileMutex ) ;
}
2020-05-05 19:04:23 +01:00
void utilsReplaceIllegalCharacters ( char * str , bool ascii_only )
2020-05-03 00:40:50 +01:00
{
size_t strsize = 0 ;
2020-04-16 11:13:11 +01:00
2020-05-03 00:40:50 +01:00
if ( ! str | | ! ( strsize = strlen ( str ) ) ) return ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
for ( size_t i = 0 ; i < strsize ; i + + )
2020-04-21 11:23:33 +01:00
{
2020-05-05 19:04:23 +01:00
if ( memchr ( " ?[]/ \\ =+<>:; \" ,*|^ " , str [ i ] , sizeof ( " ?[]/ \\ =+<>:; \" ,*|^ " ) - 1 ) | | str [ i ] < 0x20 | | ( ! ascii_only & & str [ i ] = = 0x7F ) | | ( ascii_only & & str [ i ] > = 0x7F ) ) str [ i ] = ' _ ' ;
2020-04-21 11:23:33 +01:00
}
2020-04-15 21:50:07 +01:00
}
2020-05-03 00:40:50 +01:00
void utilsTrimString ( char * str )
2020-04-15 21:50:07 +01:00
{
2020-05-03 00:40:50 +01:00
size_t strsize = 0 ;
char * start = NULL , * end = NULL ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
if ( ! str | | ! ( strsize = strlen ( str ) ) ) return ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
start = str ;
end = ( start + strsize ) ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
while ( - - end > = start )
{
if ( ! isspace ( ( unsigned char ) * end ) ) break ;
}
2020-04-17 22:59:05 +01:00
2020-05-03 00:40:50 +01:00
* ( + + end ) = ' \0 ' ;
2020-04-17 22:59:05 +01:00
2020-05-03 00:40:50 +01:00
while ( isspace ( ( unsigned char ) * start ) ) start + + ;
2020-04-21 11:23:33 +01:00
2020-05-03 00:40:50 +01:00
if ( start ! = str ) memmove ( str , start , end - start + 1 ) ;
2020-04-16 11:13:11 +01:00
}
2020-04-17 22:59:05 +01:00
void utilsGenerateHexStringFromData ( char * dst , size_t dst_size , const void * src , size_t src_size )
{
if ( ! src | | ! src_size | | ! dst | | dst_size < ( ( src_size * 2 ) + 1 ) ) return ;
size_t i , j ;
const u8 * src_u8 = ( const u8 * ) src ;
for ( i = 0 , j = 0 ; i < src_size ; i + + )
{
2020-04-19 23:44:22 +01:00
char h_nib = ( ( src_u8 [ i ] > > 4 ) & 0xF ) ;
char l_nib = ( src_u8 [ i ] & 0xF ) ;
2020-04-17 22:59:05 +01:00
2020-04-19 23:44:22 +01:00
dst [ j + + ] = ( h_nib + ( h_nib < 0xA ? 0x30 : 0x57 ) ) ;
dst [ j + + ] = ( l_nib + ( l_nib < 0xA ? 0x30 : 0x57 ) ) ;
2020-04-17 22:59:05 +01:00
}
dst [ j ] = ' \0 ' ;
}
2020-05-03 00:40:50 +01:00
bool utilsGetFreeSdCardSpace ( u64 * out )
2020-04-17 22:59:05 +01:00
{
2020-05-03 00:40:50 +01:00
return utilsGetFreeFileSystemSpace ( g_sdCardFileSystem , out ) ;
2020-04-17 22:59:05 +01:00
}
2020-05-03 00:40:50 +01:00
bool utilsGetFreeFileSystemSpace ( FsFileSystem * fs , u64 * out )
2020-04-16 11:13:11 +01:00
{
2020-05-03 00:40:50 +01:00
if ( ! fs | | ! out )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-04-16 11:13:11 +01:00
2020-05-03 00:40:50 +01:00
Result rc = fsFsGetFreeSpace ( fs , " / " , ( s64 * ) out ) ;
if ( R_FAILED ( rc ) )
2020-04-16 11:13:11 +01:00
{
2020-05-03 00:40:50 +01:00
LOGFILE ( " fsFsGetFreeSpace failed! (0x%08X) " , rc ) ;
return false ;
}
return true ;
}
bool utilsCheckIfFileExists ( const char * path )
{
if ( ! path | | ! strlen ( path ) ) return false ;
FILE * chkfile = fopen ( path , " rb " ) ;
if ( chkfile )
2020-04-16 11:13:11 +01:00
{
2020-05-03 00:40:50 +01:00
fclose ( chkfile ) ;
return true ;
2020-04-16 11:13:11 +01:00
}
2020-05-03 00:40:50 +01:00
return false ;
2020-04-16 11:13:11 +01:00
}
2020-05-03 00:40:50 +01:00
bool utilsCreateConcatenationFile ( const char * path )
2020-04-15 21:50:07 +01:00
{
2020-05-03 00:40:50 +01:00
Result rc = 0 ;
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
if ( ! path | | ! strlen ( path ) )
{
LOGFILE ( " Invalid parameters! " ) ;
return false ;
}
2020-04-15 21:50:07 +01:00
2020-05-03 00:40:50 +01:00
/* Safety check: remove any existant file/directory at the destination path */
remove ( path ) ;
fsdevDeleteDirectoryRecursively ( path ) ;
/* Create ConcatenationFile */
/* If the call succeeds, the caller function will be able to operate on this file using stdio calls */
rc = fsdevCreateFile ( path , 0 , FsCreateOption_BigFile ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " fsdevCreateFile failed for \" %s \" ! (0x%08X) " , path , rc ) ;
return false ;
}
return true ;
}
bool utilsAppletModeCheck ( void )
{
return ( g_programAppletType ! = AppletType_Application & & g_programAppletType ! = AppletType_SystemApplication ) ;
}
void utilsChangeHomeButtonBlockStatus ( bool block )
{
mutexLock ( & g_homeButtonMutex ) ;
/* Only change HOME button blocking status if we're running as a regular application or a system application, and if it's current blocking status is different than the requested one */
if ( ! utilsAppletModeCheck ( ) & & block ! = g_homeButtonBlocked )
{
if ( block )
{
appletBeginBlockingHomeButtonShortAndLongPressed ( 0 ) ;
} else {
appletEndBlockingHomeButtonShortAndLongPressed ( ) ;
}
g_homeButtonBlocked = block ;
}
mutexUnlock ( & g_homeButtonMutex ) ;
}
u8 utilsGetCustomFirmwareType ( void )
{
return g_customFirmwareType ;
}
FsStorage * utilsGetEmmcBisSystemPartitionStorage ( void )
{
return & g_emmcBisSystemPartitionStorage ;
}
void utilsOverclockSystem ( bool overclock )
{
u32 cpuClkRate = ( ( overclock ? CPU_CLKRT_OVERCLOCKED : CPU_CLKRT_NORMAL ) * 1000000 ) ;
u32 memClkRate = ( ( overclock ? MEM_CLKRT_OVERCLOCKED : MEM_CLKRT_NORMAL ) * 1000000 ) ;
servicesChangeHardwareClockRates ( cpuClkRate , memClkRate ) ;
2020-04-15 21:50:07 +01:00
}
2020-04-17 22:59:05 +01:00
static bool utilsMountEmmcBisSystemPartitionStorage ( void )
{
Result rc = 0 ;
FRESULT fr = FR_OK ;
rc = fsOpenBisStorage ( & g_emmcBisSystemPartitionStorage , FsBisPartitionId_System ) ;
if ( R_FAILED ( rc ) )
{
LOGFILE ( " Failed to open eMMC BIS System partition storage! (0x%08X) " , rc ) ;
return false ;
}
2020-04-19 23:44:22 +01:00
g_emmcBisSystemPartitionFatFsObj = calloc ( 1 , sizeof ( FATFS ) ) ;
if ( ! g_emmcBisSystemPartitionFatFsObj )
2020-04-17 22:59:05 +01:00
{
LOGFILE ( " Unable to allocate memory for FatFs object! " ) ;
return false ;
}
2020-04-19 23:44:22 +01:00
fr = f_mount ( g_emmcBisSystemPartitionFatFsObj , BIS_SYSTEM_PARTITION_MOUNT_NAME , 1 ) ;
2020-04-17 22:59:05 +01:00
if ( fr ! = FR_OK )
{
LOGFILE ( " Failed to mount eMMC BIS System partition! (%u) " , fr ) ;
return false ;
}
return true ;
}
static void utilsUnmountEmmcBisSystemPartitionStorage ( void )
{
2020-04-19 23:44:22 +01:00
if ( g_emmcBisSystemPartitionFatFsObj )
2020-04-17 22:59:05 +01:00
{
f_unmount ( BIS_SYSTEM_PARTITION_MOUNT_NAME ) ;
2020-04-19 23:44:22 +01:00
free ( g_emmcBisSystemPartitionFatFsObj ) ;
g_emmcBisSystemPartitionFatFsObj = NULL ;
2020-04-17 22:59:05 +01:00
}
if ( serviceIsActive ( & ( g_emmcBisSystemPartitionStorage . s ) ) )
{
fsStorageClose ( & g_emmcBisSystemPartitionStorage ) ;
memset ( & g_emmcBisSystemPartitionStorage , 0 , sizeof ( FsStorage ) ) ;
}
}
2020-05-03 00:40:50 +01:00
static void _utilsGetCustomFirmwareType ( void )
{
bool tx_srv = servicesCheckRunningServiceByName ( " tx " ) ;
bool rnx_srv = servicesCheckRunningServiceByName ( " rnx " ) ;
g_customFirmwareType = ( rnx_srv ? UtilsCustomFirmwareType_ReiNX : ( tx_srv ? UtilsCustomFirmwareType_SXOS : UtilsCustomFirmwareType_Atmosphere ) ) ;
}
static void utilsOverclockSystemAppletHook ( AppletHookType hook , void * param )
{
( void ) param ;
if ( hook ! = AppletHookType_OnOperationMode & & hook ! = AppletHookType_OnPerformanceMode ) return ;
/* To do: read config here to actually know the value to use with utilsOverclockSystem */
utilsOverclockSystem ( false ) ;
}