From f6c2050e485be925e7bfd500be51b22cdd832850 Mon Sep 17 00:00:00 2001 From: ZeroSkill1 Date: Sat, 11 Apr 2026 15:01:23 +0300 Subject: [PATCH] Complete MCU services implementation --- libctru/include/3ds.h | 8 + libctru/include/3ds/services/mcu_common.h | 287 +++++ libctru/include/3ds/services/mcucam.h | 32 + libctru/include/3ds/services/mcucdc.h | 25 + libctru/include/3ds/services/mcugpu.h | 106 ++ libctru/include/3ds/services/mcuhid.h | 111 ++ libctru/include/3ds/services/mcuhwc.h | 96 +- libctru/include/3ds/services/mcunwm.h | 68 ++ libctru/include/3ds/services/mcupls.h | 74 ++ libctru/include/3ds/services/mcurtc.h | 568 ++++++++++ libctru/include/3ds/services/mcusnd.h | 38 + libctru/source/services/mcucam.c | 53 + libctru/source/services/mcucdc.c | 39 + libctru/source/services/mcugpu.c | 216 ++++ libctru/source/services/mcuhid.c | 226 ++++ libctru/source/services/mcuhwc.c | 174 ++- libctru/source/services/mcunwm.c | 132 +++ libctru/source/services/mcupls.c | 156 +++ libctru/source/services/mcurtc.c | 1224 +++++++++++++++++++++ libctru/source/services/mcusnd.c | 68 ++ 20 files changed, 3615 insertions(+), 86 deletions(-) create mode 100644 libctru/include/3ds/services/mcu_common.h create mode 100644 libctru/include/3ds/services/mcucam.h create mode 100644 libctru/include/3ds/services/mcucdc.h create mode 100644 libctru/include/3ds/services/mcugpu.h create mode 100644 libctru/include/3ds/services/mcuhid.h create mode 100644 libctru/include/3ds/services/mcunwm.h create mode 100644 libctru/include/3ds/services/mcupls.h create mode 100644 libctru/include/3ds/services/mcurtc.h create mode 100644 libctru/include/3ds/services/mcusnd.h create mode 100644 libctru/source/services/mcucam.c create mode 100644 libctru/source/services/mcucdc.c create mode 100644 libctru/source/services/mcugpu.c create mode 100644 libctru/source/services/mcuhid.c create mode 100644 libctru/source/services/mcunwm.c create mode 100644 libctru/source/services/mcupls.c create mode 100644 libctru/source/services/mcurtc.c create mode 100644 libctru/source/services/mcusnd.c diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 571565f45..07aa4192b 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -81,7 +81,15 @@ extern "C" { #include <3ds/services/srvpm.h> #include <3ds/services/loader.h> #include <3ds/services/y2r.h> +#include <3ds/services/mcucam.h> +#include <3ds/services/mcugpu.h> +#include <3ds/services/mcuhid.h> +#include <3ds/services/mcurtc.h> +#include <3ds/services/mcusnd.h> +#include <3ds/services/mcunwm.h> #include <3ds/services/mcuhwc.h> +#include <3ds/services/mcupls.h> +#include <3ds/services/mcucdc.h> #include <3ds/services/cdcchk.h> #include <3ds/gpu/gx.h> diff --git a/libctru/include/3ds/services/mcu_common.h b/libctru/include/3ds/services/mcu_common.h new file mode 100644 index 000000000..4a03d1431 --- /dev/null +++ b/libctru/include/3ds/services/mcu_common.h @@ -0,0 +1,287 @@ +/** + * @file mcu_common.h + * @brief Common MCU-related definitions. + */ + +#pragma once + +#include <3ds/types.h> + +/// SRV notifications published by the MCU system module. +enum MCU_InterruptNotification +{ + MCUNOTIF_SHELL_STATE_CHANGE = 0x200, ///< The shell state has changed. + MCUNOTIF_POWER_BUTTON_PRESSED = 0x202, ///< The power button was pressed. + MCUNOTIF_POWER_BUTTON_HELD = 0x203, ///< The power button was held. + MCUNOTIF_HOME_BUTTON_PRESSED = 0x204, ///< The HOME button was pressed. + MCUNOTIF_HOME_BUTTON_RELEASED = 0x205, ///< The HOME button was released. + MCUNOTIF_WLAN_SWITCH_TRIGGERED = 0x206, ///< The WiFi switch was triggered. + MCUNOTIF_FATAL_HW_ERROR = 0x20C, ///< MCU watchdog reset occurred. + MCUNOTIF_AC_ADAPTER_REMOVED = 0x20D, ///< The AC adapter was disconnected. + MCUNOTIF_AC_ADAPTER_CONNECTED = 0x20E, ///< The AC adapter was connected. + MCUNOTIF_STARTED_CHARGING = 0x20F, ///< The battery started charging. + MCUNOTIF_STOPPED_CHARGING = 0x210, ///< The battery stopped charging. +}; + +/// MCU interrupts. +enum MCU_Interrupt +{ + MCUINT_POWER_BUTTON_PRESS = BIT(0), ///< The power button was pressed. + MCUINT_POWER_BUTTON_HELD = BIT(1), ///< The power button was held. + MCUINT_HOME_BUTTON_PRESS = BIT(2), ///< The HOME button was pressed. + MCUINT_HOME_BUTTON_RELEASE = BIT(3), ///< The HOME button was released. + MCUINT_WLAN_SWITCH_TRIGGER = BIT(4), ///< The WiFi switch was triggered. + MCUINT_SHELL_CLOSE = BIT(5), ///< The shell was closed (or sleep switch turned off). + MCUINT_SHELL_OPEN = BIT(6), ///< The shell was opened (or sleep switch turned on). + MCUINT_FATAL_HW_ERROR = BIT(7), ///< MCU watchdog reset occurred. + MCUINT_AC_ADAPTER_REMOVED = BIT(8), ///< The AC adapter was disconnected. + MCUINT_AC_ADAPTER_PLUGGED_IN = BIT(9), ///< The AC adapter was connected. + MCUINT_RTC_ALARM = BIT(10), ///< The RTC alarm time has been reached. + MCUINT_ACCELEROMETER_I2C_MANUAL_IO = BIT(11), ///< The manual accelerometer I²C read/write operation has completed. + MCUINT_ACCELEROMETER_NEW_SAMPLE = BIT(12), ///< A new accelerometer sample is available. + MCUINT_CRITICAL_BATTERY = BIT(13), ///< The battery is critically low. + MCUINT_CHARGING_STOP = BIT(14), ///< The battery stopped charging. + MCUINT_CHARGING_START = BIT(15), ///< The battery started charging. + + MCUINT_VOL_SLIDER = BIT(22), ///< The position of the volume slider changed. + + MCUINT_LCD_OFF = BIT(24), ///< The LCDs turned off. + MCUINT_LCD_ON = BIT(25), ///< The LCDs turned on. + MCUINT_BOT_BACKLIGHT_OFF = BIT(26), ///< The bottom screen backlight turned off. + MCUINT_BOT_BACKLIGHT_ON = BIT(27), ///< The bottom screen backlight turned on. + MCUINT_TOP_BACKLIGHT_OFF = BIT(28), ///< The top screen backlight turned off. + MCUINT_TOP_BACKLIGHT_ON = BIT(29), ///< The top screen backlight turned on. +}; + +/// MCU register IDs. +enum MCU_RegisterId +{ + MCUREG_VERSION_HIGH = 0x0, ///< Major version of the MCU firmware. + MCUREG_VERSION_LOW = 0x1, ///< Minor version of the MCU firmware. + + MCUREG_RESET_EVENTS = 0x2, ///< @ref MCU_ResetEventFlags + + MCUREG_VCOM_TOP = 0x3, ///< Flicker/VCOM value for the top screen. + MCUREG_VCOM_BOTTOM = 0x4, ///< Flicker/VCOM value for the bottom screen. + + MCUREG_FIRMWARE_UPLOAD_0 = 0x5, ///< Firmware upload register. + MCUREG_FIRMWARE_UPLOAD_1 = 0x6, ///< Firmware upload register. + MCUREG_FIRMWARE_UPLOAD_2 = 0x7, ///< Firmware upload register. + + MCUREG_3D_SLIDER_POSITION = 0x8, ///< Position of the 3D slider. + MCUREG_VOLUME_SLIDER_POSITION = 0x9, ///< Position of the volume slider. + + MCUREG_BATTERY_PCB_TEMPERATURE = 0xA, ///< Temperature of the battery, measured on a sensor on the PCB. + MCUREG_BATTERY_PERCENTAGE_INT = 0xB, ///< Integer part of the battery percentage. + MCUREG_BATTERY_PERCENTAGE_FRAC = 0xC, ///< Fractional part of the battery percentage. + MCUREG_BATTERY_VOLTAGE = 0xD, ///< Voltage of the battery, in units of 20 mV. + + MCUREG_POWER_STATUS = 0xF, ///< @ref MCU_PowerStatusFlags + + MCUREG_LEGACY_VERSION_HIGH = 0xF, ///< (Old MCU_FIRM only) Major firmware version. + MCUREG_LEGACY_VERSION_LOW = 0x10, ///< (Old MCU_FIRM only) Minor firmware version. + MCUREG_LEGACY_FIRM_UPLOAD = 0x3B, ///< (Old MCU_FIRM only) Firmware upload register. + + MCUREG_RECEIVED_IRQS = 0x10, ///< Bitmask of received IRQs. @ref MCU_Interrupt + MCUREG_IRQ_MASK = 0x18, ///< Bitmask of enabled IRQs. @ref MCU_Interrupt + + MCUREG_PWR_CTL = 0x20, ///< @ref MCU_PowerTrigger + MCUREG_LCD_PWR_CTL = 0x22, ///< @ref MCU_PowerStatusFlags + MCUREG_MCU_RESET_CTL = 0x23, ///< Writing 'r' to this register resets the MCU. Stubbed on retail. + MCUREG_FORCE_SHUTDOWN_DELAY = 0x24, ///< The amount of time, in units of 0.125s, for which the power button needs to be held to trigger a hard shutdown. + + MCUREG_VOLUME_UNK_25 = 0x25, ///< Unknown register. Used in mcu::SND + MCUREG_UNK_26 = 0x26, ///< Unknown register. Used in mcu::CDC + + MCUREG_LED_BRIGHTNESS_STATE = 0x28, ///< Brightness of the status LEDs. + MCUREG_POWER_LED_STATE = 0x29, ///< @ref MCU_PowerLedState + MCUREG_WLAN_LED_STATE = 0x2A, ///< Controls the WiFi LED. + MCUREG_CAMERA_LED_STATE = 0x2B, ///< Controls the camera LED (on models that have one). + MCUREG_3D_LED_STATE = 0x2C, ///< Controls the 3D LED (on models that have one). + MCUREG_NOTIFICATION_LED_STATE = 0x2D, ///< @ref MCU_InfoLedPattern + MCUREG_NOTIFICATION_LED_CYCLE_STATE = 0x2E, ///< Bit 0 is set if the info (notification) LED has started a new cycle of its pattern. + + MCUREG_RTC_TIME_SECOND = 0x30, ///< RTC second. + MCUREG_RTC_TIME_MINUTE = 0x31, ///< RTC minute. + MCUREG_RTC_TIME_HOUR = 0x32, ///< RTC hour. + MCUREG_RTC_TIME_WEEKDAY = 0x33, ///< RTC day of the week. + MCUREG_RTC_TIME_DAY = 0x34, ///< RTC day of the month. + MCUREG_RTC_TIME_MONTH = 0x35, ///< RTC month. + MCUREG_RTC_TIME_YEAR = 0x36, ///< RTC year. + MCUREG_RTC_TIME_CORRECTION = 0x37, ///< RTC subsecond (RSUBC) correction value. + + MCUREG_RTC_ALARM_MINUTE = 0x38, ///< RTC alarm minute. + MCUREG_RTC_ALARM_HOUR = 0x39, ///< RTC alarm hour. + MCUREG_RTC_ALARM_DAY = 0x3A, ///< RTC alarm day. + MCUREG_RTC_ALARM_MONTH = 0x3B, ///< RTC alarm month. + MCUREG_RTC_ALARM_YEAR = 0x3C, ///< RTC alarm year. + + MCUREG_TICK_COUNTER_LSB = 0x3D, ///< MCU tick counter value (low byte). + MCUREG_TICK_COUNTER_MSB = 0x3E, ///< MCU tick counter value (high byte). + + MCUREG_SENSOR_CONFIG = 0x40, ///< @ref MCU_SensorConfig + + MCUREG_ACCELEROMETER_MANUAL_REGID_R = 0x41, ///< Hardware register ID for use in manual accelerometer I²C reads. + MCUREG_ACCELEROMETER_MANUAL_REGID_W = 0x43, ///< Hardware reigster ID for use in manual accelerometer I²C writes. + MCUREG_ACCELEROMETER_MANUAL_IO = 0x44, ///< Data register for manual accelerometer reads/writes. + MCUREG_ACCELEROMETER_OUTPUT_X_LSB = 0x45, ///< Accelerometer X coordinate (low byte). + MCUREG_ACCELEROMETER_OUTPUT_X_MSB = 0x46, ///< Accelerometer X coordinate (high byte). + MCUREG_ACCELEROMETER_OUTPUT_Y_LSB = 0x47, ///< Accelerometer Y coordinate (low byte). + MCUREG_ACCELEROMETER_OUTPUT_Y_MSB = 0x48, ///< Accelerometer Y coordinate (high byte). + MCUREG_ACCELEROMETER_OUTPUT_Z_LSB = 0x49, ///< Accelerometer Z coordinate (low byte). + MCUREG_ACCELEROMETER_OUTPUT_Z_MSB = 0x4A, ///< Accelerometer Z coordinate (high byte). + + MCUREG_PEDOMETER_STEPS_LOWBYTE = 0x4B, ///< Pedometer step count (low byte). + MCUREG_PEDOMETER_STEPS_MIDDLEBYTE = 0x4C, ///< Pedometer step count (middle byte). + MCUREG_PEDOMETER_STEPS_HIGHBYTE = 0x4D, ///< Pedometer step count (high byte). + MCUREG_PEDOMETER_CNT = 0x4E, ///< @ref MCU_PedometerControl + MCUREG_PEDOMETER_STEP_DATA = 0x4F, ///< @ref MCU_PedometerStepData + MCUREG_PEDOMETER_WRAP_MINUTE = 0x50, ///< The minute within each RTC hour at which the step history should roll into the next hour. + MCUREG_PEDOMETER_WRAP_SECOND = 0x51, ///< The second within each RTC hour at which the step history should roll into the next hour. + + MCUREG_VOLUME_CALIBRATION_MIN = 0x58, ///< Lower bound of sound volume. + MCUREG_VOLUME_CALIBRATION_MAX = 0x59, ///< Upper bound of sound volume. + + MCUREG_STORAGE_AREA_OFFSET = 0x60, ///< Offset within the storage area to read/write to. + MCUREG_STORAGE_AREA = 0x61, ///< Input/output byte for write/read operations in the storage area. + + MCUREG_INFO = 0x7F, ///< System information register. +}; + +enum MCU_ResetEventFlags +{ + MCU_RESETFLG_RTC_TIME_LOST = BIT(0), ///< RTC time was lost (as is the case when the battery is removed). + MCU_RESETFLG_WATCHDOG_RESET = BIT(1), ///< MCU Watchdog reset occurred. +}; + +enum MCU_PowerStatusFlags +{ + MCU_PWRSTAT_SHELL_OPEN = BIT(1), ///< Set if the shell is open. + MCU_PWRSTAT_ADAPTER_CONNECTED = BIT(3), ///< Set if the AC adapter is connected. + MCU_PWRSTAT_CHARGING = BIT(4), ///< Set if the battery is charging. + MCU_PWRSTAT_BOTTOM_BL_ON = BIT(5), ///< Set if the bottom backlight is on. + MCU_PWRSTAT_TOP_BL_ON = BIT(6), ///< Set if the top backlight is on. + MCU_PWRSTAT_LCD_ON = BIT(7) ///< Set if the LCDs are on. +}; + +enum MCU_PedometerControl +{ + MCU_PEDOMETER_CLEAR = BIT(0), ///< Clear the step history. + MCU_PEDOMETER_STEPS_FULL = BIT(4) ///< Set when the step history is full. +}; + +enum MCU_PowerTrigger +{ + MCU_PWR_SHUTDOWN = BIT(0), ///< Turn off the system. + MCU_PWR_RESET = BIT(1), ///< Reset the MCU. + MCU_PWR_REBOOT = BIT(2), ///< Reboot the system. + MCU_PWR_LGY_SHUTDOWN = BIT(3), ///< Turn off the system. (Used by LgyBg) + MCU_PWR_SLEEP = BIT(4), ///< Signal to enter sleep mode. + OLDMCU_BL_OFF = BIT(4), ///< (Old MCU_FIRM only) turn the backlights off. + OLDMCU_BL_ON = BIT(5), ///< (Old MCU_FIRM only) turn the backlights on. + OLDMCU_LCD_OFF = BIT(6), ///< (Old MCU_FIRM only) turn the LCDs off. + OLDMCU_LCD_ON = BIT(7), ///< (Old MCU_FIRM only) turn the LCDs on. +}; + +typedef enum MCU_PowerLedState +{ + LED_NORMAL = 0, ///< Fade power LED to blue, while checking for battery percentage. + LED_FADE_BLUE = 1, ///< Fade power LED to blue. + LED_SLEEP_MODE = 2, ///< The power LED pulses blue slowly, as it does in sleep mode. + LED_OFF = 3, ///< Power LED fades off. + LED_RED = 4, ///< Power LED instantaneously turns red. + LED_BLUE = 5, ///< Power LED instantaneously turns blue. + LED_BLINK_RED = 6, ///< Power LED and info (notification) LED blink red, as they do when the battery is critically low. +} MCU_PowerLedState; + +typedef struct MCU_InfoLedAnimation +{ + u8 ticksPerFrame; ///< The amount of time (in ticks), for which a given frame is active. Must be nonzero. (See @ref mcuTicksFromMs) + u8 frameTransitionDelay; ///< Amount of time (in ticks) between pattern frames. (See @ref mcuTicksFromMs) Set to 0 to disable interpolation, or equal to ticksPerFrame for linear interpolation. + u8 numLastFrameRepeats; ///< The amount of times for which the last frame should be repeated. Treated as if the pattern contains numLastFrameRepeats more of the last frame than it actually does. Set to 0xFF to repeat forever. + u8 _pad; +} MCU_InfoLedAnimation; + +typedef struct MCU_InfoLedPattern +{ + MCU_InfoLedAnimation animation; ///< Animation. + u8 redPattern[32]; ///< Pattern for red component. + u8 greenPattern[32]; ///< Pattern for green component. + u8 bluePattern[32]; ///< Pattern for blue component. +} MCU_InfoLedPattern; + +typedef enum MCU_WifiMode +{ + WIFI_MODE_CTR = 0, ///< 3DS WiFi mode. + WIFI_MODE_MP = 1, ///< DS[i] WiFi mode ("MP"). +} MCU_WifiMode; + +typedef struct MCU_RtcTime +{ + u8 second; ///< RTC second. + u8 minute; ///< RTC minute. + u8 hour; ///< RTC hour. + u8 weekday; ///< RTC day of the week. + u8 monthday; ///< RTC day of the month. + u8 month; ///< RTC month. + u8 year; ///< RTC year (since 2000). +} MCU_RtcTime; + +typedef struct MCU_RtcAlarmTime +{ + u8 minute; ///< RTC alarm minute. + u8 hour; ///< RTC alarm hour. + u8 day; ///< RTC alarm day. + u8 month; ///< RTC alarm day of the month. + u8 year; ///< RTC alarm year (since 2000). +} CTR_PACKED MCU_RtcAlarmTime; + +typedef enum MCU_SensorConfig +{ + MCU_SENSOR_ACCELEROMETER_ENABLE = BIT(0), ///< If set, the accelerometer is enabled. + MCU_SENSOR_PEDOMETER_ENABLE = BIT(1), ///< If set, the pedometer is enabled. +} MCU_SensorConfig; + +typedef struct MCU_AccelerometerData +{ + s16 x; ///< X coordinate of the current accelerometer sample. + s16 y; ///< Y coordinate of the current accelerometer sample. + s16 z; ///< Z coordinate of the current accelerometer sample. +} MCU_AccelerometerData; + +typedef struct MCU_PedometerStepData +{ + struct MCU_PedometerTime + { + u8 hour; ///< RTC hour at the time of the update. + u8 monthday; ///< RTC day of the month at the time of the update. + u8 month; ///< RTC month at the time of the update. + u8 year; ///< RTC year (since 2000) at the time of the update. + u8 minute; ///< RTC minute at the time of the update. + u8 second; ///< RTC second at the time of the update. + } pedometerTime; ///< RTC timestamp for the time this data was last updated. + u16 stepCounts[7 * 24]; ///< Step counts for every hour in the week, with the last element referring to the current hour. +} CTR_PACKED MCU_PedometerStepData; + +typedef enum MCU_AccelerometerScale +{ + ACC_SCALE_2G = 0x0, ///< -2G to 2G + ACC_SCALE_4G = 0x1, ///< -4G to 4G + ACC_SCALE_8G = 0x3, ///< -8G to 8G +} MCU_AccelerometerScale; + +typedef struct MCU_LgyLcdSettings +{ + u8 enableAblPowersave : 1; ///< Whether or not ABL (adaptive backlight) power save is enabled. + u8 luminanceLevel : 3; ///< The brightness level (1-5). + u8 _unused : 4; +} MCU_LgyLcdSettings; + +static inline u8 mcuTicksFromMs(u32 ms) +{ + // 512Hz + u32 res = 512u * ms / 1000u; + res = res < 2 ? 1 : res - 1; // res not allowed to be zero + res = res > 255 ? 255 : res; // res can't exceed 255 + return (u8)res; +} \ No newline at end of file diff --git a/libctru/include/3ds/services/mcucam.h b/libctru/include/3ds/services/mcucam.h new file mode 100644 index 000000000..95c52a3ba --- /dev/null +++ b/libctru/include/3ds/services/mcucam.h @@ -0,0 +1,32 @@ +/** + * @file mcucam.h + * @brief MCU Camera service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuCam. +Result mcuCamInit(void); + +/// Exits mcuCam. +void mcuCamExit(void); + +/** + * @brief Gets the current mcuCam session handle. + * @return A pointer to the current mcuCam session handle. + */ +Handle *mcuCamGetSessionHandle(void); + +/** + * @brief Sets the camera LED state. + * @param on Whether or not the camera LED should be turned on. + */ +Result MCUCAM_SetCameraLedState(bool on); + +/** + * @brief Returns whether or not the camera LED is on. + * @param out_on Pointer to output whether or not the camera LED is on. + */ +Result MCUCAM_GetCameraLedState(bool *out_on); \ No newline at end of file diff --git a/libctru/include/3ds/services/mcucdc.h b/libctru/include/3ds/services/mcucdc.h new file mode 100644 index 000000000..a6adcc496 --- /dev/null +++ b/libctru/include/3ds/services/mcucdc.h @@ -0,0 +1,25 @@ +/** + * @file mcucdc.h + * @brief MCU CODEC service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuCdc. +Result mcuCdcInit(void); + +/// Exits mcuCdc. +void mcuCdcExit(void); + +/** + * @brief Gets the current mcuCdc session handle. + * @return A pointer to the current mcuCdc session handle. + */ +Handle *mcuCdcGetSessionHandle(void); + +/** + * @brief Writes bit 4 to MCU register 26h. + */ +Result MCUCDC_SetReg26h(); diff --git a/libctru/include/3ds/services/mcugpu.h b/libctru/include/3ds/services/mcugpu.h new file mode 100644 index 000000000..90e3cb6a4 --- /dev/null +++ b/libctru/include/3ds/services/mcugpu.h @@ -0,0 +1,106 @@ +/** + * @file mcugpu.h + * @brief MCU GPU service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuGpu. +Result mcuGpuInit(void); + +/// Exits mcuGpu. +void mcuGpuExit(void); + +/** + * @brief Gets the current mcuGpu session handle. + * @return A pointer to the current mcuGpu session handle. + */ +Handle *mcuGpuGetSessionHandle(void); + +/** + * @brief Returns whether the screen backlights are on. + * @param out_top_on Pointer to output whether or not the top screen backlight is on. + * @param out_bot_on Pointer to output whether or not the bottom screen backlight is on. + */ +Result MCUGPU_GetBacklightPower(bool *out_top_on, bool *out_bot_on); + +/** + * @brief Turns the top/bottom screen backlights on/off. + * @param top_on Whether or not the top screen backlight should be turned on. + * @param bot_on Whether or not the bottom screen backlight should be turned on. + */ +Result MCUGPU_SetBacklightPower(bool top_on, bool bot_on); + +/** + * @brief Returns whether the LCDs are on. + * @param out_on Pointer to output whether or not the LCDs are on. + */ +Result MCUGPU_GetLcdPower(bool *out_on); + +/** + * @brief Turns the LCDs on/off. + * @param on Whether or not the LCDs should be turned on. + */ +Result MCUGPU_SetLcdPower(bool on); + +/** + * @brief Sets the flicker (VCOM) value for the top screen. + * @param flicker The new value to use. Default value: 0x5C + */ +Result MCUGPU_SetTopLcdFlicker(u8 flicker); + +/** + * @brief Gets the flicker (VCOM) value for the top screen. + * @param out_flicker Pointer to output the flicker value to. + */ +Result MCUGPU_GetTopLcdFlicker(u8 *out_flicker); + +/** + * @brief Sets the flicker (VCOM) value for the bottom screen. + * @param flicker The new value to use. Default value: 0x5F + */ +Result MCUGPU_SetBottomLcdFlicker(u8 flicker); + +/** + * @brief Gets the flicker (VCOM) value for the bottom screen. + * @param out_flicker Pointer to output the flicker value to. + */ +Result MCUGPU_GetBottomLcdFlicker(u8 *out_flicker); + +/** + * @brief Gets the major MCU firmware version + * @param out Pointer to write the major firmware version to. + */ +Result MCUGPU_GetFwVerHigh(u8 *out); + +/** + * @brief Gets the minor MCU firmware version + * @param out Pointer to write the minor firmware version to. + */ +Result MCUGPU_GetFwVerLow(u8 *out); + +/** + * @brief Sets the 3D LED state. + * @param state State of 3D LED. (True/False) + */ +Result MCUGPU_Set3dLedState(bool state); + +/** + * @brief Gets the 3D LED state. + * @param out_state Pointer to output whether or not the 3D LED is on. + */ +Result MCUGPU_Get3dLedState(bool *out_state); + +/** + * @brief Gets the event handle for MCUGPU related events. + * @param out_event Pointer to output the event handle to. + */ +Result MCUGPU_GetEventHandle(Handle *out_event); + +/** + * @brief Gets the GPU events that have recently been received by the MCU. + * @param out_events Pointer to output the received events to. + */ +Result MCUGPU_GetReceivedEvents(u32 *out_events); \ No newline at end of file diff --git a/libctru/include/3ds/services/mcuhid.h b/libctru/include/3ds/services/mcuhid.h new file mode 100644 index 000000000..eb27dc27b --- /dev/null +++ b/libctru/include/3ds/services/mcuhid.h @@ -0,0 +1,111 @@ +/** + * @file mcuhid.h + * @brief MCU HID service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuHid. +Result mcuHidInit(void); + +/// Exits mcuHid. +void mcuHidExit(void); + +/** + * @brief Gets the current mcuHid session handle. + * @return A pointer to the current mcuHid session handle. + */ +Handle *mcuHidGetSessionHandle(void); + +/** + * @brief Sets the enabled sensors (pedometer, accelerometer) configuration. + * @param config The configuration to use. + */ +Result MCUHID_SetSensorConfiguration(MCU_SensorConfig config); + +/** + * @brief Returns whether or not the accelerometer is enabled. + * @param out_enabled Pointer to output whether or not the accelerometer is enabled. + */ +Result MCUHID_GetAccelerometerEnabled(bool *out_enabled); + +/** + * @brief Starts a raw accelerometer I2C read operation. + * @param hw_regid The I2C register address to read from. Refer to the datasheet for the LIS331DLH IC for more information about the available registers. + */ +Result MCUHID_StartAccelerometerManualRead(u8 hw_regid); + +/** + * @brief Gets the result of an raw accelerometer I2C read operation. + * @param out_data Pointer to output the read data byte to. + */ +Result MCUHID_GetAccelerometerManualReadResult(u8 *out_data); + +/** + * @brief Performs a raw accelerometer I2C write operation. + * @param hw_regid The I2C register address to write to. Refer to the datasheet for the LIS331DLH IC for more information about the available registers. + * @param data The data byte to write to the given address. + */ +Result MCUHID_PerformAccelerometerManualWrite(u8 hw_regid, u8 data); + +/** + * @brief Reads the current position data from the accelerometer. + * @param out_data Pointer to output the accelerometer data to. + */ +Result MCUHID_ReadAccelerometerData(MCU_AccelerometerData *out_data); + +/** + * @brief Reads the current position of the 3D slider. + * @param out_pos Pointer to output the position to. + */ +Result MCUHID_Read3dSliderPosition(u8 *out_pos); + +/** + * @brief Sets the scale of the accelerometer. + * @param scale The new scale to use. + */ +Result MCUHID_SetAccelerometerScale(MCU_AccelerometerScale scale); + +/** + * @brief Gets the currently used scale of the accelerometer. + * @param out_scale Pointer to output the scale to. + */ +Result MCUHID_GetAccelerometerScale(MCU_AccelerometerScale *out_scale); + +/** + * @brief Enables/disables the internal filter of the accelerometer. Refer to the datasheet for the LIS331DLH IC for more information. + * @param enabled Whether or not the filter should be enabled. + */ +Result MCUHID_SetAccelerometerInternalFilterEnabled(bool enabled); + +/** + * @brief Returns whether or not the internal filter of the accelerometer is enabled. Refer to the datasheet for the LIS331DLH IC for more information. + * @param out_enabled Pointer to output the status to. + */ +Result MCUHID_GetAccelerometerInternalFilterEnabled(bool *out_enabled); + +/** + * @brief Gets the event handle for MCUHID related events. + * @param out_event Pointer to output the event handle to. + */ +Result MCUHID_GetEventHandle(Handle *out_handle); + +/** + * @brief Gets the HID events that have recently been received by the MCU. + * @param out_events Pointer to output the received events to. + */ +Result MCUHID_GetReceivedEvents(u32 *out_events); + +/** + * @brief Gets the volume slider level. + * @param level Pointer to write the slider level to. + */ +Result MCUHID_GetVolumeSliderLevel(u8 *level); + +/** + * @brief Enables/disables the IRQ that fires whenever the accelerometer publishes a new sample. + * @param enable Whether or not to enable the IRQ. + */ +Result MCUHID_SetAccelerometerIrqEnabled(bool enable); \ No newline at end of file diff --git a/libctru/include/3ds/services/mcuhwc.h b/libctru/include/3ds/services/mcuhwc.h index 027cdc5fb..27864f769 100644 --- a/libctru/include/3ds/services/mcuhwc.h +++ b/libctru/include/3ds/services/mcuhwc.h @@ -1,28 +1,11 @@ /** * @file mcuhwc.h - * @brief mcuHwc service. + * @brief MCU Hardware Control service. */ #pragma once -typedef enum { - LED_NORMAL = 1, ///< The normal mode of the led - LED_SLEEP_MODE, ///< The led pulses slowly as it does in the sleep mode - LED_OFF, ///< Switch off power led - LED_RED, ///< Red state of the led - LED_BLUE, ///< Blue state of the led - LED_BLINK_RED, ///< Blinking red state of power led and notification led -} powerLedState; - -typedef struct InfoLedPattern -{ - u8 delay; ///< Delay between pattern values, 1/16th of a second (1 second = 0x10) - u8 smoothing; ///< Smoothing between pattern values (higher = smoother) - u8 loopDelay; ///< Delay between pattern loops, 1/16th of a second (1 second = 0x10, 0xFF = pattern is played only once) - u8 blinkSpeed; ///< Blink speed, when smoothing == 0x00 - u8 redPattern[32]; ///< Pattern for red component - u8 greenPattern[32]; ///< Pattern for green component - u8 bluePattern[32]; ///< Pattern for blue component -} InfoLedPattern; +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> /// Initializes mcuHwc. Result mcuHwcInit(void); @@ -34,7 +17,7 @@ void mcuHwcExit(void); * @brief Gets the current mcuHwc session handle. * @return A pointer to the current mcuHwc session handle. */ -Handle* mcuHwcGetSessionHandle(void); +Handle *mcuHwcGetSessionHandle(void); /** * @brief Reads data from an i2c device3 register @@ -53,55 +36,92 @@ Result MCUHWC_ReadRegister(u8 reg, void *data, u32 size); Result MCUHWC_WriteRegister(u8 reg, const void *data, u32 size); /** - * @brief Gets the battery voltage + * @brief Reads the info registers of the MCU. + * @param data Pointer to write the info to. + * @param size Size of the info. To read info data at a given offset, at least (offset + wanted data size) bytes must be read. + */ +Result MCUHWC_ReadInfoRegister(void *data, u8 size); + +/** + * @brief Gets the battery voltage in 20 mV increments. * @param voltage Pointer to write the battery voltage to. */ Result MCUHWC_GetBatteryVoltage(u8 *voltage); /** - * @brief Gets the battery level + * @brief Gets the battery level as a percentage. * @param level Pointer to write the current battery level to. */ Result MCUHWC_GetBatteryLevel(u8 *level); /** - * @brief Gets the sound slider level - * @param level Pointer to write the slider level to. + * @brief Sets the Power LED state. + * @param state powerLedState State of power LED. */ -Result MCUHWC_GetSoundSliderLevel(u8 *level); +Result MCUHWC_SetPowerLedState(MCU_PowerLedState state); /** - * @brief Sets Wifi LED state + * @brief Sets the WiFi LED state. * @param state State of Wifi LED. (True/False) */ Result MCUHWC_SetWifiLedState(bool state); /** - * @brief Sets the notification LED pattern - * @param pattern Pattern for the notification LED. + * @brief Sets the Camera LED state. + * @param state State of Camera LED. (True/False) */ -Result MCUHWC_SetInfoLedPattern(const InfoLedPattern* pattern); +Result MCUHWC_SetCameraLedState(bool state); /** - * @brief Sets Power LED state - * @param state powerLedState State of power LED. + * @brief Sets the 3D LED state. + * @param state State of 3D LED. (True/False) + */ +Result MCUHWC_Set3dLedState(bool state); + +/** + * @brief Sets the info (notification) LED pattern. + * @param pattern Pattern for the info LED. + */ +Result MCUHWC_SetInfoLedPattern(const MCU_InfoLedPattern *pattern); + +/** + * @brief Gets the volume slider level. + * @param level Pointer to write the slider level to. + */ +Result MCUHWC_GetVolumeSliderLevel(u8 *level); + +/** + * @brief Sets the flicker (VCOM) value for the top screen. + * @param flicker The new value to use. Default value: 0x5C + */ +Result MCUHWC_SetTopLcdFlicker(u8 flicker); + +/** + * @brief Sets the flicker (VCOM) value for the bottom screen. + * @param flicker The new value to use. Default value: 0x5F + */ +Result MCUHWC_SetBottomLcdFlicker(u8 flicker); + +/** + * @brief Gets the battery temperature using a sensor on the console's PCB. + * @param out_value Pointer to output the temperature (in degrees Celsius) to. */ -Result MCUHWC_SetPowerLedState(powerLedState state); +Result MCUHWC_GetBatteryPcbTemperature(s8 *out_value); /** - * @brief Gets 3d slider level - * @param level Pointer to write 3D slider level to. + * @brief Reads the current RTC time. + * @param out_time Pointer to output the RTC time to. */ -Result MCUHWC_Get3dSliderLevel(u8 *level); +Result MCUHWC_GetRtcTime(MCU_RtcTime *out_time); /** - * @brief Gets the major MCU firmware version + * @brief Gets the major MCU firmware version. * @param out Pointer to write the major firmware version to. */ Result MCUHWC_GetFwVerHigh(u8 *out); /** - * @brief Gets the minor MCU firmware version + * @brief Gets the minor MCU firmware version. * @param out Pointer to write the minor firmware version to. */ Result MCUHWC_GetFwVerLow(u8 *out); diff --git a/libctru/include/3ds/services/mcunwm.h b/libctru/include/3ds/services/mcunwm.h new file mode 100644 index 000000000..76024dcbf --- /dev/null +++ b/libctru/include/3ds/services/mcunwm.h @@ -0,0 +1,68 @@ +/** + * @file mcunwm.h + * @brief MCU NWM service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuNwm. +Result mcuNwmInit(void); + +/// Exits mcuNwm. +void mcuNwmExit(void); + +/** + * @brief Gets the current mcuNwm session handle. + * @return A pointer to the current mcuNwm session handle. + */ +Handle *mcuNwmGetSessionHandle(void); + +/** + * @brief Sets the WiFi LED state. + * @param state State of Wifi LED. + */ +Result MCUNWM_SetWifiLedState(bool state); + +/** + * @brief Gets the WiFi LED state. + * @param state State of Wifi LED. + */ +Result MCUNWM_GetWifiLedState(bool *out_state); + +/** + * @brief Configures the WiFi module to be in either 3DS mode (CTR mode) or DS[i] mode (MP mode). + * @param mode The mode to set. + */ +Result MCUNWM_SetWifiMode(MCU_WifiMode mode); + +/** + * @brief Returns the current mode the WiFi module is in. + * @param outIsMpMode Pointer to output the mode to. + */ +Result MCUNWM_GetWifiMode(MCU_WifiMode *out_mode); + +/** + * @brief Enables or disables WiFi. + * @param enabled Whether or not the enable WiFi. + */ +Result MCUNWM_SetWifiEnabled(bool enabled); + +/** + * @brief Returns whether or not WiFi is currently enabled. + * @param out_enabled Pointer to output the status to. + */ +Result MCUNWM_GetWifiEnabled(bool *out_enabled); + +/** + * @brief Sets the MCU flag that indicates whether or not WiFi was disabled previously (for persistence across reboots/FIRMs). + * @param value The value to set. + */ +Result MCUNWM_SetWirelessDisabledFlag(bool value); + +/** + * @brief Gets the MCU flag that indicates whether or not WiFi was disabled previously (for persistence across reboots/FIRMs). + * @param out_value Pointer to output the value to. + */ +Result MCUNWM_GetWirelessDisabledFlag(bool *out_value); diff --git a/libctru/include/3ds/services/mcupls.h b/libctru/include/3ds/services/mcupls.h new file mode 100644 index 000000000..2e6e16e87 --- /dev/null +++ b/libctru/include/3ds/services/mcupls.h @@ -0,0 +1,74 @@ +/** + * @file mcupls.h + * @brief MCU PLS (Platform Services) service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuPls. +Result mcuPlsInit(void); + +/// Exits mcuPls. +void mcuPlsExit(void); + +/** + * @brief Gets the current mcuPls session handle. + * @return A pointer to the current mcuPls session handle. + */ +Handle *mcuPlsGetSessionHandle(void); + +/** + * @brief Gets the RTC time. + * @param out_time Pointer to output the RTC time to. + */ +Result MCUPLS_GetRtcTime(MCU_RtcTime *out_time); + +/** + * @brief Gets the seconds part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeSeconds(u8 *out_value); + +/** + * @brief Gets the minute part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeMinute(u8 *out_value); + +/** + * @brief Gets the hour part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeHour(u8 *out_value); + +/** + * @brief Gets the weekday part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeWeekday(u8 *out_value); + +/** + * @brief Gets the day part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeDay(u8 *out_value); + +/** + * @brief Gets the month part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeMonth(u8 *out_value); + +/** + * @brief Gets the year since 2000 part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetRtcTimeYear(u8 *out_value); + +/** + * @brief Gets MCU's system tick. + * @param out_value Pointer to output the value to. + */ +Result MCUPLS_GetTickCounter(u16 *out_value); diff --git a/libctru/include/3ds/services/mcurtc.h b/libctru/include/3ds/services/mcurtc.h new file mode 100644 index 000000000..a1d5a3ad9 --- /dev/null +++ b/libctru/include/3ds/services/mcurtc.h @@ -0,0 +1,568 @@ +/** + * @file mcurtc.h + * @brief MCU RTC service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuRtc. +Result mcuRtcInit(void); + +/// Exits mcuRtc. +void mcuRtcExit(void); + +/** + * @brief Gets the current mcuRtc session handle. + * @return A pointer to the current mcuRtc session handle. + */ +Handle *mcuRtcGetSessionHandle(void); + +/** + * @brief Sets the RTC time. + * @param time The RTC time to set. + */ +Result MCURTC_SetRtcTime(const MCU_RtcTime *time); + +/** + * @brief Gets the RTC time. + * @param out_time Pointer to output the RTC time to. + */ +Result MCURTC_GetRtcTime(MCU_RtcTime *out_time); + +/** + * @brief Sets the seconds part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeSeconds(u8 value); + +/** + * @brief Gets the seconds part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeSeconds(u8 *out_value); + +/** + * @brief Sets the minute part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeMinute(u8 value); + +/** + * @brief Gets the minute part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeMinute(u8 *out_value); + +/** + * @brief Sets the hour part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeHour(u8 value); + +/** + * @brief Gets the hour part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeHour(u8 *out_value); + +/** + * @brief Sets the weekday part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeWeekday(u8 value); + +/** + * @brief Gets the weekday part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeWeekday(u8 *out_value); + +/** + * @brief Sets the day part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeDay(u8 value); + +/** + * @brief Gets the day part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeDay(u8 *out_value); + +/** + * @brief Sets the month part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeMonth(u8 value); + +/** + * @brief Gets the month part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeMonth(u8 *out_value); + +/** + * @brief Sets the year since 2000 part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeYear(u8 value); + +/** + * @brief Gets the year since 2000 part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeYear(u8 *out_value); + +/** + * @brief Sets the correction part of the RTC time. + * @param value The value to set. + */ +Result MCURTC_SetRtcTimeCorrection(u8 value); + +/** + * @brief Gets the correction part of the RTC time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcTimeCorrection(u8 *out_value); + +/** + * @brief Sets the RTC alarm time. + * @param time The RTC alarm time to set. + */ +Result MCURTC_SetRtcAlarmTime(const MCU_RtcAlarmTime *time); + +/** + * @brief Gets the RTC alarm time. + * @param out_time Pointer to output the RTC alarm time to. + */ +Result MCURTC_GetRtcAlarmTime(MCU_RtcAlarmTime *out_time); + +/** + * @brief Sets the minute part of the RTC alarm time. + * @param value The value to set. + */ +Result MCURTC_SetRtcAlarmTimeMinute(u8 value); + +/** + * @brief Gets the minute part of the RTC alarm time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcAlarmTimeMinute(u8 *out_value); + +/** + * @brief Sets the hour part of the RTC alarm time. + * @param value The value to set. + */ +Result MCURTC_SetRtcAlarmTimeHour(u8 value); + +/** + * @brief Gets the hour part of the RTC alarm time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcAlarmTimeHour(u8 *out_value); + +/** + * @brief Sets the day part of the RTC alarm time. + * @param value The value to set. + */ +Result MCURTC_SetRtcAlarmTimeDay(u8 value); + +/** + * @brief Gets the day part of the RTC alarm time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcAlarmTimeDay(u8 *out_value); + +/** + * @brief Sets the month part of the RTC alarm time. + * @param value The value to set. + */ +Result MCURTC_SetRtcAlarmTimeMonth(u8 value); + +/** + * @brief Gets the month part of the RTC alarm time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcAlarmTimeMonth(u8 *out_value); + +/** + * @brief Sets the year since 2000 part of the RTC alarm time. + * @param value The value to set. + */ +Result MCURTC_SetRtcAlarmTimeYear(u8 value); + +/** + * @brief Gets the year since 2000 part of the RTC alarm time. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetRtcAlarmTimeYear(u8 *out_value); + +/** + * @brief Enables/disables the pedometer. + * @param enabled Whether or not the pedometer should be enabled. + */ +Result MCURTC_SetPedometerEnabled(bool enabled); + +/** + * @brief Returns whether or not the pedometer is enabled. + * @param out_enabled Pointer to output the status to. + */ +Result MCURTC_GetPedometerEnabled(bool *out_enabled); + +/** + * @brief Returns the total number of steps measured by the pedometer. + * @param out_num_steps Pointer to output the number of steps to. + */ +Result MCURTC_ReadPedometerStepCount(u32 *out_num_steps); + +/** + * @brief Reads step data recorded by the pedometer. + * @param out_data Pointer to output the step data to. + */ +Result MCURTC_ReadPedometerStepData(MCU_PedometerStepData *out_data); + +/** + * @brief Clears the current step data of the pedometer. + */ +Result MCURTC_ClearStepData(); + +/** + * @brief Gets the event handle for power related events. + * @param out_event Pointer to output the event handle to. + */ +Result MCURTC_GetEventHandle(Handle *out_handle); + +/** + * @brief Gets the power events that have recently been received by the MCU. + * @param out_events Pointer to output the received events to. + */ +Result MCURTC_GetReceivedEvents(u32 *out_events); + +/** + * @brief Checks whether or not RTC time was lost. (This can happen due to the battery being removed, for example) + * @param out_lost Pointer to output the status to. + */ +Result MCURTC_CheckRtcTimeLost(bool *out_lost); + +/** + * @brief Clears the "RTC time lost" flag. + */ +Result MCURTC_ClearRtcTimeLost(); + +/** + * @brief Checks whether an MCU watchdog reset occurred. + * @param out_occurred Pointer to output the status to. + */ +Result MCURTC_CheckWatchdogResetOccurred(bool *out_occurred); + +/** + * @brief Clears the "watchdog reset occurred" flag. + */ +Result MCURTC_ClearWatchdogResetOccurred(); + +/** + * @brief Returns the shell open/closed (or sleep switch on/off on the original, non-XL 2DS) state. + * @param out_open Pointer to output the state to. + */ +Result MCURTC_GetShellState(bool *out_open); + +/** + * @brief Returns whether or not the AC adapter is connected. + * @param out_open Pointer to output the state to. + */ +Result MCURTC_GetAdapterState(bool *out_connected); + +/** + * @brief Returns whether or not the system is charging. + * @param out_open Pointer to output the state to. + */ +Result MCURTC_GetChargingState(bool *out_connected); + +/** + * @brief Gets the battery level as a percentage. + * @param out_level Pointer to output the value to. + */ +Result MCURTC_GetBatteryLevel(u8 *out_level); + +/** + * @brief Sets the power LED state. + * @param state The state to set. + */ +Result MCURTC_SetPowerLedState(MCU_PowerLedState state); + +/** + * @brief Gets the power LED state. + * @param out_state Pointer to output the state to. + */ +Result MCURTC_GetPowerLedState(MCU_PowerLedState *out_state); + +/** + * @brief Sets the brightness of the system LEDs (WiFi/Power/3D/etc). + * @param value The brightness to set (0-255). + */ +Result MCURTC_SetLedBrightness(u8 value); + +/** + * @brief Gets the brightness of the system LEDs (WiFi/Power/3D/etc). + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetLedBrightness(u8 *out_value); + +/** + * @brief Performs a hardware shutdown. + */ +Result MCURTC_Poweroff(); + +/** + * @brief Performs a hardware reboot. + */ +Result MCURTC_Reboot(); + +/** + * @brief Performs a hardware reset. + */ +Result MCURTC_Reset(); + +/** + * @brief Signals to the MCU that the system is about to enter sleep mode. + */ +Result MCURTC_SignalEnterSleepMode(); + +/** + * @brief Sets the delay time for force shutdowns performed by holding the power button. + * @param value The time in 8Hz units. Time in milliseconds = value * 125. Default value: 0x5D (11.625s) + */ +Result MCURTC_SetForceShutdownDelay(u8 value); + +/** + * @brief Gets the delay time for force shutdowns performed by holding the power button. + * @param out_value Pointer to output the value to. The value in 8Hz units. Time in milliseconds = value * 125. + */ +Result MCURTC_GetForceShutdownDelay(u8 *out_value); + +/** + * @brief Reads the info registers of the MCU. + * @param data Pointer to write the info to. + * @param size Size of the info. To read info data at a given offset, at least (offset + wanted data size) bytes must be read. + */ +Result MCURTC_ReadInfoRegister(void *data, u8 size); + +/** + * @brief Writes to the battery-backed RAM storage area of the MCU. + * @param offset Offset to write to. Writing beyond 0xC0 is not allowed. + * @param size Amount of bytes to write, starting at the given offset. + */ +Result MCURTC_WriteStorageArea(u8 offset, void *buf, u8 size); + +/** + * @brief Reads from the battery-backed RAM storage area of the MCU. + * @param offset Offset to read from. Reading beyond 0xC0 is not allowed. + * @param size Amount of bytes to read, starting at the given offset. + */ +Result MCURTC_ReadStorageArea(u8 offset, void *buf, u8 size); + +/** + * @brief Sets the info (notification) LED pattern. + * @param pattern Pattern for the info LED. + */ +Result MCURTC_SetInfoLedPattern(const MCU_InfoLedPattern *pattern); + +/** + * @brief Sets the info (notification) LED animation, without changing the pattern. + * @param animation The new animation to use. + */ +Result MCURTC_SetInfoLedAnimation(const MCU_InfoLedAnimation *animation); + +/** + * @brief Checks whether or not a new info (notification) LED pattern cycle has been started. + * @param out_new_cycle_started Pointer to output the status to. + */ +Result MCURTC_GetInfoLedCycleStatus(bool *out_new_cycle_started); + +/** + * @brief Sets the minute within every hour of RTC time when a new hour worth of step data should be published. + * @param value The value to set. + */ +Result MCURTC_SetPedometerWrapTimeMinute(u8 value); + +/** + * @brief Gets the minute within every hour of RTC time when a new hour worth of step data should be published. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetPedometerWrapTimeMinute(u8 *out_value); + +/** + * @brief Sets the second within every hour of RTC time when a new hour worth of step data should be published. + * @param value The value to set. + */ +Result MCURTC_SetPedometerWrapTimeSecond(u8 value); + +/** + * @brief Gets the second within every hour of RTC time when a new hour worth of step data should be published. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetPedometerWrapTimeSecond(u8 *out_value); + +/** + * @brief Sets the blink pattern for when the battery is critically low. + * @param pattern The new pattern to use. Default: 0x55555555. The pattern consists of 32 steps corresponding to the 32 bits of the pattern. + */ +Result MCURTC_SetPowerLedBlinkPattern(u32 pattern); + +/** + * @brief Sets the flicker (VCOM) value for the top screen. + * @param flicker The new value to use. Default value: 0x5C + */ +Result MCURTC_SetTopLcdFlicker(u8 flicker); + +/** + * @brief Gets the flicker (VCOM) value for the top screen. + * @param out_flicker Pointer to output the flicker value to. + */ +Result MCURTC_GetTopLcdFlicker(u8 *out_flicker); + +/** + * @brief Sets the flicker (VCOM) value for the bottom screen. + * @param flicker The new value to use. Default value: 0x5F + */ +Result MCURTC_SetBottomLcdFlicker(u8 flicker); + +/** + * @brief Gets the flicker (VCOM) value for the bottom screen. + * @param out_flicker Pointer to output the flicker value to. + */ +Result MCURTC_GetBottomLcdFlicker(u8 *out_flicker); + +/** + * @brief Sets the minimum and maximum levels for the volume slider. + * @param min The minimum level. Default: 0x24 (+8 in PTM). + * @param max The maximum level. Default: 0xDB (-8 in PTM). + */ +Result MCURTC_SetVolumeSliderBounds(u8 min, u8 max); + +/** + * @brief Gets the minimum and maximum levels for the volume slider. + * @param out_min Pointer to output the minimum level to. + * @param out_max Pointer to output the maximum level to. + */ +Result MCURTC_GetVolumeSliderBounds(u8 *out_min, u8 *out_max); + +/** + * @brief Sets the MCU interrupt mask. + * @Param mask Bitmask for enabled interrupts. + */ +Result MCURTC_SetInterruptMask(u32 mask); + +/** + * @brief Gets the MCU interrupt mask. + * @Param out_mask Pointer to output the interrupt mask to. + */ +Result MCURTC_GetInterruptMask(u32 *out_mask); + +/** + * @brief Exits exclusive interrupt mode and transfers control of IRQs to the MCU system module. + */ +Result MCURTC_LeaveExclusiveInterruptMode(); + +/** + * @brief Enters exclusive interrupt mode, taking control of IRQs from the MCU system module. + */ +Result MCURTC_EnterExclusiveInterruptMode(); + +/** + * @brief Reads received interrupts and acknowledges them. + * @param out_interrupts Pointer to output the received interrupts to. + */ +Result MCURTC_ReadInterrupts(u32 *out_interrupts); + +/** + * @brief Forcefully triggers the MCU interrupt handler to handle the given set of IRQs, even if none of them happened. + * @param interrupts Bitmask of the interrupts to force-trigger. + */ +Result MCURTC_TriggerInterrupts(u32 interrupts); + +/** + * @brief Sets the MCU flag indicating whether or not the MCU firmware was updated. + * @param value The value to set. + */ +Result MCURTC_SetMcuFirmUpdatedFlag(bool value); + +/** + * @brief Gets the MCU flag indicating whether or not the MCU firmware was updated. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetMcuFirmUpdatedFlag(bool *out_value); + +/** + * @brief Sets the MCU flag indicating whether or not either a legacy title or System Settings was closed, as a result of pressing the power button to trigger a reboot. + * @param value The value to set. + */ +Result MCURTC_SetSoftwareClosedFlag(bool value); + +/** + * @brief Gets the MCU flag indicating whether or not either a legacy title or System Settings was closed, as a result of pressing the power button to trigger a reboot. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetSoftwareClosedFlag(bool *out_value); + +/** + * @brief Sets LCD settings for legacy titles. + * @param settings The settings data to set. + */ +Result MCURTC_SetLgyLcdSettings(MCU_LgyLcdSettings settings); + +/** + * @brief Gets the LCD settings for legacy titles. + * @param out_config Pointer to output the settings data to. + */ +Result MCURTC_GetLgyLcdConfig(MCU_LgyLcdSettings *out_settings); + +/** + * @brief Sets the MCU flag that indicates whether or the legacy title should play in native resolution. + * @param value The value to set. + */ +Result MCURTC_SetLgyNativeResolutionFlag(bool value); + +/** + * @brief Gets the MCU flag that indicates whether or the legacy title should play in native resolution. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetLgyNativeResolutionFlag(bool *out_value); + +/** + * @brief Sets the local friend code counter. + * @param value The value to set. + */ +Result MCURTC_SetLocalFriendCodeCounter(u16 value); + +/** + * @brief Gets the local friend code counter. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetLocalFriendCodeCounter(u16 *out_value); + +/** + * @brief Sets the LegacyJumpProhibited MCU flag. + * @param value The value to set. + */ +Result MCURTC_SetLegacyJumpProhibitedFlag(bool value); + +/** + * @brief Gets the LegacyJumpProhibited MCU flag. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetLegacyJumpProhibitedFlag(bool *out_value); + +/** + * @brief Sets the UUID clock sequence. + * @param value The value to set. + */ +Result MCURTC_SetUuidClockSequence(u16 value); + +/** + * @brief Gets the UUID clock sequence. + * @param out_value Pointer to output the value to. + */ +Result MCURTC_GetUuidClockSequence(u16 *out_value); diff --git a/libctru/include/3ds/services/mcusnd.h b/libctru/include/3ds/services/mcusnd.h new file mode 100644 index 000000000..15ce68c35 --- /dev/null +++ b/libctru/include/3ds/services/mcusnd.h @@ -0,0 +1,38 @@ +/** + * @file mcusnd.h + * @brief MCU Sound service. + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/mcu_common.h> + +/// Initializes mcuSnd. +Result mcuSndInit(void); + +/// Exits mcuSnd. +void mcuSndExit(void); + +/** + * @brief Gets the current mcuSnd session handle. + * @return A pointer to the current mcuSnd session handle. + */ +Handle *mcuSndGetSessionHandle(void); + +/** + * @brief Gets the volume slider level. + * @param level Pointer to write the slider level to. + */ +Result MCUSND_GetVolumeSliderLevel(u8 *level); + +/** + * @brief Writes to MCU register 25h. The value is clamped to 6 bits (max value 63). + * @param value The value to write. + */ +Result MCUSND_WriteReg25h(u8 value); + +/** + * @brief Reads from MCU register 25h. + * @param out_value Pointer to output the value to. + */ +Result MCUSND_ReadReg25h(u8 *out_value); diff --git a/libctru/source/services/mcucam.c b/libctru/source/services/mcucam.c new file mode 100644 index 000000000..c763d63cc --- /dev/null +++ b/libctru/source/services/mcucam.c @@ -0,0 +1,53 @@ +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle mcuCamHandle; +static int mcuCamRefCount; + +Result mcuCamInit(void) +{ + if (AtomicPostIncrement(&mcuCamRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuCamHandle, "mcu::CAM"); + if (R_FAILED(res)) AtomicDecrement(&mcuCamRefCount); + return res; +} + +void mcuCamExit(void) +{ + if (AtomicDecrement(&mcuCamRefCount)) return; + svcCloseHandle(mcuCamHandle); +} + +Handle *mcuCamGetSessionHandle(void) +{ + return &mcuCamHandle; +} + +Result MCUCAM_SetCameraLedState(bool on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 1, 0); // 0x00010040 + cmdbuf[1] = !!on; + + Result res = svcSendSyncRequest(mcuCamHandle); + if (R_FAILED(res)) return res; + + return (Result)cmdbuf[1]; +} + +Result MCUCAM_GetCameraLedState(bool *out_on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 0, 0); // 0x00020000 + + Result res = svcSendSyncRequest(mcuCamHandle); + if (R_FAILED(res)) return res; + + *out_on = !!cmdbuf[2]; + return (Result)cmdbuf[1]; +} \ No newline at end of file diff --git a/libctru/source/services/mcucdc.c b/libctru/source/services/mcucdc.c new file mode 100644 index 000000000..efd997ad5 --- /dev/null +++ b/libctru/source/services/mcucdc.c @@ -0,0 +1,39 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle mcuCdcHandle; +static int mcuCdcRefCount; + +Result mcuCdcInit(void) +{ + if (AtomicPostIncrement(&mcuCdcRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuCdcHandle, "mcu::CDC"); + if (R_FAILED(res)) AtomicDecrement(&mcuCdcRefCount); + return res; +} + +void mcuCdcExit(void) +{ + if (AtomicDecrement(&mcuCdcRefCount)) return; + svcCloseHandle(mcuCdcHandle); +} + +Handle *mcuCdcGetSessionHandle(void) +{ + return &mcuCdcHandle; +} + +Result MCUCDC_SetReg26h() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 0, 0); // 0x00010000 + + Result res = svcSendSyncRequest(mcuCdcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/mcugpu.c b/libctru/source/services/mcugpu.c new file mode 100644 index 000000000..81740a210 --- /dev/null +++ b/libctru/source/services/mcugpu.c @@ -0,0 +1,216 @@ +#include <3ds/synchronization.h> +#include <3ds/services/mcugpu.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle mcuGpuHandle; +static int mcuGpuRefCount; + +Result mcuGpuInit(void) +{ + if (AtomicPostIncrement(&mcuGpuRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuGpuHandle, "mcu::GPU"); + if (R_FAILED(res)) AtomicDecrement(&mcuGpuRefCount); + return res; +} + +void mcuGpuExit(void) +{ + if (AtomicDecrement(&mcuGpuRefCount)) return; + svcCloseHandle(mcuGpuHandle); +} + +Handle *mcuGpuGetSessionHandle(void) +{ + return &mcuGpuHandle; +} + +Result MCUGPU_GetBacklightPower(bool *out_top_on, bool *out_bot_on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 0, 0); // 0x00010000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + + if (R_FAILED(res)) return res; + + *out_top_on = !!cmdbuf[2]; + *out_bot_on = !!cmdbuf[3]; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_SetBacklightPower(bool top_on, bool bot_on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 2, 0); // 0x00020080 + cmdbuf[1] = !!top_on; + cmdbuf[2] = !!bot_on; + + Result res = svcSendSyncRequest(mcuGpuHandle); + + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetLcdPower(bool *out_on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 0, 0); // 0x00030000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + + if (R_FAILED(res)) return res; + + *out_on = !!cmdbuf[2]; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_SetLcdPower(bool on) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0004, 1, 0); // 0x00040040 + cmdbuf[1] = !!on; + + Result res = svcSendSyncRequest(mcuGpuHandle); + + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_SetTopLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0005, 1, 0); // 0x00050040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetTopLcdFlicker(u8 *out_flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0006, 0, 0); // 0x00060000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out_flicker = cmdbuf[2] & 0xFF; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_SetBottomLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0007, 1, 0); // 0x00070040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetBottomLcdFlicker(u8 *out_flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 0, 0); // 0x00080000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out_flicker = cmdbuf[2] & 0xFF; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetFwVerHigh(u8 *out) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0009, 0, 0); // 0x00090000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetFwVerLow(u8 *out) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000A, 0, 0); // 0x000A0000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUGPU_Set3dLedState(bool state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000B, 1, 0); // 0x000B0040 + cmdbuf[1] = state; + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + return (Result)cmdbuf[1]; +} + +Result MCUGPU_Get3dLedState(bool *out_state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000C, 0, 0); // 0x000C0000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out_state = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetEventHandle(Handle *out_event) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000D, 0, 0); // 0x000D0000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out_event = cmdbuf[3]; + return (Result)cmdbuf[1]; +} + +Result MCUGPU_GetReceivedEvents(u32 *out_events) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000E, 0, 0); // 0x000E0000 + + Result res = svcSendSyncRequest(mcuGpuHandle); + if (R_FAILED(res)) return res; + + *out_events = cmdbuf[2]; + return (Result)cmdbuf[1]; +} \ No newline at end of file diff --git a/libctru/source/services/mcuhid.c b/libctru/source/services/mcuhid.c new file mode 100644 index 000000000..ed65f9059 --- /dev/null +++ b/libctru/source/services/mcuhid.c @@ -0,0 +1,226 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +#include + +static Handle mcuHidHandle; +static int mcuHidRefCount; + +Result mcuHidInit(void) +{ + if (AtomicPostIncrement(&mcuHidRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuHidHandle, "mcu::HID"); + if (R_FAILED(res)) AtomicDecrement(&mcuHidRefCount); + return res; +} + +void mcuHidExit(void) +{ + if (AtomicDecrement(&mcuHidRefCount)) return; + svcCloseHandle(mcuHidHandle); +} + +Handle *mcuHidGetSessionHandle(void) +{ + return &mcuHidHandle; +} + +Result MCUHID_SetSensorConfiguration(MCU_SensorConfig config) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 1, 0); // 0x00010040 + cmdbuf[1] = config; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetAccelerometerEnabled(bool *out_enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 0, 0); // 0x00020000 + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_enabled = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUHID_StartAccelerometerManualRead(u8 hw_regid) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 1, 0); // 0x00030040 + cmdbuf[1] = (u32)hw_regid; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetAccelerometerManualReadResult(u8 *out_data) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0004, 0, 0); // 0x00040000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_data = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCUHID_PerformAccelerometerManualWrite(u8 hw_regid, u8 data) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0005, 2, 0); // 0x00050080 + cmdbuf[1] = (u32)hw_regid; + cmdbuf[2] = (u32)data; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHID_ReadAccelerometerData(MCU_AccelerometerData *out_data) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0006, 0, 0); // 0x00060000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + memcpy(out_data, &cmdbuf[2], sizeof(MCU_AccelerometerData)); + + return (Result)cmdbuf[1]; +} + +Result MCUHID_Read3dSliderPosition(u8 *out_pos) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0007, 0, 0); // 0x00070000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_pos = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCUHID_SetAccelerometerScale(MCU_AccelerometerScale scale) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 1, 0); // 0x00080040 + cmdbuf[1] = scale; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetAccelerometerScale(MCU_AccelerometerScale *out_scale) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0009, 0, 0); // 0x00090000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_scale = (MCU_AccelerometerScale)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCUHID_SetAccelerometerInternalFilterEnabled(bool enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000A, 1, 0); // 0x000A0040 + cmdbuf[1] = !!enabled; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetAccelerometerInternalFilterEnabled(bool *out_enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000B, 0, 0); // 0x000B0000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_enabled = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetEventHandle(Handle *out_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000C, 0, 0); // 0x000C0000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_handle = cmdbuf[3]; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetReceivedEvents(u32 *out_events) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000D, 0, 0); // 0x000D0000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *out_events = cmdbuf[2]; + return (Result)cmdbuf[1]; +} + +Result MCUHID_GetVolumeSliderLevel(u8 *level) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000E, 0, 0); // 0x000E0000 + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + + *level = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUHID_SetAccelerometerIrqEnabled(bool enable) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000F, 1, 0); // 0x000F0040 + cmdbuf[1] = !!enable; + + Result res = svcSendSyncRequest(mcuHidHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} \ No newline at end of file diff --git a/libctru/source/services/mcuhwc.c b/libctru/source/services/mcuhwc.c index c7de9bc2e..a6e315588 100644 --- a/libctru/source/services/mcuhwc.c +++ b/libctru/source/services/mcuhwc.c @@ -1,11 +1,12 @@ -#include +#include <3ds/synchronization.h> +#include <3ds/services/mcuhwc.h> +#include <3ds/result.h> #include <3ds/types.h> #include <3ds/svc.h> -#include <3ds/synchronization.h> #include <3ds/ipc.h> -#include <3ds/result.h> #include <3ds/srv.h> -#include <3ds/services/mcuhwc.h> + +#include static Handle mcuHwcHandle; static int mcuHwcRefCount; @@ -24,51 +25,63 @@ void mcuHwcExit(void) svcCloseHandle(mcuHwcHandle); } -Handle* mcuHwcGetSessionHandle(void) +Handle *mcuHwcGetSessionHandle(void) { return &mcuHwcHandle; } -Result MCUHWC_ReadRegister(u8 reg, void* data, u32 size) +Result MCUHWC_ReadRegister(u8 reg, void *data, u32 size) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x1,2,2); // 0x10082 + cmdbuf[0] = IPC_MakeHeader(0x0001, 2, 2); // 0x00010082 cmdbuf[1] = reg; cmdbuf[2] = size; cmdbuf[3] = IPC_Desc_Buffer (size, IPC_BUFFER_W); cmdbuf[4] = (u32)data; - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; - + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; return (Result)cmdbuf[1]; } Result MCUHWC_WriteRegister(u8 reg, const void *data, u32 size) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x2,2,2); // 0x20082 + cmdbuf[0] = IPC_MakeHeader(0x0002, 2, 2); // 0x00020082 cmdbuf[1] = reg; cmdbuf[2] = size; cmdbuf[3] = IPC_Desc_Buffer (size, IPC_BUFFER_R); cmdbuf[4] = (u32)data; - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} +Result MCUHWC_ReadInfoRegister(void *data, u8 size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 1, 2); // 0x00030042 + cmdbuf[1] = (u32)size; + cmdbuf[2] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmdbuf[3] = (u32)data; + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; return (Result)cmdbuf[1]; } Result MCUHWC_GetBatteryVoltage(u8 *voltage) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 + cmdbuf[0] = IPC_MakeHeader(0x0004, 0, 0); // 0x00040000 - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; *voltage = cmdbuf[2]; @@ -77,87 +90,152 @@ Result MCUHWC_GetBatteryVoltage(u8 *voltage) Result MCUHWC_GetBatteryLevel(u8 *level) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x5,0,0); // 0x50000 + cmdbuf[0] = IPC_MakeHeader(0x0005, 0, 0); // 0x00050000 - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; *level = cmdbuf[2]; return (Result)cmdbuf[1]; } -Result MCUHWC_SetPowerLedState(powerLedState state) +Result MCUHWC_SetPowerLedState(MCU_PowerLedState state) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x6,2,0); // 0x60040 + cmdbuf[0] = IPC_MakeHeader(0x0006, 1, 0); // 0x00060040 cmdbuf[1] = state; - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; - + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; return (Result)cmdbuf[1]; } Result MCUHWC_SetWifiLedState(bool state) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x7,0,0); // 0x70000 - cmdbuf[1] = state; + cmdbuf[0] = IPC_MakeHeader(0x0007, 1, 0); // 0x00070040 + cmdbuf[1] = !!state; - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} +Result MCUHWC_SetCameraLedState(bool state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 1, 0); // 0x00080040 + cmdbuf[1] = !!state; + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; return (Result)cmdbuf[1]; } -Result MCUHWC_SetInfoLedPattern(const InfoLedPattern* pattern) +Result MCUHWC_Set3dLedState(bool state) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x0A,25,0); // 0xA0640 - cmdbuf[1] = ((u32)pattern->blinkSpeed << 24) | ((u32)pattern->loopDelay << 16) | ((u32)pattern->smoothing << 8) | pattern->delay; - memcpy(&cmdbuf[2], pattern->redPattern, sizeof(pattern->redPattern)); - memcpy(&cmdbuf[10], pattern->greenPattern, sizeof(pattern->greenPattern)); - memcpy(&cmdbuf[18], pattern->bluePattern, sizeof(pattern->bluePattern)); + cmdbuf[0] = IPC_MakeHeader(0x0009, 1, 0); // 0x00090040 + cmdbuf[1] = !!state; - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle))) return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHWC_SetInfoLedPattern(const MCU_InfoLedPattern *pattern) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000A, 25, 0); // 0x000A0640 + memcpy(&cmdbuf[1], pattern, sizeof(MCU_InfoLedPattern)); + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; return (Result)cmdbuf[1]; } -Result MCUHWC_GetSoundSliderLevel(u8 *level) +Result MCUHWC_GetVolumeSliderLevel(u8 *level) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0xB,0,0); // 0xB0000 + cmdbuf[0] = IPC_MakeHeader(0x000B, 0, 0); // 0x000B0000 - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; *level = cmdbuf[2]; return (Result)cmdbuf[1]; } -Result MCUHWC_Get3dSliderLevel(u8 *level) +Result MCUHWC_SetTopLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000C, 1, 0); // 0x000C0040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHWC_SetBottomLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000D, 1, 0); // 0x000D0040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUHWC_GetBatteryPcbTemperature(s8 *out_value) { - return MCUHWC_ReadRegister(8, level, 1); + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000E, 0, 0); // 0x000E0000 + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + + *out_value = (s8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCUHWC_GetRtcTime(MCU_RtcTime *out_time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000F, 0, 0); // 0x000F0000 + + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; + + memcpy(out_time, &cmdbuf[2], sizeof(MCU_RtcTime)); + + return (Result)cmdbuf[1]; } Result MCUHWC_GetFwVerHigh(u8 *out) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x10,0,0); // 0x100000 + cmdbuf[0] = IPC_MakeHeader(0x0010, 0, 0); // 0x00100000 - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; *out = cmdbuf[2]; @@ -166,12 +244,12 @@ Result MCUHWC_GetFwVerHigh(u8 *out) Result MCUHWC_GetFwVerLow(u8 *out) { - Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x11,0,0); // 0x110000 + cmdbuf[0] = IPC_MakeHeader(0x0011, 0, 0); // 0x00110000 - if(R_FAILED(ret = svcSendSyncRequest(mcuHwcHandle)))return ret; + Result res = svcSendSyncRequest(mcuHwcHandle); + if (R_FAILED(res)) return res; *out = cmdbuf[2]; diff --git a/libctru/source/services/mcunwm.c b/libctru/source/services/mcunwm.c new file mode 100644 index 000000000..6f8101082 --- /dev/null +++ b/libctru/source/services/mcunwm.c @@ -0,0 +1,132 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle mcuNwmHandle; +static int mcuNwmRefCount; + +Result mcuNwmInit(void) +{ + if (AtomicPostIncrement(&mcuNwmRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuNwmHandle, "mcu::NWM"); + if (R_FAILED(res)) AtomicDecrement(&mcuNwmRefCount); + return res; +} + +void mcuNwmExit(void) +{ + if (AtomicDecrement(&mcuNwmRefCount)) return; + svcCloseHandle(mcuNwmHandle); +} + +Handle *mcuNwmGetSessionHandle(void) +{ + return &mcuNwmHandle; +} + +Result MCUNWM_SetWifiLedState(bool state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 1, 0); // 0x00010040 + cmdbuf[1] = !!state; + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUNWM_GetWifiLedState(bool *out_state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 0, 0); // 0x00020000 + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + + *out_state = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUNWM_SetWifiMode(MCU_WifiMode mode) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 1, 0); // 0x00030040 + cmdbuf[1] = mode; + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUNWM_GetWifiMode(MCU_WifiMode *out_mode) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0004, 0, 0); // 0x00040000 + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + + *out_mode = (MCU_WifiMode)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCUNWM_SetWifiEnabled(bool enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0005, 1, 0); // 0x00050040 + cmdbuf[1] = !!enabled; + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUNWM_GetWifiEnabled(bool *out_enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0006, 0, 0); // 0x00060000 + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + + *out_enabled = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUNWM_SetWirelessDisabledFlag(bool value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0007, 1, 0); // 0x00070040 + cmdbuf[1] = !!value; + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUNWM_GetWirelessDisabledFlag(bool *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 0, 0); // 0x00080000 + + Result res = svcSendSyncRequest(mcuNwmHandle); + if (R_FAILED(res)) return res; + + *out_value = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} \ No newline at end of file diff --git a/libctru/source/services/mcupls.c b/libctru/source/services/mcupls.c new file mode 100644 index 000000000..1a89764fc --- /dev/null +++ b/libctru/source/services/mcupls.c @@ -0,0 +1,156 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +#include + +static Handle mcuPlsHandle; +static int mcuPlsRefCount; + +Result mcuPlsInit(void) +{ + if (AtomicPostIncrement(&mcuPlsRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuPlsHandle, "mcu::PLS"); + if (R_FAILED(res)) AtomicDecrement(&mcuPlsRefCount); + return res; +} + +void mcuPlsExit(void) +{ + if (AtomicDecrement(&mcuPlsRefCount)) return; + svcCloseHandle(mcuPlsHandle); +} + +Handle *mcuPlsGetSessionHandle(void) +{ + return &mcuPlsHandle; +} + +Result MCURTC_GetRtcTime(MCU_RtcTime *out_time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 0, 0); // 0x00010000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + memcpy(out_time, &cmdbuf[2], sizeof(MCU_RtcTime)); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeSeconds(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 0, 0); // 0x00020000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeMinute(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 0, 0); // 0x00030000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeHour(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0004, 0, 0); // 0x00040000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeWeekday(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0005, 0, 0); // 0x00050000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeDay(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0006, 0, 0); // 0x00060000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeMonth(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0007, 0, 0); // 0x00070000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeYear(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 0, 0); // 0x00080000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCUPLS_GetTickCounter(u16 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0009, 0, 0); // 0x00090000 + + Result res = svcSendSyncRequest(mcuPlsHandle); + if (R_FAILED(res)) return res; + + *out_value = (u16)(cmdbuf[2] & 0xFFFF); + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/mcurtc.c b/libctru/source/services/mcurtc.c new file mode 100644 index 000000000..7a8c0adfb --- /dev/null +++ b/libctru/source/services/mcurtc.c @@ -0,0 +1,1224 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +#include + +static Handle mcuRtcHandle; +static int mcuRtcRefCount; + +Result mcuRtcInit(void) +{ + if (AtomicPostIncrement(&mcuRtcRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuRtcHandle, "mcu::RTC"); + if (R_FAILED(res)) AtomicDecrement(&mcuRtcRefCount); + return res; +} + +void mcuRtcExit(void) +{ + if (AtomicDecrement(&mcuRtcRefCount)) return; + svcCloseHandle(mcuRtcHandle); +} + +Handle *mcuRtcGetSessionHandle(void) +{ + return &mcuRtcHandle; +} + +Result MCURTC_SetRtcTime(const MCU_RtcTime *time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 2, 0); // 0x00010080 + memcpy(&cmdbuf[1], time, sizeof(MCU_RtcTime)); + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTime(MCU_RtcTime *out_time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 0, 0); // 0x00020000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + memcpy(out_time, &cmdbuf[2], sizeof(MCU_RtcTime)); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeSeconds(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 1, 0); // 0x00030040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeSeconds(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0004, 0, 0); // 0x00040000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeMinute(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0005, 1, 0); // 0x00050040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeMinute(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0006, 0, 0); // 0x00060000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeHour(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0007, 1, 0); // 0x00070040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeHour(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0008, 0, 0); // 0x00080000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeWeekday(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0009, 1, 0); // 0x00090040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeWeekday(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000A, 0, 0); // 0x000A0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeDay(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000B, 1, 0); // 0x000B0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeDay(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000C, 0, 0); // 0x000C0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeMonth(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000D, 1, 0); // 0x000D0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeMonth(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000E, 0, 0); // 0x000E0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeYear(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x000F, 1, 0); // 0x000F0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeYear(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0010, 0, 0); // 0x00100000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcTimeCorrection(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0011, 1, 0); // 0x00110040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcTimeCorrection(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0012, 0, 0); // 0x00120000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTime(const MCU_RtcAlarmTime *time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0013, 2, 0); // 0x00130080 + memcpy(&cmdbuf[1], time, sizeof(MCU_RtcAlarmTime)); + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTime(MCU_RtcAlarmTime *out_time) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0014, 0, 0); // 0x00140000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + memcpy(out_time, &cmdbuf[2], sizeof(MCU_RtcAlarmTime)); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTimeMinute(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0015, 1, 0); // 0x00150040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTimeMinute(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0016, 0, 0); // 0x00160000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTimeHour(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0017, 1, 0); // 0x00170040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTimeHour(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0018, 0, 0); // 0x00180000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTimeDay(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0019, 1, 0); // 0x00190040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTimeDay(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001A, 0, 0); // 0x001A0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTimeMonth(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001B, 1, 0); // 0x001B0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTimeMonth(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001C, 0, 0); // 0x001C0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetRtcAlarmTimeYear(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001D, 1, 0); // 0x001D0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetRtcAlarmTimeYear(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001E, 0, 0); // 0x001E0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = cmdbuf[2] & 0xFF; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetPedometerEnabled(bool enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x001F, 1, 0); // 0x001F0040 + cmdbuf[1] = !!enabled; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetPedometerEnabled(bool *out_enabled) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0020, 0, 0); // 0x00200000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_enabled = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_ReadPedometerStepCount(u32 *out_num_steps) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0021, 0, 0); // 0x00210000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_num_steps = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_ReadPedometerStepData(MCU_PedometerStepData *out_data) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0022, 1, 2); // 0x00220042 + cmdbuf[1] = sizeof(MCU_PedometerStepData); + cmdbuf[2] = IPC_Desc_Buffer(sizeof(MCU_PedometerStepData), IPC_BUFFER_W); + cmdbuf[3] = (u32)out_data; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_ClearStepData() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0023, 0, 0); // 0x00230000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetEventHandle(Handle *out_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0024, 0, 0); // 0x00240000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_handle = cmdbuf[3]; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetReceivedEvents(u32 *out_events) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0025, 0, 0); // 0x00250000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_events = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_CheckRtcTimeLost(bool *out_lost) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0026, 0, 0); // 0x00260000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_lost = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_ClearRtcTimeLost() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0027, 0, 0); // 0x00270000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_CheckWatchdogResetOccurred(bool *out_occurred) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0028, 0, 0); // 0x00280000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_occurred = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +/** + * @brief Clears the "watchdog reset occurred" flag. + */ +Result MCURTC_ClearWatchdogResetOccurred() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0029, 0, 0); // 0x00290000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetShellState(bool *out_open) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002A, 0, 0); // 0x002A0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_open = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetAdapterState(bool *out_connected) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002B, 0, 0); // 0x002B0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_connected = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetChargingState(bool *out_connected) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002C, 0, 0); // 0x002C0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_connected = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetBatteryLevel(u8 *out_level) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002D, 0, 0); // 0x002D0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_level = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetPowerLedState(MCU_PowerLedState state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002E, 1, 0); // 0x002E0040 + cmdbuf[1] = state; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetPowerLedState(MCU_PowerLedState *out_state) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x002F, 0, 0); // 0x002F0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_state = (MCU_PowerLedState)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetLedBrightness(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0030, 1, 0); // 0x00300040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetLedBrightness(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0031, 0, 0); // 0x00310000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_Poweroff() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0032, 0, 0); // 0x00320000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_Reboot() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0033, 0, 0); // 0x00330000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_Reset() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0034, 0, 0); // 0x00340000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SignalEnterSleepMode() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0035, 0, 0); // 0x00350000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetForceShutdownDelay(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0036, 1, 0); // 0x00360040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetForceShutdownDelay(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0037, 0, 0); // 0x00370000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_ReadInfoRegister(void *data, u8 size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0038, 1, 2); // 0x00380042 + cmdbuf[1] = (u32)size; + cmdbuf[2] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmdbuf[3] = (u32)data; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_WriteStorageArea(u8 offset, void *buf, u8 size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0039, 2, 2); // 0x00390082 + cmdbuf[1] = offset; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_Buffer(size, IPC_BUFFER_R); + cmdbuf[4] = (u32)buf; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_ReadStorageArea(u8 offset, void *buf, u8 size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003A, 2, 2); // 0x003A0082 + cmdbuf[1] = offset; + cmdbuf[2] = size; + cmdbuf[3] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmdbuf[4] = (u32)buf; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetInfoLedPattern(const MCU_InfoLedPattern *pattern) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003B, 25, 0); // 0x003B0640 + memcpy(&cmdbuf[1], pattern, sizeof(MCU_InfoLedPattern)); + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetInfoLedAnimation(const MCU_InfoLedAnimation *animation) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003C, 1, 0); // 0x003C0040 + memcpy(&cmdbuf[1], animation, sizeof(MCU_InfoLedAnimation)); + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetInfoLedCycleStatus(bool *out_new_cycle_started) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003D, 0, 0); // 0x003D0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_new_cycle_started = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetPedometerWrapTimeMinute(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003E, 1, 0); // 0x003E0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetPedometerWrapTimeMinute(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x003F, 0, 0); // 0x003F0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetPedometerWrapTimeSecond(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0040, 1, 0); // 0x00400040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetPedometerWrapTimeSecond(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0041, 0, 0); // 0x00410000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetPowerLedBlinkPattern(u32 pattern) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0042, 1, 0); // 0x00420040 + cmdbuf[1] = pattern; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetTopLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0043, 1, 0); // 0x00430040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetTopLcdFlicker(u8 *out_flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0044, 0, 0); // 0x00440000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_flicker = cmdbuf[2] & 0xFF; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetBottomLcdFlicker(u8 flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0045, 1, 0); // 0x00450040 + cmdbuf[1] = (u32)flicker; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetBottomLcdFlicker(u8 *out_flicker) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0046, 0, 0); // 0x00460000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_flicker = cmdbuf[2] & 0xFF; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetVolumeSliderBounds(u8 min, u8 max) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0047, 2, 0); // 0x00470080 + cmdbuf[1] = min; + cmdbuf[2] = max; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetVolumeSliderBounds(u8 *out_min, u8 *out_max) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0048, 0, 0); // 0x00480000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_min = (u8)(cmdbuf[2] & 0xFF); + *out_max = (u8)(cmdbuf[3] & 0xFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetInterruptMask(u32 mask) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0049, 1, 0); // 0x00490040 + cmdbuf[1] = mask; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetInterruptMask(u32 *out_mask) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004A, 0, 0); // 0x004A0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_mask = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_LeaveExclusiveInterruptMode() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004B, 0, 0); // 0x004B0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_EnterExclusiveInterruptMode() +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004C, 0, 0); // 0x004C0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_ReadInterrupts(u32 *out_interrupts) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004D, 0, 0); // 0x004D0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_interrupts = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_TriggerInterrupts(u32 interrupts) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004E, 1, 0); // 0x004E0040 + cmdbuf[1] = interrupts; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetMcuFirmUpdatedFlag(bool value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x004F, 1, 0); // 0x004F0040 + cmdbuf[1] = !!value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetMcuFirmUpdatedFlag(bool *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0050, 0, 0); // 0x00500000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetSoftwareClosedFlag(bool value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0051, 1, 0); // 0x00510040 + cmdbuf[1] = !!value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetSoftwareClosedFlag(bool *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0052, 0, 0); // 0x00520000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetLgyLcdSettings(MCU_LgyLcdSettings settings) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0053, 1, 0); // 0x00530040 + cmdbuf[1] = *((u8 *)&settings); + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetLgyLcdSettings(MCU_LgyLcdSettings *out_settings) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0054, 0, 0); // 0x00540000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_settings = *((MCU_LgyLcdSettings *)&cmdbuf[2]); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetLgyNativeResolutionFlag(bool value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0055, 1, 0); // 0x00550040 + cmdbuf[1] = !!value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetLgyNativeResolutionFlag(bool *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0056, 0, 0); // 0x00560000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetLocalFriendCodeCounter(u16 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0057, 1, 0); // 0x00570040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetLocalFriendCodeCounter(u16 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0058, 0, 0); // 0x00580000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u16)(cmdbuf[2] & 0xFFFF); + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetLegacyJumpProhibitedFlag(bool value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0059, 1, 0); // 0x00590040 + cmdbuf[1] = !!value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetLegacyJumpProhibitedFlag(bool *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x005A, 0, 0); // 0x005A0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = !!cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCURTC_SetUuidClockSequence(u16 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x005B, 1, 0); // 0x005B0040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCURTC_GetUuidClockSequence(u16 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x005C, 0, 0); // 0x005C0000 + + Result res = svcSendSyncRequest(mcuRtcHandle); + if (R_FAILED(res)) return res; + + *out_value = (u16)(cmdbuf[2] & 0xFFFF); + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/mcusnd.c b/libctru/source/services/mcusnd.c new file mode 100644 index 000000000..d8a811ce7 --- /dev/null +++ b/libctru/source/services/mcusnd.c @@ -0,0 +1,68 @@ +#include <3ds/services/mcu_common.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/types.h> +#include <3ds/ipc.h> +#include <3ds/srv.h> + +static Handle mcuSndHandle; +static int mcuSndRefCount; + +Result mcuSndInit(void) +{ + if (AtomicPostIncrement(&mcuSndRefCount)) return 0; + Result res = srvGetServiceHandle(&mcuSndHandle, "mcu::SND"); + if (R_FAILED(res)) AtomicDecrement(&mcuSndRefCount); + return res; +} + +void mcuSndExit(void) +{ + if (AtomicDecrement(&mcuSndRefCount)) return; + svcCloseHandle(mcuSndHandle); +} + +Handle *mcuSndGetSessionHandle(void) +{ + return &mcuSndHandle; +} + +Result MCUSND_GetVolumeSliderLevel(u8 *level) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0001, 0, 0); // 0x00010000 + + Result res = svcSendSyncRequest(mcuSndHandle); + if (R_FAILED(res)) return res; + + *level = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result MCUSND_WriteReg25h(u8 value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0002, 1, 0); // 0x00020040 + cmdbuf[1] = value; + + Result res = svcSendSyncRequest(mcuSndHandle); + if (R_FAILED(res)) return res; + return (Result)cmdbuf[1]; +} + +Result MCUSND_ReadReg25h(u8 *out_value) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x0003, 0, 0); // 0x00030000 + + Result res = svcSendSyncRequest(mcuSndHandle); + if (R_FAILED(res)) return res; + + *out_value = (u8)(cmdbuf[2] & 0xFF); + + return (Result)cmdbuf[1]; +} \ No newline at end of file