Alternate USB mode for >=10.0.0, small fixes

This commit is contained in:
XorTroll 2020-04-14 20:05:21 +02:00
parent fbeeccb331
commit 45ed6bf530
8 changed files with 170 additions and 80 deletions

View file

@ -9,20 +9,16 @@ export UL_DEV := 0
export UL_DEFS := -DUL_DEV=$(UL_DEV) -DUL_MAJOR=$(UL_MAJOR) -DUL_MINOR=$(UL_MINOR) -DUL_MICRO=$(UL_MICRO) -DUL_VERSION=\"$(UL_VERSION)\"
export UL_COMMON_SOURCES := ../uLaunch/source ../uLaunch/source/am ../uLaunch/source/cfg ../uLaunch/source/db ../uLaunch/source/fs ../uLaunch/source/net ../uLaunch/source/os ../uLaunch/source/util
export UL_COMMON_INCLUDES := ../uLaunch/include ../master-libnx/nx/external/bsd/include
export UL_COMMON_INCLUDES := ../uLaunch/include
export UL_CXXFLAGS := -fno-rtti -fexceptions -std=gnu++17
# TODO: remove this and libnx master submodule when libnx releases
export LIBNX := $(CURDIR)/master-libnx/nx
.PHONY: all base make_hbtarget hbtarget make_daemon daemon make_menu menu clean
all: hbtarget daemon menu
base:
@mkdir -p SdOut/
@$(MAKE) -C master-libnx/
make_hbtarget:
@$(MAKE) -C uHbTarget/

@ -1 +1 @@
Subproject commit c1c71b1d96467f328d34e911781ffcdc35c6c077
Subproject commit a3c31497a7f5c7f9136fb612a9e1970500b3e8f6

@ -1 +1 @@
Subproject commit 30f3e4c33d2767126c36a51b9259051c6c42d6b5
Subproject commit da6eac986d7f67ca3dcc3a8df0c191ffbea4686f

View file

@ -35,6 +35,13 @@ namespace ams
}
}
enum class USBMode : u32
{
Invalid,
RawRGBA,
JPEG
};
AccountUid selected_uid = {};
hb::HbTargetParams hblaunch_flag = {};
hb::HbTargetParams hbapplaunch_flag = {};
@ -45,10 +52,14 @@ bool album_flag = false;
bool menu_restart_flag = false;
bool app_opened_hb = false;
AppletOperationMode console_mode;
u8 *usbbuf = nullptr;
u8 *usb_buf = nullptr;
u8 *usb_buf_read = nullptr;
cfg::Config config = {};
Thread ipc_thr;
Thread usb_thr;
USBMode usb_mode = USBMode::Invalid;
static constexpr size_t USBPacketSize = RawRGBAScreenBufferSize + sizeof(u32);
// This way the menu isn't loaded, even if nothing but the home menu is present, which outside of the debug menu is considered an invalid state
bool debug_menu = false;
@ -371,6 +382,18 @@ namespace
ams::sf::hipc::ServerManager<NumServers, ServerOptions, MaxSessions> daemon_ipc_manager;
}
static inline Result capsscCommand1204(void *buf, size_t buf_size, u64 *out_jpeg_size)
{
struct {
u32 a;
u64 b;
} in = {0, 10000000000};
return serviceDispatchInOut(capsscGetServiceSession(), 1204, in, *out_jpeg_size,
.buffer_attrs = { SfBufferAttr_HipcMapTransferAllowsNonSecure | SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { buf, buf_size } },
);
}
namespace impl
{
void IPCManagerThread(void *arg)
@ -380,18 +403,44 @@ namespace impl
daemon_ipc_manager.LoopProcess();
}
void USBViewerThread(void *arg)
void USBViewerRGBAThread(void *arg)
{
while(true)
{
bool flag;
appletGetLastForegroundCaptureImageEx(usbbuf, RawRGBAScreenBufferSize, &flag);
bool tmp_flag;
appletGetLastForegroundCaptureImageEx(usb_buf_read, RawRGBAScreenBufferSize, &tmp_flag);
appletUpdateLastForegroundCaptureImage();
usbCommsWrite(usbbuf, RawRGBAScreenBufferSize);
usbCommsWrite(usb_buf, USBPacketSize);
svcSleepThread(10'000'000l);
}
}
void USBViewerJPEGThread(void *arg)
{
while(true)
{
u64 tmp_size;
capsscCommand1204(usb_buf_read, RawRGBAScreenBufferSize, &tmp_size);
usbCommsWrite(usb_buf, USBPacketSize);
svcSleepThread(10'000'000l);
}
}
void PrepareUSBViewer()
{
usb_buf = new (std::align_val_t(0x1000)) u8[USBPacketSize]();
usb_buf_read = usb_buf + sizeof(u32);
u64 tmp_size;
auto rc = capsscCommand1204(usb_buf_read, RawRGBAScreenBufferSize, &tmp_size);
if(R_SUCCEEDED(rc)) usb_mode = USBMode::JPEG;
else
{
usb_mode = USBMode::RawRGBA;
capsscExit();
}
*(u32*)usb_buf = static_cast<u32>(usb_mode);
}
void LoopUpdate()
{
HandleGeneralChannel();
@ -486,14 +535,24 @@ namespace impl
Result LaunchIPCManagerThread()
{
R_TRY(threadCreate(&ipc_thr, &IPCManagerThread, NULL, NULL, 0x4000, 0x2b, -2));
R_TRY(threadCreate(&ipc_thr, &IPCManagerThread, nullptr, nullptr, 0x4000, 0x2b, -2));
R_TRY(threadStart(&ipc_thr));
return 0;
}
Result LaunchUSBViewerThread()
{
R_TRY(threadCreate(&usb_thr, &USBViewerThread, NULL, NULL, 0x4000, 0x2b, -2));
switch(usb_mode)
{
case USBMode::RawRGBA:
R_TRY(threadCreate(&usb_thr, &USBViewerRGBAThread, nullptr, nullptr, 0x4000, 0x2b, -2));
break;
case USBMode::JPEG:
R_TRY(threadCreate(&usb_thr, &USBViewerJPEGThread, nullptr, nullptr, 0x4000, 0x2b, -2));
break;
default:
return 0;
}
R_TRY(threadStart(&usb_thr));
return 0;
}
@ -531,7 +590,8 @@ namespace impl
if(config.viewer_usb_enabled)
{
UL_ASSERT(usbCommsInitialize());
usbbuf = new (std::align_val_t(0x1000)) u8[RawRGBAScreenBufferSize]();
UL_ASSERT(capsscInitialize());
PrepareUSBViewer();
UL_ASSERT(LaunchUSBViewerThread());
}
@ -541,7 +601,7 @@ namespace impl
// Debug testing mode
debug_menu = true;
consoleInit(NULL);
consoleInit(nullptr);
CONSOLE_FMT("Welcome to uDaemon -> debug mode menu")
CONSOLE_FMT("")
CONSOLE_FMT("(A) -> Dump system save data to sd:/ulaunch/save_dump")
@ -595,7 +655,8 @@ namespace impl
if(config.viewer_usb_enabled)
{
usbCommsExit();
operator delete[](usbbuf, std::align_val_t(0x1000));
if(usb_mode == USBMode::JPEG) capsscExit();
operator delete[](usb_buf, std::align_val_t(0x1000));
}
nsExit();

View file

@ -45,7 +45,7 @@ LIBS := -lnx
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(CURDIR)/../master-libnx/nx
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------

View file

@ -45,7 +45,7 @@ LIBS := -lnx -lpu -lfreetype -lSDL2_mixer -lopusfile -lopus -lmodplug -lmpg123 -
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(CURDIR)/../master-libnx/nx $(CURDIR)/../Plutonium/Plutonium/Output
LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/../Plutonium/Plutonium/Output
#---------------------------------------------------------------------------------

View file

@ -37,18 +37,18 @@ namespace uViewer
public void RefreshBackups()
{
Array.Copy(Main.CaptureBlocks[5], CaptureBackups[4], CaptureBackups[4].Length);
Array.Copy(Main.CaptureBlocks[4], CaptureBackups[3], CaptureBackups[3].Length);
Array.Copy(Main.CaptureBlocks[3], CaptureBackups[2], CaptureBackups[2].Length);
Array.Copy(Main.CaptureBlocks[2], CaptureBackups[1], CaptureBackups[1].Length);
Array.Copy(Main.CaptureBlocks[1], CaptureBackups[0], CaptureBackups[0].Length);
Buffer.BlockCopy(Main.CaptureBlocks[5], 0, CaptureBackups[4], 0, CaptureBackups[4].Length);
Buffer.BlockCopy(Main.CaptureBlocks[4], 0, CaptureBackups[3], 0, CaptureBackups[3].Length);
Buffer.BlockCopy(Main.CaptureBlocks[3], 0, CaptureBackups[2], 0, CaptureBackups[2].Length);
Buffer.BlockCopy(Main.CaptureBlocks[2], 0, CaptureBackups[1], 0, CaptureBackups[1].Length);
Buffer.BlockCopy(Main.CaptureBlocks[1], 0, CaptureBackups[0], 0, CaptureBackups[0].Length);
}
private void ScreenshotList_SelectedIndexChanged(object sender, EventArgs e)
{
if (ScreenshotList.SelectedIndex >= 0)
if(ScreenshotList.SelectedIndex >= 0)
{
ViewerMainForm.ApplyRGBAToPictureBox(ScreenshotBox, CaptureBackups[ScreenshotList.SelectedIndex]);
ViewerMainForm.ApplyModeDelegate(ScreenshotBox, CaptureBackups[ScreenshotList.SelectedIndex]);
Refresh();
}
}
@ -57,7 +57,7 @@ namespace uViewer
{
RefreshBackups();
ScreenshotList.SelectedIndex = 0;
ViewerMainForm.ApplyRGBAToPictureBox(ScreenshotBox, CaptureBackups[ScreenshotList.SelectedIndex]);
ViewerMainForm.ApplyModeDelegate(ScreenshotBox, CaptureBackups[ScreenshotList.SelectedIndex]);
Refresh();
}

View file

@ -1,33 +1,76 @@
using System;
using System.Collections.Generic;
using libusbK;
using System;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Drawing;
using System.Linq;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using libusbK;
namespace uViewer
{
public enum USBMode : uint
{
Invalid,
RawRGBA,
JPEG,
}
public partial class ViewerMainForm : Form
{
private UsbK USB = null;
private Thread USBThread;
private Thread USBThread = null;
private ToolboxForm Toolbox;
private ToolboxForm Toolbox = null;
private static MemoryStream BaseStream = new MemoryStream((int)RawRGBAScreenBufferSize);
private static USBMode Mode = USBMode.Invalid;
public delegate void ApplyTypeImplDelegate(PictureBox Box, byte[] Data);
public static ApplyTypeImplDelegate ApplyModeDelegate = null;
public delegate void ApplyDelegate(byte[] data);
private static unsafe void ApplyRGBA(PictureBox Box, byte[] RGBA)
{
var bmp = Box.Image as Bitmap;
BitmapData img = bmp.LockBits(new Rectangle(0, 0, 1280, 720), ImageLockMode.ReadWrite, bmp.PixelFormat);
fixed (byte* raw_data = RGBA) unchecked
{
uint* ptr = (uint*)raw_data;
ptr++;
uint* image = (uint*)img.Scan0.ToPointer();
uint* ptr_end = ptr + 720 * 1280;
while (ptr != ptr_end)
{
uint argb = *ptr << 8;
*image = ((argb & 0x0000FF00) << 8) | ((argb & 0x00FF0000) >> 8) | ((argb & 0xFF000000) >> 24) | 0xFF000000;
image++;
ptr++;
}
}
bmp.UnlockBits(img);
}
private static void ApplyJPEG(PictureBox Box, byte[] JPEG)
{
BaseStream.Position = 0;
BaseStream.Write(JPEG, 4, (int)RawRGBAScreenBufferSize);
Box.Image = Image.FromStream(BaseStream);
}
public const long RawRGBAScreenBufferSize = 1280 * 720 * 4;
public const long USBPacketSize = RawRGBAScreenBufferSize + 4;
public byte[][] CaptureBlocks = new byte[][]
{
new byte[RawRGBAScreenBufferSize], // Current block
new byte[RawRGBAScreenBufferSize], // Temporary blocks (5)
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
new byte[RawRGBAScreenBufferSize],
new byte[USBPacketSize], // Current block
new byte[USBPacketSize], // Temporary blocks (5)
new byte[USBPacketSize],
new byte[USBPacketSize],
new byte[USBPacketSize],
new byte[USBPacketSize],
};
public ViewerMainForm(UsbK USB)
@ -56,7 +99,7 @@ namespace uViewer
if(USB == null)
{
MessageBox.Show("Unable to connect to uLaunch via USB-C cable.", "Unable to connect");
Environment.Exit(Environment.ExitCode);
Environment.Exit(1);
}
base.OnShown(e);
}
@ -70,13 +113,29 @@ namespace uViewer
{
try
{
USB.ReadPipe(0x81, CaptureBlocks[0], CaptureBlocks[0].Length, out _, IntPtr.Zero);
Array.Copy(CaptureBlocks[4], CaptureBlocks[5], CaptureBlocks[4].Length);
Array.Copy(CaptureBlocks[3], CaptureBlocks[4], CaptureBlocks[3].Length);
Array.Copy(CaptureBlocks[2], CaptureBlocks[3], CaptureBlocks[2].Length);
Array.Copy(CaptureBlocks[1], CaptureBlocks[2], CaptureBlocks[1].Length);
Array.Copy(CaptureBlocks[0], CaptureBlocks[1], CaptureBlocks[0].Length);
ApplyRGBAInternal(CaptureBlocks[0]);
USB.ReadPipe(0x81, CaptureBlocks[0], (int)USBPacketSize, out _, IntPtr.Zero);
if(Mode == USBMode.Invalid)
{
var mode_raw = BitConverter.ToUInt32(CaptureBlocks[0], 0);
Mode = (USBMode)mode_raw;
switch(Mode)
{
case USBMode.RawRGBA:
ApplyModeDelegate = ApplyRGBA;
break;
case USBMode.JPEG:
ApplyModeDelegate = ApplyJPEG;
break;
default:
break;
}
}
Buffer.BlockCopy(CaptureBlocks[4], 0, CaptureBlocks[5], 0, (int)USBPacketSize);
Buffer.BlockCopy(CaptureBlocks[3], 0, CaptureBlocks[4], 0, (int)USBPacketSize);
Buffer.BlockCopy(CaptureBlocks[2], 0, CaptureBlocks[3], 0, (int)USBPacketSize);
Buffer.BlockCopy(CaptureBlocks[1], 0, CaptureBlocks[2], 0, (int)USBPacketSize);
Buffer.BlockCopy(CaptureBlocks[0], 0, CaptureBlocks[1], 0, (int)USBPacketSize);
ApplyDataImpl(CaptureBlocks[0]);
}
catch
{
@ -87,45 +146,19 @@ namespace uViewer
public static void InitializePictureBox(PictureBox Box)
{
int w = 1280;
int h = 720;
Box.Image = new Bitmap(w, h, PixelFormat.Format32bppArgb);
Box.Image = new Bitmap(1280, 720, PixelFormat.Format32bppArgb);
}
public static unsafe void ApplyRGBAToPictureBox(PictureBox Box, byte[] RGBA)
public void ApplyDataImpl(byte[] data)
{
var bmp = Box.Image as Bitmap;
BitmapData img = bmp.LockBits(new Rectangle(0, 0, 1280, 720), ImageLockMode.ReadWrite, bmp.PixelFormat);
fixed (byte* rawData = RGBA) unchecked
if(CaptureBox.InvokeRequired)
{
uint* ptr = (uint*)rawData;
uint* image = (uint*)img.Scan0.ToPointer();
uint* ptrEnd = ptr + 720 * 1280;
while (ptr != ptrEnd)
{
uint argb = *ptr << 8;
*image = ((argb & 0x0000FF00) << 8) | ((argb & 0x00FF0000) >> 8) | ((argb & 0xFF000000) >> 24) | 0xFF000000;
image++; ptr++;
}
}
bmp.UnlockBits(img);
}
public delegate void ApplyDelegate(byte[] data);
public void ApplyRGBAInternal(byte[] data)
{
if (CaptureBox.InvokeRequired)
{
var d = new ApplyDelegate(ApplyRGBAInternal);
var d = new ApplyDelegate(ApplyDataImpl);
CaptureBox.Invoke(d, data);
}
else
{
ApplyRGBAToPictureBox(CaptureBox, data);
ApplyModeDelegate(CaptureBox, data);
Refresh();
}
}