diff --git a/source/main.c b/source/main.c index 7189b0a..e524190 100644 --- a/source/main.c +++ b/source/main.c @@ -22,7 +22,6 @@ #include #include #include -#include //#include "lvgl_helper.h" @@ -150,7 +149,7 @@ static int read_thread_func(void *arg) return -1; } - u8 *buf = memalign(USB_TRANSFER_ALIGNMENT, TEST_BUF_SIZE); + u8 *buf = usbAllocatePageAlignedBuffer(TEST_BUF_SIZE); if (!buf) { shared_data->read_error = true; @@ -268,7 +267,10 @@ int main(int argc, char *argv[]) Result rc = 0; - mkdir("sdmc:/nxdt_test", 0744); + ThreadSharedData shared_data = {0}; + thrd_t read_thread, write_thread; + + //mkdir("sdmc:/nxdt_test", 0744); // SSBU's Base Program NCA NcmContentInfo base_program_content_info = { @@ -330,7 +332,7 @@ int main(int argc, char *argv[]) consolePrint("ncm open storage succeeded\n"); - if (!ncaInitializeContext(base_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &base_program_content_info, &base_tik)) + /*if (!ncaInitializeContext(base_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &base_program_content_info, &base_tik)) { consolePrint("base nca initialize ctx failed\n"); goto out2; @@ -390,7 +392,7 @@ int main(int argc, char *argv[]) goto out2; } - consolePrint("bktr get file entry by path success: %.*s | 0x%lX\n", bktr_file_entry->name_length, bktr_file_entry->name, bktr_file_entry->size); + consolePrint("bktr get file entry by path success: %.*s | 0x%lX\n", bktr_file_entry->name_length, bktr_file_entry->name, bktr_file_entry->size);*/ @@ -414,7 +416,17 @@ int main(int argc, char *argv[]) consolePrint("open concatenationfile success\n");*/ - ThreadSharedData shared_data = {0}; + + + + + + consolePrint("waiting for gamecard to be ready...\n"); + + while(appletMainLoop()) + { + if (gamecardIsReady()) break; + } //shared_data.fileobj = tmp_file; shared_data.fileobj = NULL; @@ -425,36 +437,24 @@ int main(int argc, char *argv[]) consolePrint("waiting for usb connection... "); - u8 count = 0; - - while(appletMainLoop()) + if (!usbPerformHandshake()) { - /* Avoid using usbIsHostAvailable() alone inside a loop, because it can hang up the system */ - consolePrint("%u ", count); - if (usbIsHostAvailable()) break; - utilsSleep(1); - count++; - if (count == 10) break; - } - - if (count == 10) - { - consolePrint("\nusb connection not detected\n"); + consolePrint("failed\n"); goto out2; } - consolePrint("\nusb connection detected\n"); + consolePrint("success\n"); + + consolePrint("sending file properties... "); if (!usbSendFileProperties(shared_data.total_size, "gamecard.xci")) { - consolePrint("usb send file properties failed\n"); + consolePrint("failed\n"); goto out2; } - consolePrint("usb send file properties succeeded\n"); + consolePrint("success\n"); - thrd_t read_thread, write_thread; - consolePrint("creating threads\n\n"); thrd_create(&read_thread, read_thread_func, &shared_data); thrd_create(&write_thread, write_thread_func, &shared_data); @@ -475,12 +475,12 @@ int main(int argc, char *argv[]) if (prev_time == ts->tm_sec || prev_size == size) continue; - percent = (u8)((size * 100) / shared_data.total_size) + 1; + percent = (u8)((size * 100) / shared_data.total_size); prev_time = ts->tm_sec; prev_size = size; - printf("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (time(NULL) - start)); + printf("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (now - start)); consoleUpdate(NULL); } @@ -514,6 +514,7 @@ int main(int argc, char *argv[]) out2: + consolePrint("press any button to exit\n"); utilsWaitForButtonPress(); if (tmp_file) fclose(tmp_file); diff --git a/source/usb.c b/source/usb.c index ca82da0..7723095 100644 --- a/source/usb.c +++ b/source/usb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "usb.h" #include "utils.h" @@ -27,7 +28,8 @@ #define USB_CMD_HEADER_MAGIC 0x4E584454 /* "NXDT" */ -#define USB_TRANSFER_TIMEOUT (u64)30000000000 /* 10 seconds (in nanoseconds) */ +#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB */ +#define USB_TRANSFER_TIMEOUT 30 /* 30 seconds */ /* Type definitions. */ @@ -68,17 +70,17 @@ typedef struct { } UsbCommandSendFileProperties; typedef enum { - UsbStatusType_Success = 0, + UsbStatusType_Success = 0, - UsbStatusType_InvalidCommandSize = 1, - UsbStatusType_WriteCommandFailed = 2, - UsbStatusType_ReadStatusFailed = 3, - UsbStatusType_InvalidMagicWord = 4, + UsbStatusType_InvalidCommandSize = 1, + UsbStatusType_WriteCommandFailed = 2, + UsbStatusType_ReadStatusFailed = 3, + UsbStatusType_InvalidMagicWord = 4, - UsbStatusType_MalformedCommand = 5, - UsbStatusType_UnsupportedAbiVersion = 6, - UsbStatusType_UnsupportedCommand = 7, - UsbStatusType_HostIoError = 8 + UsbStatusType_MalformedCommand = 5, + UsbStatusType_UnsupportedAbiVersion = 6, + UsbStatusType_UnsupportedCommand = 7, + UsbStatusType_HostIoError = 8 } UsbStatusType; typedef struct { @@ -98,6 +100,8 @@ static u64 g_usbTransferRemainingSize = 0; /* Function prototypes. */ +static bool _usbPerformHandshake(void); + NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size); static u32 usbSendCommand(size_t cmd_size); NX_INLINE void usbLogStatusDetail(u32 status); @@ -114,8 +118,10 @@ NX_INLINE bool usbInitializeDeviceInterface(void); static bool usbInitializeDeviceInterface5x(void); static bool usbInitializeDeviceInterface1x(void); -static bool usbRead(void *buf, size_t size); -static bool usbWrite(void *buf, size_t size); +NX_INLINE bool usbIsHostAvailable(void); + +NX_INLINE bool usbRead(void *buf, size_t size); +NX_INLINE bool usbWrite(void *buf, size_t size); static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint); bool usbInitialize(void) @@ -159,11 +165,10 @@ void usbExit(void) rwlockWriteUnlock(&g_usbDeviceLock); } -bool usbIsHostAvailable(void) +void *usbAllocatePageAlignedBuffer(size_t size) { - u32 state = 0; - usbDsGetState(&state); - return (state == 5); + if (!size) return NULL; + return memalign(USB_TRANSFER_ALIGNMENT, size); } bool usbPerformHandshake(void) @@ -172,34 +177,23 @@ bool usbPerformHandshake(void) rwlockWriteLock(&(g_usbDeviceInterface.lock)); bool ret = false; - UsbCommandPerformHandshake *cmd_block = NULL; - size_t cmd_size = 0; - u32 status = UsbStatusType_Success; + time_t start = time(NULL); + time_t now = start; - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized) + while((now - start) < USB_TRANSFER_TIMEOUT) { - LOGFILE("Invalid parameters!"); - goto exit; + if (usbIsHostAvailable()) + { + /* Once the console has been connected to a host device, there's no need to keep running this loop */ + /* usbTransferData() implements its own timeout */ + ret = _usbPerformHandshake(); + break; + } + + utilsSleep(1); + now = time(NULL); } - usbPrepareCommandHeader(UsbCommandType_PerformHandshake, (u32)sizeof(UsbCommandPerformHandshake)); - - cmd_block = (UsbCommandPerformHandshake*)(g_usbTransferBuffer + sizeof(UsbCommandHeader)); - memset(cmd_block, 0, sizeof(UsbCommandPerformHandshake)); - - cmd_block->app_ver_major = VERSION_MAJOR; - cmd_block->app_ver_minor = VERSION_MINOR; - cmd_block->app_ver_micro = VERSION_MICRO; - cmd_block->abi_version = USB_ABI_VERSION; - - cmd_size = (sizeof(UsbCommandHeader) + sizeof(UsbCommandPerformHandshake)); - - status = usbSendCommand(cmd_size); - if (status != UsbStatusType_Success) usbLogStatusDetail(status); - - ret = (status == UsbStatusType_Success); - -exit: rwlockWriteUnlock(&(g_usbDeviceInterface.lock)); rwlockWriteUnlock(&g_usbDeviceLock); @@ -251,7 +245,7 @@ exit: return ret; } -bool usbSendFileData(void *data, u32 data_size) +bool usbSendFileData(void *data, u64 data_size) { rwlockWriteLock(&g_usbDeviceLock); rwlockWriteLock(&(g_usbDeviceInterface.lock)); @@ -317,6 +311,36 @@ exit: return ret; } +static bool _usbPerformHandshake(void) +{ + UsbCommandPerformHandshake *cmd_block = NULL; + size_t cmd_size = 0; + u32 status = UsbStatusType_Success; + + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized) + { + LOGFILE("Invalid parameters!"); + return false; + } + + usbPrepareCommandHeader(UsbCommandType_PerformHandshake, (u32)sizeof(UsbCommandPerformHandshake)); + + cmd_block = (UsbCommandPerformHandshake*)(g_usbTransferBuffer + sizeof(UsbCommandHeader)); + memset(cmd_block, 0, sizeof(UsbCommandPerformHandshake)); + + cmd_block->app_ver_major = VERSION_MAJOR; + cmd_block->app_ver_minor = VERSION_MINOR; + cmd_block->app_ver_micro = VERSION_MICRO; + cmd_block->abi_version = USB_ABI_VERSION; + + cmd_size = (sizeof(UsbCommandHeader) + sizeof(UsbCommandPerformHandshake)); + + status = usbSendCommand(cmd_size); + if (status != UsbStatusType_Success) usbLogStatusDetail(status); + + return (status == UsbStatusType_Success); +} + NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size) { if (cmd > UsbCommandType_SendNspHeader) return; @@ -518,6 +542,19 @@ static bool usbInitializeComms(void) rc = usbDsSetBinaryObjectStore(bos, sizeof(bos)); if (R_FAILED(rc)) LOGFILE("usbDsSetBinaryObjectStore failed! (0x%08X)", rc); } + } else { + static const UsbDsDeviceInfo device_info = { + .idVendor = 0x057e, + .idProduct = 0x3000, + .bcdDevice = 0x0100, + .Manufacturer = APP_AUTHOR, + .Product = APP_TITLE, + .SerialNumber = APP_VERSION + }; + + /* Set VID, PID and BCD */ + rc = usbDsSetVidPidBcd(&device_info); + if (R_FAILED(rc)) LOGFILE("usbDsSetVidPidBcd failed! (0x%08X)", rc); } if (R_FAILED(rc)) goto exit; @@ -822,7 +859,14 @@ static bool usbInitializeDeviceInterface1x(void) return true; } -static bool usbRead(void *buf, size_t size) +NX_INLINE bool usbIsHostAvailable(void) +{ + u32 state = 0; + Result rc = usbDsGetState(&state); + return (R_SUCCEEDED(rc) && state == 5); +} + +NX_INLINE bool usbRead(void *buf, u64 size) { rwlockWriteLock(&(g_usbDeviceInterface.lock_out)); bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_out); @@ -830,7 +874,7 @@ static bool usbRead(void *buf, size_t size) return ret; } -static bool usbWrite(void *buf, size_t size) +NX_INLINE bool usbWrite(void *buf, u64 size) { rwlockWriteLock(&(g_usbDeviceInterface.lock_in)); bool ret = usbTransferData(buf, size, g_usbDeviceInterface.endpoint_in); @@ -838,7 +882,7 @@ static bool usbWrite(void *buf, size_t size) return ret; } -static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint) +static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint) { if (!buf || ((u64)buf & (USB_TRANSFER_ALIGNMENT - 1)) > 0 || !size || !endpoint) { @@ -866,7 +910,7 @@ static bool usbTransferData(void *buf, size_t size, UsbDsEndpoint *endpoint) } /* Wait for the transfer to finish */ - rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT); + rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT * (u64)1000000000); eventClear(&(endpoint->CompletionEvent)); if (R_FAILED(rc)) diff --git a/source/usb.h b/source/usb.h index a229354..167766e 100644 --- a/source/usb.h +++ b/source/usb.h @@ -21,7 +21,6 @@ #include -#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB */ #define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB */ /// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer. @@ -30,17 +29,18 @@ bool usbInitialize(void); /// Closes the USB interface, input and output endpoints and frees the transfer buffer. void usbExit(void); -/// Checks if the console is currently connected to a host device. -bool usbIsHostAvailable(void); +/// Returns a pointer to a heap-allocated, page-aligned memory buffer that's suitable for USB transfers. +void *usbAllocatePageAlignedBuffer(size_t size); -/// Performs a handshake with the host device. Returns true if the host device replies with valid data. +/// Performs a handshake with the host device. Returns true if the host device replies with valid data within a certain time span. +/// This should be called before usbSendFileProperties(). bool usbPerformHandshake(void); -/// Sends file properties to the host device before starting a file data transfer. Must be called before usbSendFileData(). +/// Sends file properties to the host device before starting a file data transfer. Must be called before usbSendFileData(), and after usbPerformHandshake(). bool usbSendFileProperties(u64 file_size, const char *filename); -/// Performs a file data transfer. Must be called after usbSendFileProperties(). +/// Performs a file data transfer. Must be continuously called after usbSendFileProperties() until all file data has been transferred. /// Data chunk size must not exceed USB_TRANSFER_BUFFER_SIZE. -bool usbSendFileData(void *data, u32 data_size); +bool usbSendFileData(void *data, u64 data_size); #endif /* __USB_H__ */