2019-11-17 16:01:06 +01:00
# include "install/usb_nsp.hpp"
# include <switch.h>
# include <algorithm>
# include <malloc.h>
# include <threads.h>
# include "data/byte_buffer.hpp"
# include "data/buffered_placeholder_writer.hpp"
# include "util/usb_util.hpp"
2019-12-10 01:46:02 +01:00
# include "util/error.hpp"
# include "util/debug.h"
2019-11-30 17:12:45 +01:00
# include "sdInstall.hpp"
2019-11-28 01:49:58 +01:00
# include "util/util.hpp"
2019-12-08 04:54:03 +01:00
# include "util/usb_comms_awoo.h"
2019-11-17 16:01:06 +01:00
namespace tin : : install : : nsp
{
2019-12-13 02:50:40 +01:00
bool stopThreads ;
std : : string errorMessage ;
2019-11-17 16:01:06 +01:00
USBNSP : : USBNSP ( std : : string nspName ) :
m_nspName ( nspName )
{
}
struct USBFuncArgs
{
std : : string nspName ;
tin : : data : : BufferedPlaceholderWriter * bufferedPlaceholderWriter ;
u64 pfs0Offset ;
u64 ncaSize ;
} ;
int USBThreadFunc ( void * in )
{
USBFuncArgs * args = reinterpret_cast < USBFuncArgs * > ( in ) ;
tin : : util : : USBCmdHeader header = tin : : util : : USBCmdManager : : SendFileRangeCmd ( args - > nspName , args - > pfs0Offset , args - > ncaSize ) ;
u8 * buf = ( u8 * ) memalign ( 0x1000 , 0x800000 ) ;
u64 sizeRemaining = header . dataSize ;
size_t tmpSizeRead = 0 ;
try
{
2019-12-13 02:50:40 +01:00
while ( sizeRemaining & & ! tin : : install : : nsp : : stopThreads )
2019-11-17 16:01:06 +01:00
{
2019-12-08 04:54:03 +01:00
tmpSizeRead = awoo_usbCommsRead ( buf , std : : min ( sizeRemaining , ( u64 ) 0x800000 ) ) ;
2019-12-08 03:09:58 +01:00
if ( tmpSizeRead = = 0 ) THROW_FORMAT ( " USB transfer timed out or failed " ) ;
2019-11-17 16:01:06 +01:00
sizeRemaining - = tmpSizeRead ;
while ( true )
{
if ( args - > bufferedPlaceholderWriter - > CanAppendData ( tmpSizeRead ) )
break ;
}
args - > bufferedPlaceholderWriter - > AppendData ( buf , tmpSizeRead ) ;
}
}
catch ( std : : exception & e )
{
2019-12-13 02:50:40 +01:00
tin : : install : : nsp : : stopThreads = true ;
tin : : install : : nsp : : errorMessage = e . what ( ) ;
2019-12-12 17:18:30 +01:00
}
free ( buf ) ;
return 0 ;
}
int USBThreadFuncNcz ( void * in ) // nczs corrupt with ranges over 8MB
{
USBFuncArgs * args = reinterpret_cast < USBFuncArgs * > ( in ) ;
u8 * buf = ( u8 * ) memalign ( 0x1000 , 0x800000 ) ;
tin : : util : : USBCmdHeader header ;
u64 sizeRemaining = args - > ncaSize ;
size_t tmpSizeRead = 0 ;
u64 curOffset = 0 ;
u64 curRequestLeft = 0 ;
u64 reqSize = 0 ;
u64 readSize = 0 ;
try
{
2019-12-13 02:50:40 +01:00
while ( sizeRemaining & & ! tin : : install : : nsp : : stopThreads )
2019-12-12 17:18:30 +01:00
{
if ( ! curRequestLeft ) {
reqSize = std : : min ( sizeRemaining , ( u64 ) 0x800000 ) ;
header = tin : : util : : USBCmdManager : : SendFileRangeCmd ( args - > nspName , args - > pfs0Offset + curOffset , reqSize ) ;
curRequestLeft = header . dataSize ;
}
readSize = std : : min ( curRequestLeft , ( u64 ) 0x800000 ) ;
tmpSizeRead = awoo_usbCommsRead ( buf , readSize ) ;
if ( tmpSizeRead = = 0 ) THROW_FORMAT ( " USB transfer timed out or failed " ) ;
curOffset + = tmpSizeRead ;
sizeRemaining - = tmpSizeRead ;
curRequestLeft - = tmpSizeRead ;
while ( true )
{
if ( args - > bufferedPlaceholderWriter - > CanAppendData ( tmpSizeRead ) )
break ;
}
args - > bufferedPlaceholderWriter - > AppendData ( buf , tmpSizeRead ) ;
}
}
catch ( std : : exception & e )
{
2019-12-13 02:50:40 +01:00
tin : : install : : nsp : : stopThreads = true ;
tin : : install : : nsp : : errorMessage = e . what ( ) ;
2019-11-17 16:01:06 +01:00
}
free ( buf ) ;
return 0 ;
}
int USBPlaceholderWriteFunc ( void * in )
{
USBFuncArgs * args = reinterpret_cast < USBFuncArgs * > ( in ) ;
2019-12-13 02:50:40 +01:00
while ( ! args - > bufferedPlaceholderWriter - > IsPlaceholderComplete ( ) & & ! tin : : install : : nsp : : stopThreads )
2019-11-17 16:01:06 +01:00
{
if ( args - > bufferedPlaceholderWriter - > CanWriteSegmentToPlaceholder ( ) )
args - > bufferedPlaceholderWriter - > WriteSegmentToPlaceholder ( ) ;
}
return 0 ;
}
void USBNSP : : StreamToPlaceholder ( std : : shared_ptr < nx : : ncm : : ContentStorage > & contentStorage , NcmContentId placeholderId )
{
const PFS0FileEntry * fileEntry = this - > GetFileEntryByNcaId ( placeholderId ) ;
std : : string ncaFileName = this - > GetFileEntryName ( fileEntry ) ;
2019-11-30 18:12:59 +01:00
LOG_DEBUG ( " Retrieving %s \n " , ncaFileName . c_str ( ) ) ;
2019-11-17 16:01:06 +01:00
size_t ncaSize = fileEntry - > fileSize ;
tin : : data : : BufferedPlaceholderWriter bufferedPlaceholderWriter ( contentStorage , placeholderId , ncaSize ) ;
USBFuncArgs args ;
args . nspName = m_nspName ;
args . bufferedPlaceholderWriter = & bufferedPlaceholderWriter ;
args . pfs0Offset = this - > GetDataOffset ( ) + fileEntry - > dataOffset ;
args . ncaSize = ncaSize ;
thrd_t usbThread ;
thrd_t writeThread ;
2019-12-13 02:50:40 +01:00
tin : : install : : nsp : : stopThreads = false ;
2019-12-12 17:18:30 +01:00
if ( m_nspName . substr ( m_nspName . size ( ) - 1 , 1 ) = = " z " ) thrd_create ( & usbThread , USBThreadFuncNcz , & args ) ;
else thrd_create ( & usbThread , USBThreadFunc , & args ) ;
2019-11-17 16:01:06 +01:00
thrd_create ( & writeThread , USBPlaceholderWriteFunc , & args ) ;
u64 freq = armGetSystemTickFreq ( ) ;
u64 startTime = armGetSystemTick ( ) ;
size_t startSizeBuffered = 0 ;
double speed = 0.0 ;
2019-11-30 19:20:59 +01:00
inst : : ui : : setInstBarPerc ( 0 ) ;
2019-12-13 02:50:40 +01:00
while ( ! bufferedPlaceholderWriter . IsBufferDataComplete ( ) & & ! tin : : install : : nsp : : stopThreads )
2019-11-17 16:01:06 +01:00
{
u64 newTime = armGetSystemTick ( ) ;
2019-12-07 20:05:16 +01:00
if ( newTime - startTime > = freq )
2019-11-17 16:01:06 +01:00
{
size_t newSizeBuffered = bufferedPlaceholderWriter . GetSizeBuffered ( ) ;
double mbBuffered = ( newSizeBuffered / 1000000.0 ) - ( startSizeBuffered / 1000000.0 ) ;
double duration = ( ( double ) ( newTime - startTime ) / ( double ) freq ) ;
speed = mbBuffered / duration ;
startTime = newTime ;
startSizeBuffered = newSizeBuffered ;
2019-11-30 20:53:04 +01:00
int downloadProgress = ( int ) ( ( ( double ) bufferedPlaceholderWriter . GetSizeBuffered ( ) / ( double ) bufferedPlaceholderWriter . GetTotalDataSize ( ) ) * 100.0 ) ;
2019-11-30 19:20:59 +01:00
# ifdef NXLINK_DEBUG
u64 totalSizeMB = bufferedPlaceholderWriter . GetTotalDataSize ( ) / 1000000 ;
u64 downloadSizeMB = bufferedPlaceholderWriter . GetSizeBuffered ( ) / 1000000 ;
LOG_DEBUG ( " > Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s) \r " , downloadSizeMB , totalSizeMB , downloadProgress , " % " , speed ) ;
# endif
2019-11-17 16:01:06 +01:00
2019-11-28 01:49:58 +01:00
inst : : ui : : setInstInfoText ( " Downloading " + inst : : util : : formatUrlString ( ncaFileName ) + " at " + std : : to_string ( speed ) . substr ( 0 , std : : to_string ( speed ) . size ( ) - 4 ) + " MB/s " ) ;
inst : : ui : : setInstBarPerc ( ( double ) downloadProgress ) ;
}
2019-11-17 16:01:06 +01:00
}
2019-11-30 19:20:59 +01:00
inst : : ui : : setInstBarPerc ( 100 ) ;
2019-11-17 16:01:06 +01:00
2019-11-30 19:20:59 +01:00
# ifdef NXLINK_DEBUG
u64 totalSizeMB = bufferedPlaceholderWriter . GetTotalDataSize ( ) / 1000000 ;
# endif
2019-11-17 16:01:06 +01:00
2019-11-30 19:20:59 +01:00
inst : : ui : : setInstInfoText ( " Installing " + ncaFileName + " ... " ) ;
inst : : ui : : setInstBarPerc ( 0 ) ;
2019-12-13 02:50:40 +01:00
while ( ! bufferedPlaceholderWriter . IsPlaceholderComplete ( ) & & ! tin : : install : : nsp : : stopThreads )
2019-11-17 16:01:06 +01:00
{
2019-11-30 20:53:04 +01:00
int installProgress = ( int ) ( ( ( double ) bufferedPlaceholderWriter . GetSizeWrittenToPlaceholder ( ) / ( double ) bufferedPlaceholderWriter . GetTotalDataSize ( ) ) * 100.0 ) ;
2019-11-30 19:20:59 +01:00
# ifdef NXLINK_DEBUG
u64 installSizeMB = bufferedPlaceholderWriter . GetSizeWrittenToPlaceholder ( ) / 1000000 ;
LOG_DEBUG ( " > Install Progress: %lu/%lu MB (%i%s) \r " , installSizeMB , totalSizeMB , installProgress , " % " ) ;
# endif
2019-11-28 01:49:58 +01:00
inst : : ui : : setInstBarPerc ( ( double ) installProgress ) ;
2019-11-17 16:01:06 +01:00
}
2019-11-30 19:20:59 +01:00
inst : : ui : : setInstBarPerc ( 100 ) ;
2019-11-17 16:01:06 +01:00
thrd_join ( usbThread , NULL ) ;
thrd_join ( writeThread , NULL ) ;
2019-12-13 02:50:40 +01:00
if ( tin : : install : : nsp : : stopThreads ) throw std : : runtime_error ( tin : : install : : nsp : : errorMessage . c_str ( ) ) ;
2019-11-17 16:01:06 +01:00
}
void USBNSP : : BufferData ( void * buf , off_t offset , size_t size )
{
2019-12-11 03:33:51 +01:00
LOG_DEBUG ( " buffering 0x%lx-0x%lx \n " , offset , offset + size ) ;
2019-11-17 16:01:06 +01:00
tin : : util : : USBCmdHeader header = tin : : util : : USBCmdManager : : SendFileRangeCmd ( m_nspName , offset , size ) ;
2019-12-10 01:46:02 +01:00
u8 * tempBuffer = ( u8 * ) memalign ( 0x1000 , header . dataSize ) ;
if ( tin : : util : : USBRead ( tempBuffer , header . dataSize ) = = 0 ) THROW_FORMAT ( " USB transfer timed out or failed " ) ;
memcpy ( buf , tempBuffer , header . dataSize ) ;
free ( tempBuffer ) ;
2019-11-17 16:01:06 +01:00
}
}