mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 14:15:41 +12:00
Merge pull request #380 from wheremyfoodat/scheduler
Add support for software keyboard & mii selector applets, improve APT/PTM/BOSS/misc HLE
This commit is contained in:
commit
2ff5bff00a
22 changed files with 598 additions and 27 deletions
|
@ -188,7 +188,9 @@ set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_d
|
|||
src/core/fs/ivfc.cpp src/core/fs/archive_user_save_data.cpp src/core/fs/archive_system_save_data.cpp
|
||||
)
|
||||
|
||||
set(APPLET_SOURCE_FILES src/core/applets/applet.cpp src/core/applets/mii_selector.cpp src/core/applets/software_keyboard.cpp src/core/applets/applet_manager.cpp)
|
||||
set(APPLET_SOURCE_FILES src/core/applets/applet.cpp src/core/applets/mii_selector.cpp src/core/applets/software_keyboard.cpp src/core/applets/applet_manager.cpp
|
||||
src/core/applets/error_applet.cpp
|
||||
)
|
||||
set(RENDERER_SW_SOURCE_FILES src/core/renderer_sw/renderer_sw.cpp)
|
||||
|
||||
# Frontend source files
|
||||
|
@ -244,7 +246,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
|
|||
include/services/news_u.hpp include/applets/software_keyboard.hpp include/applets/applet_manager.hpp include/fs/archive_user_save_data.hpp
|
||||
include/services/amiibo_device.hpp include/services/nfc_types.hpp include/swap.hpp include/services/csnd.hpp include/services/nwm_uds.hpp
|
||||
include/fs/archive_system_save_data.hpp include/lua_manager.hpp include/memory_mapped_file.hpp include/hydra_icon.hpp
|
||||
include/PICA/dynapica/shader_rec_emitter_arm64.hpp include/scheduler.hpp
|
||||
include/PICA/dynapica/shader_rec_emitter_arm64.hpp include/scheduler.hpp include/applets/error_applet.hpp
|
||||
)
|
||||
|
||||
cmrc_add_resource_library(
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "kernel/kernel_types.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "result/result.hpp"
|
||||
|
||||
|
@ -65,10 +68,11 @@ namespace Applets {
|
|||
};
|
||||
|
||||
struct Parameter {
|
||||
u32 senderID;
|
||||
u32 destID;
|
||||
u32 signal;
|
||||
std::vector<u8> data;
|
||||
u32 senderID; // ID of the parameter sender
|
||||
u32 destID; // ID of the app to receive parameter
|
||||
u32 signal; // Signal type (eg request)
|
||||
u32 object; // Some applets will also respond with shared memory handles for transferring data between the sender and called
|
||||
std::vector<u8> data; // Misc data
|
||||
};
|
||||
|
||||
class AppletBase {
|
||||
|
@ -80,7 +84,7 @@ namespace Applets {
|
|||
virtual const char* name() = 0;
|
||||
|
||||
// Called by APT::StartLibraryApplet and similar
|
||||
virtual Result::HorizonResult start() = 0;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) = 0;
|
||||
// Transfer parameters from application -> applet
|
||||
virtual Result::HorizonResult receiveParameter(const Parameter& parameter) = 0;
|
||||
virtual void reset() = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
#include "applets/error_applet.hpp"
|
||||
#include "applets/mii_selector.hpp"
|
||||
#include "applets/software_keyboard.hpp"
|
||||
#include "helpers.hpp"
|
||||
|
@ -11,6 +12,7 @@ namespace Applets {
|
|||
class AppletManager {
|
||||
MiiSelectorApplet miiSelector;
|
||||
SoftwareKeyboardApplet swkbd;
|
||||
ErrorApplet error;
|
||||
std::optional<Applets::Parameter> nextParameter = std::nullopt;
|
||||
|
||||
public:
|
||||
|
|
15
include/applets/error_applet.hpp
Normal file
15
include/applets/error_applet.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <string>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
|
||||
namespace Applets {
|
||||
class ErrorApplet final : public AppletBase {
|
||||
public:
|
||||
virtual const char* name() override { return "Error/EULA Agreement"; }
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
ErrorApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
};
|
||||
} // namespace Applets
|
|
@ -1,13 +1,83 @@
|
|||
#include <string>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
#include "swap.hpp"
|
||||
|
||||
namespace Applets {
|
||||
struct MiiConfig {
|
||||
u8 enableCancelButton;
|
||||
u8 enableGuestMii;
|
||||
u8 showOnTopScreen;
|
||||
std::array<u8, 0x5> pad1;
|
||||
std::array<u16_le, 0x40> title;
|
||||
std::array<u8, 0x4> pad2;
|
||||
u8 showGuestMiis;
|
||||
std::array<u8, 0x3> pad3;
|
||||
u32 initiallySelectedIndex;
|
||||
std::array<u8, 0x6> guestMiiWhitelist;
|
||||
std::array<u8, 0x64> userMiiWhitelist;
|
||||
std::array<u8, 0x2> pad4;
|
||||
u32 magicValue;
|
||||
};
|
||||
static_assert(sizeof(MiiConfig) == 0x104, "Mii config size is wrong");
|
||||
|
||||
// Some members of this struct are not properly aligned so we need pragma pack
|
||||
#pragma pack(push, 1)
|
||||
struct MiiData {
|
||||
u8 version;
|
||||
u8 miiOptions;
|
||||
u8 miiPos;
|
||||
u8 consoleID;
|
||||
|
||||
u64_be systemID;
|
||||
u32_be miiID;
|
||||
std::array<u8, 0x6> creatorMAC;
|
||||
u16 padding;
|
||||
|
||||
u16_be miiDetails;
|
||||
std::array<char16_t, 0xA> miiName;
|
||||
u8 height;
|
||||
u8 width;
|
||||
|
||||
u8 faceStyle;
|
||||
u8 faceDetails;
|
||||
u8 hairStyle;
|
||||
u8 hairDetails;
|
||||
u32_be eyeDetails;
|
||||
u32_be eyebrowDetails;
|
||||
u16_be noseDetails;
|
||||
u16_be mouthDetails;
|
||||
u16_be moustacheDetails;
|
||||
u16_be beardDetails;
|
||||
u16_be glassesDetails;
|
||||
u16_be moleDetails;
|
||||
|
||||
std::array<char16_t, 0xA> authorName;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size");
|
||||
|
||||
struct MiiResult {
|
||||
u32_be returnCode;
|
||||
u32_be isGuestMiiSelected;
|
||||
u32_be selectedGuestMiiIndex;
|
||||
MiiData selectedMiiData;
|
||||
u16_be unknown1;
|
||||
u16_be miiChecksum;
|
||||
std::array<u16_le, 0xC> guestMiiName;
|
||||
};
|
||||
static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");
|
||||
|
||||
class MiiSelectorApplet final : public AppletBase {
|
||||
public:
|
||||
virtual const char* name() override { return "Mii Selector"; }
|
||||
virtual Result::HorizonResult start() override;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
MiiResult output;
|
||||
MiiConfig config;
|
||||
MiiResult getDefaultMii();
|
||||
MiiSelectorApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
};
|
||||
} // namespace Applets
|
|
@ -1,13 +1,162 @@
|
|||
#include <array>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
#include "swap.hpp"
|
||||
|
||||
namespace Applets {
|
||||
// Software keyboard definitions adapted from libctru/Citra
|
||||
// Keyboard input filtering flags. Allows the caller to specify what input is explicitly not allowed
|
||||
namespace SoftwareKeyboardFilter {
|
||||
enum Filter : u32 {
|
||||
Digits = 1, // Disallow the use of more than a certain number of digits (0 or more)
|
||||
At = 1 << 1, // Disallow the use of the @ sign.
|
||||
Percent = 1 << 2, // Disallow the use of the % sign.
|
||||
Backslash = 1 << 3, // Disallow the use of the \ sign.
|
||||
Profanity = 1 << 4, // Disallow profanity using Nintendo's profanity filter.
|
||||
Callback = 1 << 5, // Use a callback in order to check the input.
|
||||
};
|
||||
} // namespace SoftwareKeyboardFilter
|
||||
|
||||
// Keyboard features.
|
||||
namespace SoftwareKeyboardFeature {
|
||||
enum Feature {
|
||||
Parental = 1, // Parental PIN mode.
|
||||
DarkenTopScreen = 1 << 1, // Darken the top screen when the keyboard is shown.
|
||||
PredictiveInput = 1 << 2, // Enable predictive input (necessary for Kanji input in JPN systems).
|
||||
Multiline = 1 << 3, // Enable multiline input.
|
||||
FixedWidth = 1 << 4, // Enable fixed-width mode.
|
||||
AllowHome = 1 << 5, // Allow the usage of the HOME button.
|
||||
AllowReset = 1 << 6, // Allow the usage of a software-reset combination.
|
||||
AllowPower = 1 << 7, // Allow the usage of the POWER button.
|
||||
DefaultQWERTY = 1 << 9, // Default to the QWERTY page when the keyboard is shown.
|
||||
};
|
||||
} // namespace SoftwareKeyboardFeature
|
||||
|
||||
class SoftwareKeyboardApplet final : public AppletBase {
|
||||
public:
|
||||
static constexpr int MAX_BUTTON = 3; // Maximum number of buttons that can be in the keyboard.
|
||||
static constexpr int MAX_BUTTON_TEXT_LEN = 16; // Maximum button text length, in UTF-16 code units.
|
||||
static constexpr int MAX_HINT_TEXT_LEN = 64; // Maximum hint text length, in UTF-16 code units.
|
||||
static constexpr int MAX_CALLBACK_MSG_LEN = 256; // Maximum filter callback error message length, in UTF-16 code units.
|
||||
|
||||
// Keyboard types
|
||||
enum class SoftwareKeyboardType : u32 {
|
||||
Normal, // Normal keyboard with several pages (QWERTY/accents/symbol/mobile)
|
||||
QWERTY, // QWERTY keyboard only.
|
||||
NumPad, // Number pad.
|
||||
Western, // On JPN systems, a text keyboard without Japanese input capabilities, otherwise same as SWKBD_TYPE_NORMAL.
|
||||
};
|
||||
|
||||
// Keyboard dialog buttons.
|
||||
enum class SoftwareKeyboardButtonConfig : u32 {
|
||||
SingleButton, // Ok button
|
||||
DualButton, // Cancel | Ok buttons
|
||||
TripleButton, // Cancel | I Forgot | Ok buttons
|
||||
NoButton, // No button (returned by swkbdInputText in special cases)
|
||||
};
|
||||
|
||||
// Accepted input types.
|
||||
enum class SoftwareKeyboardValidInput : u32 {
|
||||
Anything, // All inputs are accepted.
|
||||
NotEmpty, // Empty inputs are not accepted.
|
||||
NotEmptyNotBlank, // Empty or blank inputs (consisting solely of whitespace) are not accepted.
|
||||
NotBlank, // Blank inputs (consisting solely of whitespace) are not accepted, but empty inputs are.
|
||||
FixedLen, // The input must have a fixed length (specified by maxTextLength in swkbdInit)
|
||||
};
|
||||
|
||||
// Keyboard password modes.
|
||||
enum class SoftwareKeyboardPasswordMode : u32 {
|
||||
None, // Characters are not concealed.
|
||||
Hide, // Characters are concealed immediately.
|
||||
HideDelay, // Characters are concealed a second after they've been typed.
|
||||
};
|
||||
|
||||
// Keyboard filter callback return values.
|
||||
enum class SoftwareKeyboardCallbackResult : u32 {
|
||||
OK, // Specifies that the input is valid.
|
||||
Close, // Displays an error message, then closes the keyboard.
|
||||
Continue, // Displays an error message and continues displaying the keyboard.
|
||||
};
|
||||
|
||||
// Keyboard return values.
|
||||
enum class SoftwareKeyboardResult : s32 {
|
||||
None = -1, // Dummy/unused.
|
||||
InvalidInput = -2, // Invalid parameters to swkbd.
|
||||
OutOfMem = -3, // Out of memory.
|
||||
|
||||
D0Click = 0, // The button was clicked in 1-button dialogs.
|
||||
D1Click0, // The left button was clicked in 2-button dialogs.
|
||||
D1Click1, // The right button was clicked in 2-button dialogs.
|
||||
D2Click0, // The left button was clicked in 3-button dialogs.
|
||||
D2Click1, // The middle button was clicked in 3-button dialogs.
|
||||
D2Click2, // The right button was clicked in 3-button dialogs.
|
||||
|
||||
HomePressed = 10, // The HOME button was pressed.
|
||||
ResetPressed, // The soft-reset key combination was pressed.
|
||||
PowerPressed, // The POWER button was pressed.
|
||||
|
||||
ParentalOK = 20, // The parental PIN was verified successfully.
|
||||
ParentalFail, // The parental PIN was incorrect.
|
||||
|
||||
BannedInput = 30, // The filter callback returned SoftwareKeyboardCallback::CLOSE.
|
||||
};
|
||||
|
||||
struct SoftwareKeyboardConfig {
|
||||
enum_le<SoftwareKeyboardType> type;
|
||||
enum_le<SoftwareKeyboardButtonConfig> numButtonsM1;
|
||||
enum_le<SoftwareKeyboardValidInput> validInput;
|
||||
enum_le<SoftwareKeyboardPasswordMode> passwordMode;
|
||||
s32_le isParentalScreen;
|
||||
s32_le darkenTopScreen;
|
||||
u32_le filterFlags;
|
||||
u32_le saveStateFlags;
|
||||
u16_le maxTextLength;
|
||||
u16_le dictWordCount;
|
||||
u16_le maxDigits;
|
||||
std::array<std::array<u16_le, MAX_BUTTON_TEXT_LEN + 1>, MAX_BUTTON> buttonText;
|
||||
std::array<u16_le, 2> numpadKeys;
|
||||
std::array<u16_le, MAX_HINT_TEXT_LEN + 1> hintText; // Text to display when asking the user for input
|
||||
bool predictiveInput;
|
||||
bool multiline;
|
||||
bool fixedWidth;
|
||||
bool allowHome;
|
||||
bool allowReset;
|
||||
bool allowPower;
|
||||
bool unknown;
|
||||
bool defaultQwerty;
|
||||
std::array<bool, 4> buttonSubmitsText;
|
||||
u16_le language;
|
||||
|
||||
u32_le initialTextOffset; // Offset of the default text in the output SharedMemory
|
||||
u32_le dictOffset;
|
||||
u32_le initialStatusOffset;
|
||||
u32_le initialLearningOffset;
|
||||
u32_le sharedMemorySize; // Size of the SharedMemory
|
||||
u32_le version;
|
||||
|
||||
enum_le<SoftwareKeyboardResult> returnCode;
|
||||
|
||||
u32_le statusOffset;
|
||||
u32_le learningOffset;
|
||||
|
||||
u32_le textOffset; // Offset in the SharedMemory where the output text starts
|
||||
u16_le textLength; // Length in characters of the output text
|
||||
|
||||
enum_le<SoftwareKeyboardCallbackResult> callbackResult;
|
||||
std::array<u16_le, MAX_CALLBACK_MSG_LEN + 1> callbackMessage;
|
||||
bool skipAtCheck;
|
||||
std::array<u8, 0xAB> pad;
|
||||
};
|
||||
static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software keyboard config size is wrong");
|
||||
|
||||
virtual const char* name() override { return "Software Keyboard"; }
|
||||
virtual Result::HorizonResult start() override;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
SoftwareKeyboardApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
void closeKeyboard(u32 appID);
|
||||
|
||||
SoftwareKeyboardConfig config;
|
||||
};
|
||||
} // namespace Applets
|
|
@ -53,6 +53,7 @@ namespace KernelHandles {
|
|||
GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory
|
||||
FontSharedMemHandle,
|
||||
CSNDSharedMemHandle,
|
||||
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
||||
HIDSharedMemHandle,
|
||||
|
||||
MinSharedMemHandle = GSPSharedMemHandle,
|
||||
|
|
|
@ -137,6 +137,7 @@ public:
|
|||
void duplicateHandle();
|
||||
void exitThread();
|
||||
void mapMemoryBlock();
|
||||
void unmapMemoryBlock();
|
||||
void queryMemory();
|
||||
void getCurrentProcessorNumber();
|
||||
void getProcessID();
|
||||
|
|
|
@ -112,11 +112,12 @@ class Memory {
|
|||
// This tracks our OS' memory allocations
|
||||
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
|
||||
|
||||
std::array<SharedMemoryBlock, 4> sharedMemBlocks = {
|
||||
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
|
||||
SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
||||
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
||||
SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -14,6 +14,7 @@ class BOSSService {
|
|||
void cancelTask(u32 messagePointer);
|
||||
void initializeSession(u32 messagePointer);
|
||||
void getErrorCode(u32 messagePointer);
|
||||
void getNewArrivalFlag(u32 messagePointer);
|
||||
void getNsDataIdList(u32 messagePointer, u32 commandWord);
|
||||
void getOptoutFlag(u32 messagePointer);
|
||||
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
||||
|
|
|
@ -60,12 +60,22 @@ class GPUService {
|
|||
};
|
||||
static_assert(sizeof(FramebufferUpdate) == 64, "GSP::GPU::FramebufferUpdate has the wrong size");
|
||||
|
||||
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
|
||||
struct CaptureInfo {
|
||||
u32 leftFramebuffer; // Left framebuffer VA
|
||||
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
||||
u32 format;
|
||||
u32 stride;
|
||||
};
|
||||
static_assert(sizeof(CaptureInfo) == 16, "GSP::GPU::CaptureInfo has the wrong size");
|
||||
|
||||
// Service commands
|
||||
void acquireRight(u32 messagePointer);
|
||||
void flushDataCache(u32 messagePointer);
|
||||
void importDisplayCaptureInfo(u32 messagePointer);
|
||||
void registerInterruptRelayQueue(u32 messagePointer);
|
||||
void releaseRight(u32 messagePointer);
|
||||
void restoreVramSysArea(u32 messagePointer);
|
||||
void saveVramSysArea(u32 messagePointer);
|
||||
void setAxiConfigQoSMode(u32 messagePointer);
|
||||
void setBufferSwap(u32 messagePointer);
|
||||
|
@ -86,6 +96,15 @@ class GPUService {
|
|||
|
||||
void setBufferSwapImpl(u32 screen_id, const FramebufferInfo& info);
|
||||
|
||||
// Get the framebuffer info in shared memory for a given screen
|
||||
FramebufferUpdate* getFramebufferInfo(int screen) {
|
||||
// TODO: Offset depends on GSP thread being triggered
|
||||
return reinterpret_cast<FramebufferUpdate*>(&sharedMem[0x200 + screen * sizeof(FramebufferUpdate)]);
|
||||
}
|
||||
|
||||
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
|
||||
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
|
||||
|
||||
public:
|
||||
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu),
|
||||
kernel(kernel), currentPID(currentPID) {}
|
||||
|
|
|
@ -17,6 +17,7 @@ class PTMService {
|
|||
void getAdapterState(u32 messagePointer);
|
||||
void getBatteryChargeState(u32 messagePointer);
|
||||
void getBatteryLevel(u32 messagePointer);
|
||||
void getPedometerState(u32 messagePointer);
|
||||
void getStepHistory(u32 messagePointer);
|
||||
void getStepHistoryAll(u32 messagePointer);
|
||||
void getTotalStepCount(u32 messagePointer);
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
using namespace Applets;
|
||||
|
||||
AppletManager::AppletManager(Memory& mem) : miiSelector(mem, nextParameter), swkbd(mem, nextParameter) {}
|
||||
AppletManager::AppletManager(Memory& mem) : miiSelector(mem, nextParameter), swkbd(mem, nextParameter), error(mem, nextParameter) {}
|
||||
|
||||
void AppletManager::reset() {
|
||||
nextParameter = std::nullopt;
|
||||
|
||||
miiSelector.reset();
|
||||
swkbd.reset();
|
||||
error.reset();
|
||||
}
|
||||
|
||||
AppletBase* AppletManager::getApplet(u32 id) {
|
||||
|
@ -21,6 +22,9 @@ AppletBase* AppletManager::getApplet(u32 id) {
|
|||
case AppletIDs::SoftwareKeyboard:
|
||||
case AppletIDs::SoftwareKeyboard2: return &swkbd;
|
||||
|
||||
case AppletIDs::ErrDisp:
|
||||
case AppletIDs::ErrDisp2: return &error;
|
||||
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
32
src/core/applets/error_applet.cpp
Normal file
32
src/core/applets/error_applet.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "applets/error_applet.hpp"
|
||||
#include "kernel/handles.hpp"
|
||||
|
||||
using namespace Applets;
|
||||
|
||||
void ErrorApplet::reset() {}
|
||||
|
||||
Result::HorizonResult ErrorApplet::start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) {
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = appID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::WakeupByExit),
|
||||
.object = 0,
|
||||
.data = parameters, // TODO: Figure out how the data format for this applet
|
||||
};
|
||||
|
||||
nextParameter = param;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
Result::HorizonResult ErrorApplet::receiveParameter(const Applets::Parameter& parameter) {
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = parameter.destID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::Response),
|
||||
.object = KernelHandles::APTCaptureSharedMemHandle,
|
||||
.data = {},
|
||||
};
|
||||
|
||||
nextParameter = param;
|
||||
return Result::Success;
|
||||
}
|
|
@ -1,11 +1,87 @@
|
|||
#include "applets/mii_selector.hpp"
|
||||
|
||||
#include <boost/crc.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "kernel/handles.hpp"
|
||||
|
||||
using namespace Applets;
|
||||
|
||||
void MiiSelectorApplet::reset() {}
|
||||
Result::HorizonResult MiiSelectorApplet::start() { return Result::Success; }
|
||||
Result::HorizonResult MiiSelectorApplet::start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) {
|
||||
// Get mii configuration from the application
|
||||
std::memcpy(&config, ¶meters[0], sizeof(config));
|
||||
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = appID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::WakeupByExit),
|
||||
.object = 0,
|
||||
};
|
||||
|
||||
// Thanks to Citra devs as always for the default mii data and other applet help
|
||||
output = getDefaultMii();
|
||||
output.returnCode = 0; // Success
|
||||
// output.selectedMiiData = miiData;
|
||||
output.selectedGuestMiiIndex = std::numeric_limits<u32>::max();
|
||||
output.miiChecksum = boost::crc<16, 0x1021, 0, 0, false, false>(&output.selectedMiiData, sizeof(MiiData) + sizeof(output.unknown1));
|
||||
|
||||
// Copy output into the response parameter
|
||||
param.data.resize(sizeof(output));
|
||||
std::memcpy(¶m.data[0], &output, sizeof(output));
|
||||
|
||||
nextParameter = param;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
Result::HorizonResult MiiSelectorApplet::receiveParameter(const Applets::Parameter& parameter) {
|
||||
Helpers::warn("Mii Selector: Unimplemented ReceiveParameter");
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = parameter.destID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::Response),
|
||||
.object = KernelHandles::APTCaptureSharedMemHandle,
|
||||
.data = {},
|
||||
};
|
||||
|
||||
nextParameter = param;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
MiiResult MiiSelectorApplet::getDefaultMii() {
|
||||
// This data was obtained from Citra
|
||||
MiiData miiData;
|
||||
miiData.version = 0x03;
|
||||
miiData.miiOptions = 0x00;
|
||||
miiData.miiPos = 0x10;
|
||||
miiData.consoleID = 0x30;
|
||||
miiData.systemID = 0xD285B6B300C8850A;
|
||||
miiData.miiID = 0x98391EE4;
|
||||
miiData.creatorMAC = {0x40, 0xF4, 0x07, 0xB7, 0x37, 0x10};
|
||||
miiData.padding = 0x0000;
|
||||
miiData.miiDetails = 0xA600;
|
||||
miiData.miiName = {'P', 'a', 'n', 'd', 'a', '3', 'D', 'S', 0x0, 0x0};
|
||||
miiData.height = 0x40;
|
||||
miiData.width = 0x40;
|
||||
miiData.faceStyle = 0x00;
|
||||
miiData.faceDetails = 0x00;
|
||||
miiData.hairStyle = 0x21;
|
||||
miiData.hairDetails = 0x01;
|
||||
miiData.eyeDetails = 0x02684418;
|
||||
miiData.eyebrowDetails = 0x26344614;
|
||||
miiData.noseDetails = 0x8112;
|
||||
miiData.mouthDetails = 0x1768;
|
||||
miiData.moustacheDetails = 0x0D00;
|
||||
miiData.beardDetails = 0x0029;
|
||||
miiData.glassesDetails = 0x0052;
|
||||
miiData.moleDetails = 0x4850;
|
||||
miiData.authorName = {u'B', u'O', u'N', u'K', u'E', u'R'};
|
||||
|
||||
MiiResult result;
|
||||
result.returnCode = 0x0;
|
||||
result.isGuestMiiSelected = 0x0;
|
||||
result.selectedGuestMiiIndex = std::numeric_limits<u32>::max();
|
||||
result.selectedMiiData = miiData;
|
||||
result.guestMiiName.fill(0x0);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,20 +1,93 @@
|
|||
#include "applets/software_keyboard.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "kernel/handles.hpp"
|
||||
|
||||
using namespace Applets;
|
||||
|
||||
void SoftwareKeyboardApplet::reset() {}
|
||||
Result::HorizonResult SoftwareKeyboardApplet::start() { return Result::Success; }
|
||||
|
||||
Result::HorizonResult SoftwareKeyboardApplet::receiveParameter(const Applets::Parameter& parameter) {
|
||||
Helpers::warn("Software keyboard: Unimplemented ReceiveParameter");
|
||||
switch (parameter.signal) {
|
||||
// Signal == request -> Applet is asking swkbd for a shared memory handle for backing up the framebuffer before opening the applet
|
||||
case u32(APTSignal::Request): {
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = parameter.destID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::Response),
|
||||
.object = KernelHandles::APTCaptureSharedMemHandle,
|
||||
.data = {},
|
||||
};
|
||||
|
||||
nextParameter = param;
|
||||
break;
|
||||
}
|
||||
|
||||
default: Helpers::panic("Unimplemented swkbd signal %d\n", parameter.signal);
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
Result::HorizonResult SoftwareKeyboardApplet::start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) {
|
||||
if (parameters.size() < sizeof(SoftwareKeyboardConfig)) {
|
||||
Helpers::warn("SoftwareKeyboard::Start: Invalid size for keyboard configuration");
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
if (sharedMem == nullptr) {
|
||||
Helpers::warn("SoftwareKeyboard: Missing shared memory");
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
// Get keyboard configuration from the application
|
||||
std::memcpy(&config, ¶meters[0], sizeof(config));
|
||||
|
||||
const std::u16string text = u"Pand";
|
||||
u32 textAddress = sharedMem->addr;
|
||||
|
||||
// Copy text to shared memory the app gave us
|
||||
for (u32 i = 0; i < text.size(); i++) {
|
||||
mem.write16(textAddress, u16(text[i]));
|
||||
textAddress += sizeof(u16);
|
||||
}
|
||||
mem.write16(textAddress, 0); // Write UTF-16 null terminator
|
||||
|
||||
// Temporarily hardcode the pressed button to be the firs tone
|
||||
switch (config.numButtonsM1) {
|
||||
case SoftwareKeyboardButtonConfig::SingleButton: config.returnCode = SoftwareKeyboardResult::D0Click; break;
|
||||
case SoftwareKeyboardButtonConfig::DualButton: config.returnCode = SoftwareKeyboardResult::D1Click1; break;
|
||||
case SoftwareKeyboardButtonConfig::TripleButton: config.returnCode = SoftwareKeyboardResult::D2Click2; break;
|
||||
case SoftwareKeyboardButtonConfig::NoButton: config.returnCode = SoftwareKeyboardResult::None; break;
|
||||
default: Helpers::warn("Software keyboard: Invalid button mode specification"); break;
|
||||
}
|
||||
|
||||
config.textOffset = 0;
|
||||
config.textLength = static_cast<u16>(text.size());
|
||||
static_assert(offsetof(SoftwareKeyboardConfig, textOffset) == 324);
|
||||
static_assert(offsetof(SoftwareKeyboardConfig, textLength) == 328);
|
||||
|
||||
if (config.filterFlags & SoftwareKeyboardFilter::Callback) {
|
||||
Helpers::warn("Unimplemented software keyboard profanity callback");
|
||||
}
|
||||
|
||||
closeKeyboard(appID);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
void SoftwareKeyboardApplet::closeKeyboard(u32 appID) {
|
||||
Applets::Parameter param = Applets::Parameter{
|
||||
.senderID = parameter.destID,
|
||||
.senderID = appID,
|
||||
.destID = AppletIDs::Application,
|
||||
.signal = static_cast<u32>(APTSignal::Response),
|
||||
.data = {},
|
||||
.signal = static_cast<u32>(APTSignal::WakeupByExit),
|
||||
.object = 0,
|
||||
};
|
||||
|
||||
// Copy software keyboard configuration into the response parameter
|
||||
param.data.resize(sizeof(config));
|
||||
std::memcpy(¶m.data[0], &config, sizeof(config));
|
||||
|
||||
nextParameter = param;
|
||||
return Result::Success;
|
||||
}
|
|
@ -50,6 +50,7 @@ void Kernel::serviceSVC(u32 svc) {
|
|||
case 0x1D: svcClearTimer(); break;
|
||||
case 0x1E: createMemoryBlock(); break;
|
||||
case 0x1F: mapMemoryBlock(); break;
|
||||
case 0x20: unmapMemoryBlock(); break;
|
||||
case 0x21: createAddressArbiter(); break;
|
||||
case 0x22: arbitrateAddress(); break;
|
||||
case 0x23: svcCloseHandle(); break;
|
||||
|
|
|
@ -144,6 +144,7 @@ void Kernel::mapMemoryBlock() {
|
|||
printf("Mapping CSND memory block\n");
|
||||
break;
|
||||
|
||||
case KernelHandles::APTCaptureSharedMemHandle: break;
|
||||
default: Helpers::panic("Mapping unknown shared memory block: %X", block);
|
||||
}
|
||||
} else {
|
||||
|
@ -206,3 +207,12 @@ void Kernel::createMemoryBlock() {
|
|||
regs[0] = Result::Success;
|
||||
regs[1] = makeMemoryBlock(addr, size, myPermission, otherPermission);
|
||||
}
|
||||
|
||||
void Kernel::unmapMemoryBlock() {
|
||||
Handle block = regs[0];
|
||||
u32 addr = regs[1];
|
||||
logSVC("Unmap memory block (block handle = %X, addr = %08X)\n", block, addr);
|
||||
|
||||
Helpers::warn("Stubbed svcUnmapMemoryBlock!");
|
||||
regs[0] = Result::Success;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ void APTService::handleSyncRequest(u32 messagePointer) {
|
|||
case APTCommands::NotifyToWait: notifyToWait(messagePointer); break;
|
||||
case APTCommands::PreloadLibraryApplet: preloadLibraryApplet(messagePointer); break;
|
||||
case APTCommands::PrepareToStartLibraryApplet: prepareToStartLibraryApplet(messagePointer); break;
|
||||
case APTCommands::StartLibraryApplet: startLibraryApplet(messagePointer); break;
|
||||
case APTCommands::ReceiveParameter: [[likely]] receiveParameter(messagePointer); break;
|
||||
case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break;
|
||||
case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break;
|
||||
|
@ -140,6 +141,39 @@ void APTService::prepareToStartLibraryApplet(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void APTService::startLibraryApplet(u32 messagePointer) {
|
||||
const u32 appID = mem.read32(messagePointer + 4);
|
||||
const u32 bufferSize = mem.read32(messagePointer + 8);
|
||||
const Handle parameters = mem.read32(messagePointer + 16);
|
||||
const u32 buffer = mem.read32(messagePointer + 24);
|
||||
log("APT::StartLibraryApplet (app ID = %X)\n", appID);
|
||||
|
||||
Applets::AppletBase* destApplet = appletManager.getApplet(appID);
|
||||
if (destApplet == nullptr) {
|
||||
Helpers::warn("APT::StartLibraryApplet: Unimplemented dest applet ID");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x1E, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
} else {
|
||||
KernelObject* sharedMemObject = kernel.getObject(parameters);
|
||||
|
||||
const MemoryBlock* sharedMem = sharedMemObject ? sharedMemObject->getData<MemoryBlock>() : nullptr;
|
||||
std::vector<u8> data;
|
||||
data.reserve(bufferSize);
|
||||
|
||||
for (u32 i = 0; i < bufferSize; i++) {
|
||||
data.push_back(mem.read8(buffer + i));
|
||||
}
|
||||
|
||||
Result::HorizonResult result = destApplet->start(sharedMem, data, appID);
|
||||
if (resumeEvent.has_value()) {
|
||||
kernel.signalEvent(resumeEvent.value());
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x1E, 1, 0));
|
||||
mem.write32(messagePointer + 4, result);
|
||||
}
|
||||
}
|
||||
|
||||
void APTService::checkNew3DS(u32 messagePointer) {
|
||||
log("APT::CheckNew3DS\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
|
||||
|
@ -222,7 +256,7 @@ void APTService::sendParameter(u32 messagePointer) {
|
|||
|
||||
const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis?
|
||||
const u32 parameterPointer = mem.read32(messagePointer + 32);
|
||||
log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X) (Stubbed)", sourceAppID, destAppID, cmd, paramSize);
|
||||
log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X)", sourceAppID, destAppID, cmd, paramSize);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0C, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
|
@ -260,7 +294,9 @@ void APTService::sendParameter(u32 messagePointer) {
|
|||
void APTService::receiveParameter(u32 messagePointer) {
|
||||
const u32 app = mem.read32(messagePointer + 4);
|
||||
const u32 size = mem.read32(messagePointer + 8);
|
||||
log("APT::ReceiveParameter(app ID = %X, size = %04X) (STUBBED)\n", app, size);
|
||||
// Parameter data pointer is in the thread static buffer, which starts 0x100 bytes after the command buffer
|
||||
const u32 buffer = mem.read32(messagePointer + 0x100 + 4);
|
||||
log("APT::ReceiveParameter(app ID = %X, size = %04X)\n", app, size);
|
||||
|
||||
if (size > 0x1000) Helpers::panic("APT::ReceiveParameter with size > 0x1000");
|
||||
auto parameter = appletManager.receiveParameter();
|
||||
|
@ -274,14 +310,21 @@ void APTService::receiveParameter(u32 messagePointer) {
|
|||
// Size of parameter data
|
||||
mem.write32(messagePointer + 16, parameter.data.size());
|
||||
mem.write32(messagePointer + 20, 0x10);
|
||||
mem.write32(messagePointer + 24, 0);
|
||||
mem.write32(messagePointer + 24, parameter.object);
|
||||
mem.write32(messagePointer + 28, 0);
|
||||
|
||||
const u32 transferSize = std::min<u32>(size, parameter.data.size());
|
||||
for (u32 i = 0; i < transferSize; i++) {
|
||||
mem.write8(buffer + i, parameter.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void APTService::glanceParameter(u32 messagePointer) {
|
||||
const u32 app = mem.read32(messagePointer + 4);
|
||||
const u32 size = mem.read32(messagePointer + 8);
|
||||
log("APT::GlanceParameter(app ID = %X, size = %04X) (STUBBED)\n", app, size);
|
||||
// Parameter data pointer is in the thread static buffer, which starts 0x100 bytes after the command buffer
|
||||
const u32 buffer = mem.read32(messagePointer + 0x100 + 4);
|
||||
log("APT::GlanceParameter(app ID = %X, size = %04X)\n", app, size);
|
||||
|
||||
if (size > 0x1000) Helpers::panic("APT::GlanceParameter with size > 0x1000");
|
||||
auto parameter = appletManager.glanceParameter();
|
||||
|
@ -296,8 +339,13 @@ void APTService::glanceParameter(u32 messagePointer) {
|
|||
// Size of parameter data
|
||||
mem.write32(messagePointer + 16, parameter.data.size());
|
||||
mem.write32(messagePointer + 20, 0);
|
||||
mem.write32(messagePointer + 24, 0);
|
||||
mem.write32(messagePointer + 24, parameter.object);
|
||||
mem.write32(messagePointer + 28, 0);
|
||||
|
||||
const u32 transferSize = std::min<u32>(size, parameter.data.size());
|
||||
for (u32 i = 0; i < transferSize; i++) {
|
||||
mem.write8(buffer + i, parameter.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void APTService::replySleepQuery(u32 messagePointer) {
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace BOSSCommands {
|
|||
InitializeSession = 0x00010082,
|
||||
UnregisterStorage = 0x00030000,
|
||||
GetTaskStorageInfo = 0x00040000,
|
||||
GetNewArrivalFlag = 0x00070000,
|
||||
RegisterNewArrivalEvent = 0x00080002,
|
||||
SetOptoutFlag = 0x00090040,
|
||||
GetOptoutFlag = 0x000A0000,
|
||||
|
@ -37,6 +38,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) {
|
|||
switch (command) {
|
||||
case BOSSCommands::CancelTask: cancelTask(messagePointer); break;
|
||||
case BOSSCommands::GetErrorCode: getErrorCode(messagePointer); break;
|
||||
case BOSSCommands::GetNewArrivalFlag: getNewArrivalFlag(messagePointer); break;
|
||||
case BOSSCommands::GetNsDataIdList:
|
||||
case BOSSCommands::GetNsDataIdList1:
|
||||
getNsDataIdList(messagePointer, command); break;
|
||||
|
@ -240,4 +242,11 @@ void BOSSService::unregisterStorage(u32 messagePointer) {
|
|||
log("BOSS::UnregisterStorage (stubbed)\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x3, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void BOSSService::getNewArrivalFlag(u32 messagePointer) {
|
||||
log("BOSS::GetNewArrivalFlag (stubbed)\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, 0); // Flag
|
||||
}
|
|
@ -18,6 +18,7 @@ namespace ServiceCommands {
|
|||
ReleaseRight = 0x00170000,
|
||||
ImportDisplayCaptureInfo = 0x00180000,
|
||||
SaveVramSysArea = 0x00190000,
|
||||
RestoreVramSysArea = 0x001A0000,
|
||||
SetInternalPriorities = 0x001E0080,
|
||||
StoreDataCache = 0x001F0082
|
||||
};
|
||||
|
@ -51,6 +52,7 @@ void GPUService::handleSyncRequest(u32 messagePointer) {
|
|||
case ServiceCommands::ImportDisplayCaptureInfo: importDisplayCaptureInfo(messagePointer); break;
|
||||
case ServiceCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
|
||||
case ServiceCommands::ReleaseRight: releaseRight(messagePointer); break;
|
||||
case ServiceCommands::RestoreVramSysArea: restoreVramSysArea(messagePointer); break;
|
||||
case ServiceCommands::SaveVramSysArea: saveVramSysArea(messagePointer); break;
|
||||
case ServiceCommands::SetAxiConfigQoSMode: setAxiConfigQoSMode(messagePointer); break;
|
||||
case ServiceCommands::SetBufferSwap: setBufferSwap(messagePointer); break;
|
||||
|
@ -143,8 +145,7 @@ void GPUService::requestInterrupt(GPUInterrupt type) {
|
|||
// Not emulating this causes Yoshi's Wooly World, Captain Toad, Metroid 2 et al to hang
|
||||
if (type == GPUInterrupt::VBlank0 || type == GPUInterrupt::VBlank1) {
|
||||
int screen = static_cast<u32>(type) - static_cast<u32>(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom
|
||||
// TODO: Offset depends on GSP thread being triggered
|
||||
FramebufferUpdate* update = reinterpret_cast<FramebufferUpdate*>(&sharedMem[0x200 + screen * sizeof(FramebufferUpdate)]);
|
||||
FramebufferUpdate* update = getFramebufferInfo(screen);
|
||||
|
||||
if (update->dirtyFlag & 1) {
|
||||
setBufferSwapImpl(screen, update->framebufferInfo[update->index]);
|
||||
|
@ -482,10 +483,50 @@ void GPUService::saveVramSysArea(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void GPUService::restoreVramSysArea(u32 messagePointer) {
|
||||
Helpers::warn("GSP::GPU::RestoreVramSysArea (stubbed)");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x1A, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
// Used in similar fashion to the SaveVramSysArea function
|
||||
void GPUService::importDisplayCaptureInfo(u32 messagePointer) {
|
||||
Helpers::warn("GSP::GPU::ImportDisplayCaptureInfo (stubbed)");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x18, 9, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
|
||||
if (sharedMem == nullptr) {
|
||||
Helpers::warn("GSP::GPU::ImportDisplayCaptureInfo called without GSP module being properly initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
FramebufferUpdate* topScreen = getTopFramebufferInfo();
|
||||
FramebufferUpdate* bottomScreen = getBottomFramebufferInfo();
|
||||
|
||||
// Capture the relevant data for both screens and return them to the caller
|
||||
CaptureInfo topScreenCapture = {
|
||||
.leftFramebuffer = topScreen->framebufferInfo[topScreen->index].leftFramebufferVaddr,
|
||||
.rightFramebuffer = topScreen->framebufferInfo[topScreen->index].rightFramebufferVaddr,
|
||||
.format = topScreen->framebufferInfo[topScreen->index].format,
|
||||
.stride = topScreen->framebufferInfo[topScreen->index].stride,
|
||||
};
|
||||
|
||||
CaptureInfo bottomScreenCapture = {
|
||||
.leftFramebuffer = bottomScreen->framebufferInfo[bottomScreen->index].leftFramebufferVaddr,
|
||||
.rightFramebuffer = bottomScreen->framebufferInfo[bottomScreen->index].rightFramebufferVaddr,
|
||||
.format = bottomScreen->framebufferInfo[bottomScreen->index].format,
|
||||
.stride = bottomScreen->framebufferInfo[bottomScreen->index].stride,
|
||||
};
|
||||
|
||||
mem.write32(messagePointer + 8, topScreenCapture.leftFramebuffer);
|
||||
mem.write32(messagePointer + 12, topScreenCapture.rightFramebuffer);
|
||||
mem.write32(messagePointer + 16, topScreenCapture.format);
|
||||
mem.write32(messagePointer + 20, topScreenCapture.stride);
|
||||
|
||||
mem.write32(messagePointer + 24, bottomScreenCapture.leftFramebuffer);
|
||||
mem.write32(messagePointer + 28, bottomScreenCapture.rightFramebuffer);
|
||||
mem.write32(messagePointer + 32, bottomScreenCapture.format);
|
||||
mem.write32(messagePointer + 36, bottomScreenCapture.stride);
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace PTMCommands {
|
|||
GetAdapterState = 0x00050000,
|
||||
GetBatteryLevel = 0x00070000,
|
||||
GetBatteryChargeState = 0x00080000,
|
||||
GetPedometerState = 0x00090000,
|
||||
GetStepHistory = 0x000B00C2,
|
||||
GetTotalStepCount = 0x000C0000,
|
||||
GetStepHistoryAll = 0x000F0084,
|
||||
|
@ -30,6 +31,7 @@ void PTMService::handleSyncRequest(u32 messagePointer, PTMService::Type type) {
|
|||
case PTMCommands::GetAdapterState: getAdapterState(messagePointer); break;
|
||||
case PTMCommands::GetBatteryChargeState: getBatteryChargeState(messagePointer); break;
|
||||
case PTMCommands::GetBatteryLevel: getBatteryLevel(messagePointer); break;
|
||||
case PTMCommands::GetPedometerState: getPedometerState(messagePointer); break;
|
||||
case PTMCommands::GetStepHistory: getStepHistory(messagePointer); break;
|
||||
case PTMCommands::GetStepHistoryAll: getStepHistoryAll(messagePointer); break;
|
||||
case PTMCommands::GetTotalStepCount: getTotalStepCount(messagePointer); break;
|
||||
|
@ -67,11 +69,20 @@ void PTMService::getBatteryChargeState(u32 messagePointer) {
|
|||
// We're only charging if the battery is not already full
|
||||
const bool charging = config.chargerPlugged && (config.batteryPercentage < 100);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x8, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, charging ? 1 : 0);
|
||||
}
|
||||
|
||||
void PTMService::getPedometerState(u32 messagePointer) {
|
||||
log("PTM::GetPedometerState");
|
||||
constexpr bool countingSteps = true;
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, countingSteps ? 1 : 0);
|
||||
}
|
||||
|
||||
void PTMService::getBatteryLevel(u32 messagePointer) {
|
||||
log("PTM::GetBatteryLevel");
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue