This repository has been archived on 2021-12-25. You can view files and clone it, but cannot push or open issues or pull requests.
Awoo-Installer/source/install/usb_nsp.cpp

220 lines
8.0 KiB
C++
Raw Normal View History

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"
#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"
#include "util/usb_comms_awoo.h"
2019-11-17 16:01:06 +01:00
2019-12-13 17:04:42 +01:00
bool stopThreads;
std::string errorMessage;
2019-11-17 16:01:06 +01:00
namespace tin::install::nsp
{
2019-12-13 02:50:40 +01:00
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 17:04:42 +01:00
while (sizeRemaining && !stopThreads)
2019-11-17 16:01:06 +01:00
{
tmpSizeRead = awoo_usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000));
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 17:04:42 +01:00
stopThreads = true;
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 17:04:42 +01:00
while (sizeRemaining && !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 17:04:42 +01:00
stopThreads = true;
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 17:04:42 +01:00
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete() && !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 17:04:42 +01:00
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 17:04:42 +01:00
while (!bufferedPlaceholderWriter.IsBufferDataComplete() && !stopThreads)
2019-11-17 16:01:06 +01:00
{
u64 newTime = armGetSystemTick();
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;
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 17:04:42 +01:00
while (!bufferedPlaceholderWriter.IsPlaceholderComplete() && !stopThreads)
2019-11-17 16:01:06 +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 17:04:42 +01:00
if (stopThreads) throw std::runtime_error(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);
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
}
}