2019-11-30 16:12:45 +00:00
# include "install/usb_xci.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"
# include "error.hpp"
# include "debug.h"
# include "sdInstall.hpp"
# include "util/util.hpp"
namespace tin : : install : : xci
{
USBXCI : : USBXCI ( std : : string xciName ) :
m_xciName ( xciName )
{
}
struct USBFuncArgs
{
std : : string xciName ;
tin : : data : : BufferedPlaceholderWriter * bufferedPlaceholderWriter ;
u64 hfs0Offset ;
u64 ncaSize ;
} ;
int USBThreadFunc ( void * in )
{
USBFuncArgs * args = reinterpret_cast < USBFuncArgs * > ( in ) ;
tin : : util : : USBCmdHeader header = tin : : util : : USBCmdManager : : SendFileRangeCmd ( args - > xciName , args - > hfs0Offset , args - > ncaSize ) ;
u8 * buf = ( u8 * ) memalign ( 0x1000 , 0x800000 ) ;
u64 sizeRemaining = header . dataSize ;
size_t tmpSizeRead = 0 ;
try
{
while ( sizeRemaining )
{
tmpSizeRead = usbCommsRead ( buf , std : : min ( sizeRemaining , ( u64 ) 0x800000 ) ) ;
2019-12-05 18:18:33 +00:00
if ( tmpSizeRead = = 0 ) THROW_FORMAT ( " USB error " ) ;
2019-11-30 16:12:45 +00:00
sizeRemaining - = tmpSizeRead ;
while ( true )
{
if ( args - > bufferedPlaceholderWriter - > CanAppendData ( tmpSizeRead ) )
break ;
}
args - > bufferedPlaceholderWriter - > AppendData ( buf , tmpSizeRead ) ;
}
}
catch ( std : : exception & e )
{
2019-11-30 17:12:59 +00:00
LOG_DEBUG ( " An error occurred: \n %s " , e . what ( ) ) ;
2019-11-30 16:12:45 +00:00
}
free ( buf ) ;
return 0 ;
}
int USBPlaceholderWriteFunc ( void * in )
{
USBFuncArgs * args = reinterpret_cast < USBFuncArgs * > ( in ) ;
while ( ! args - > bufferedPlaceholderWriter - > IsPlaceholderComplete ( ) )
{
if ( args - > bufferedPlaceholderWriter - > CanWriteSegmentToPlaceholder ( ) )
args - > bufferedPlaceholderWriter - > WriteSegmentToPlaceholder ( ) ;
}
return 0 ;
}
void USBXCI : : StreamToPlaceholder ( std : : shared_ptr < nx : : ncm : : ContentStorage > & contentStorage , NcmContentId placeholderId )
{
const HFS0FileEntry * fileEntry = this - > GetFileEntryByNcaId ( placeholderId ) ;
std : : string ncaFileName = this - > GetFileEntryName ( fileEntry ) ;
2019-11-30 17:12:59 +00:00
LOG_DEBUG ( " Retrieving %s \n " , ncaFileName . c_str ( ) ) ;
2019-11-30 16:12:45 +00:00
size_t ncaSize = fileEntry - > fileSize ;
tin : : data : : BufferedPlaceholderWriter bufferedPlaceholderWriter ( contentStorage , placeholderId , ncaSize ) ;
USBFuncArgs args ;
args . xciName = m_xciName ;
args . bufferedPlaceholderWriter = & bufferedPlaceholderWriter ;
args . hfs0Offset = this - > GetDataOffset ( ) + fileEntry - > dataOffset ;
args . ncaSize = ncaSize ;
thrd_t usbThread ;
thrd_t writeThread ;
thrd_create ( & usbThread , USBThreadFunc , & args ) ;
thrd_create ( & writeThread , USBPlaceholderWriteFunc , & args ) ;
u64 freq = armGetSystemTickFreq ( ) ;
u64 startTime = armGetSystemTick ( ) ;
size_t startSizeBuffered = 0 ;
double speed = 0.0 ;
2019-11-30 18:20:59 +00:00
inst : : ui : : setInstBarPerc ( 0 ) ;
2019-11-30 16:12:45 +00:00
while ( ! bufferedPlaceholderWriter . IsBufferDataComplete ( ) )
{
u64 newTime = armGetSystemTick ( ) ;
2019-11-30 18:42:55 +00:00
if ( newTime - startTime > = freq * 0.5 )
2019-11-30 16:12:45 +00: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 19:53:04 +00:00
int downloadProgress = ( int ) ( ( ( double ) bufferedPlaceholderWriter . GetSizeBuffered ( ) / ( double ) bufferedPlaceholderWriter . GetTotalDataSize ( ) ) * 100.0 ) ;
2019-11-30 18:20:59 +00: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-30 16:12:45 +00: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-30 18:20:59 +00:00
inst : : ui : : setInstBarPerc ( 100 ) ;
# ifdef NXLINK_DEBUG
u64 totalSizeMB = bufferedPlaceholderWriter . GetTotalDataSize ( ) / 1000000 ;
# endif
2019-11-30 16:12:45 +00:00
2019-11-30 18:20:59 +00:00
inst : : ui : : setInstInfoText ( " Installing " + ncaFileName + " ... " ) ;
inst : : ui : : setInstBarPerc ( 0 ) ;
2019-11-30 16:12:45 +00:00
while ( ! bufferedPlaceholderWriter . IsPlaceholderComplete ( ) )
{
2019-11-30 19:53:04 +00:00
int installProgress = ( int ) ( ( ( double ) bufferedPlaceholderWriter . GetSizeWrittenToPlaceholder ( ) / ( double ) bufferedPlaceholderWriter . GetTotalDataSize ( ) ) * 100.0 ) ;
2019-11-30 18:20:59 +00: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-30 16:12:45 +00:00
inst : : ui : : setInstBarPerc ( ( double ) installProgress ) ;
}
2019-11-30 18:20:59 +00:00
inst : : ui : : setInstBarPerc ( 100 ) ;
2019-11-30 16:12:45 +00:00
thrd_join ( usbThread , NULL ) ;
thrd_join ( writeThread , NULL ) ;
}
void USBXCI : : BufferData ( void * buf , off_t offset , size_t size )
{
2019-11-30 17:12:59 +00:00
LOG_DEBUG ( " buffering 0x%lx-0x%lx " , offset , offset + size ) ;
2019-11-30 16:12:45 +00:00
tin : : util : : USBCmdHeader header = tin : : util : : USBCmdManager : : SendFileRangeCmd ( m_xciName , offset , size ) ;
2019-12-06 21:04:16 +00:00
u8 * ourBuffer = ( u8 * ) memalign ( 0x1000 , header . dataSize ) ;
if ( tin : : util : : USBRead ( ourBuffer , header . dataSize ) = = 0 ) THROW_FORMAT ( " USB error " ) ;
memcpy ( buf , ourBuffer , header . dataSize ) ;
2019-11-30 16:12:45 +00:00
}
}