Merge sys-clk-oc and add upto 2903 clocks (please don't use)

I do have to come up with a better name too...
This commit is contained in:
souldbminersmwc
2025-08-22 18:31:38 -04:00
parent 822556e6e4
commit 4738eea080
289 changed files with 50229 additions and 4772 deletions

View File

@@ -165,7 +165,8 @@ volatile CustomizeTable C = {
{ 2091000, { 1716501, -39395, 27 }, { 1235000 } },
{ 2193000, { 1775132, -40505, 27 }, { 1235000 } },
{ 2295000, { 1866287, -42005, 27 }, { 1235000 } },
//{ 2397000, { 1961107, -43506, 27 }, { 1235000 } },
// Unsafe
{ 2397000, { 1961107, -43506, 27 }, { 1235000 } },
},
.marikoCpuDvfsTableSLT = {
@@ -192,6 +193,11 @@ volatile CustomizeTable C = {
{ 2193000, { 1580725, -33235, 113 }, { 1235000 } },
{ 2295000, { 1635431, -34095, 113 }, { 1235000 } },
{ 2397000, { 1702903, -34955, 113 }, { 1235000 } },
{ 2499000, { 1754400, -35643, 113 }, { 1235000 } },
{ 2601000, { 1805897, -36331, 113 }, { 1235000 } },
{ 2703000, { 1857394, -37019, 113 }, { 1235000 } },
{ 2805000, { 1908891, -37707, 113 }, { 1235000 } },
{ 2907000, { 1960388, -38395, 113 }, { 1250000 } },
},
/* - Erista GPU DVFS Table:
@@ -234,7 +240,7 @@ volatile CustomizeTable C = {
{ 1228800, {}, { 1277303, -11675, -859, 0, 3722, 313 } },
{ 1267200, {}, { 1335531, -12567, -867, 0, 3681, 559 } },
// Appending table
//{ 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
{ 1305600, {}, { 1374130, -13725, -859, 0, 4442, 576 } },
},
.marikoGpuDvfsTableSLT = {

View File

@@ -1 +0,0 @@
dist

View File

@@ -1,224 +0,0 @@
# sys-clk-OC
Switch sysmodule allowing you to set cpu/gpu clocks according to the running application and docked state.
## Clock table (MHz)
official means HOS official, unless specified
### CPU clocks
* 2397 → OC max for Mariko (with CPU UV)
* 2295 → OC max for Mariko
* 2193
* 2091 → OC max for Erista
* 1963 → official and safe max for Mariko
* 1887
* 1785 → official boost mode, safe max for Erista
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev OC
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612
### GPU clocks
* 1305 → N/A
* 1267 → official max for Mariko (Tegra X1+ official max)
* 1228 → recommended max for Hiopt
* 1152
* 1075 → recommended max for SLT
* 998 → safe max for Mariko, max for Erista (Tegra X1 official max)
* 921 → safe max for Erista
* 844
* 768 → official docked
* 691
* 614 → recommended Mariko max for handheld
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
### MEM clocks
From Hekate Minerva module [sys_sdrammtc.c](https://github.com/CTCaer/hekate/blob/master/modules/hekate_libsys_minerva/sys_sdrammtc.c#L65)
- 3200 → l4t and closed version max for Mariko
- 2931
- 2665
- 2502 → max for Mariko
- 2400
- 2361 → l4t and closed version max for Erista
- 2131 → JEDEC. max for Erista and official max for Mariko. lpddr4(x) official max
- 2099
- 2064
- 1996 → OCS mariko default
- 1932
- 1894
- 1862 → JEDEC. official max for Erista; OCS erista default
- 1795
- 1728
- 1600 → official docked & official boost mode
- 1331 → JEDEC. official handheld
- 1065
- 800
- 665
## Capping
To protect the battery from excessive strain, clocks requested from config may be capped before applying, depending on your current profile:
### Erista (Safe)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1785 | 1785 | 1785 | 1785 |
| **GPU** | 460 | 768 | 921 | 921 |
### Erista (Unsafe allowed)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1785 | 1785 | - | - |
| **GPU** | 460 | 768 | - | - |
### Mariko (Safe)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1963 | 1963 | 1963 | 1963 |
| **GPU** | 768 | 921 | 998 | 998 |
### Mariko (Unsafe allowed)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1963 | 1963 | - | - |
| **GPU** | 768 | 921 | - | - |
## Installation
The following instructions assumes you have a Nintendo Switch running Atmosphère, updated to at least the latest stable version.
Copy the `atmosphere`, and `switch` folders at the root of your sdcard, overwriting files if prompted. Also copy the `config` folder if you're not updating, to include default settings.
**Note:** sys-clk-overlay requires to have [Tesla](https://gbatemp.net/threads/tesla-the-nintendo-switch-overlay-menu.557362/) installed and running
## Relevant files
* Config file allows one to set custom clocks per docked state and title id, described below
`/config/sys-clk-oc/config.ini`
* Log file where the logs are written if enabled
`/config/sys-clk-oc/log.txt`
* Log flag file enables log writing if file exists
`/config/sys-clk-oc/log.flag`
* CSV file where the title id, profile, clocks and temperatures are written if enabled
`/config/sys-clk-oc/context.csv`
* sys-clk overlay (accessible from anywhere by invoking the [Tesla menu](https://gbatemp.net/threads/tesla-the-nintendo-switch-overlay-menu.557362/))
`/switch/.overlays/sys-clk-overlay.ovl`
* sys-clk core sysmodule
`/atmosphere/contents/00FF0000636C6BFF/exefs.nsp`
`/atmosphere/contents/00FF0000636C6BFF/flags/boot2.flag`
## Config
Presets can be customized by adding them to the ini config file located at `/config/sys-clk/config.ini`, using the following template for each app
```
[Application Title ID]
docked_cpu=
docked_gpu=
docked_mem=
handheld_charging_cpu=
handheld_charging_gpu=
handheld_charging_mem=
handheld_charging_usb_cpu=
handheld_charging_usb_gpu=
handheld_charging_usb_mem=
handheld_charging_official_cpu=
handheld_charging_official_gpu=
handheld_charging_official_mem=
handheld_cpu=
handheld_gpu=
handheld_mem=
governor_config=
```
* Replace `Application Title ID` with the title id of the game/application you're interested in customizing.
A list of games title id can be found in the [Switchbrew wiki](https://switchbrew.org/wiki/Title_list/Games).
* Frequencies are expressed in mhz, and will be scaled to the nearest possible values, described in the clock table below.
* If any key is omitted, value is empty or set to 0, it will be ignored, and stock clocks will apply.
* If charging, sys-clk will look for the frequencies in that order, picking the first found
1. Charger specific config (USB or Official) `handheld_charging_usb_X` or `handheld_charging_official_X`
2. Non specific charging config `handheld_charging_X`
3. Handheld config `handheld_X`
### Example 1: Zelda BOTW
* Overclock CPU when docked or charging
Leads to a smoother framerate overall (ex: in the korok forest)
```
[01007EF00011E000]
docked_cpu=1224
handheld_charging_cpu=1224
handheld_mem=1600
```
### Example 2: Picross
* Underclocks on handheld to save battery
```
[0100BA0003EEA000]
handheld_cpu=816
handheld_gpu=153
```
### Advanced
The `[values]` section allows you to alter timings in sys-clk, you should not need to edit any of these unless you know what you are doing. Possible values are:
| Key | Desc | Default |
|:------------------------:|-------------------------------------------------------------------------------|:---------:|
|**allow_unsafe_freq** | Allow unsafe frequencies (CPU > 1963.5 MHz, GPU > 921.6 MHz) | OFF |
|**uncapped_clocks** | Remove CPU/GPU clock cappings | OFF |
|**temp_log_interval_ms** | Defines how often sys-clk log temperatures, in milliseconds (`0` to disable) | 0 ms |
|**csv_write_interval_ms** | Defines how often sys-clk writes to the CSV, in milliseconds (`0` to disable) | 0 ms |
|**poll_interval_ms** | Defines how fast sys-clk checks and applies profiles, in milliseconds | 500 ms |
Only available for prior to Switch OC Suite 1.9.0
| Key | Desc | Default |
|:------------------------:|-------------------------------------------------------------------------------|:---------:|
|**auto_cpu_boost** | Auto-boost CPU when system Core #3 utilization ≥ 95% | OFF |
|**sync_reversenx_mode** | Sync nominal profile (mode) with ReverseNX (-Tool and -RT) | ON |
|**charging_current** | Charging current limit (100 mA - 2000 mA) | 2000 mA |
|**charging_limit_perc** | Charging limit (20% - 100%) | 100%(OFF) |
|**governor_experimental** | CPU & GPU frequency governor (Experimental) | OFF |
|**governor_handheld_only**| Use governor only on Handheld Profile | OFF |

View File

@@ -1,36 +0,0 @@
#pragma once
#include <utility>
template<typename F>
class ScopeGuard {
public:
ScopeGuard(F&& f)
: f(f), engaged(true) {};
~ScopeGuard() {
if (engaged)
f();
};
ScopeGuard(ScopeGuard&& rhs)
: f(std::move(rhs.f)) {};
void dismiss() { engaged = false; }
private:
F f;
bool engaged;
};
struct MakeScopeExit {
template<typename F>
ScopeGuard<F> operator+=(F&& f) {
return ScopeGuard<F>(std::move(f));
};
};
#define STRING_CAT2(x, y) x##y
#define STRING_CAT(x, y) STRING_CAT2(x, y)
#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline))
#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD

View File

@@ -1,183 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef enum
{
SysClkProfile_Handheld = 0,
SysClkProfile_HandheldCharging,
SysClkProfile_HandheldChargingUSB,
SysClkProfile_HandheldChargingOfficial,
SysClkProfile_Docked,
SysClkProfile_EnumMax
} SysClkProfile;
typedef enum
{
SysClkModule_CPU = 0,
SysClkModule_GPU,
SysClkModule_MEM,
SysClkModule_EnumMax
} SysClkModule;
typedef enum
{
SysClkThermalSensor_SOC = 0,
SysClkThermalSensor_PCB,
SysClkThermalSensor_Skin,
SysClkThermalSensor_EnumMax
} SysClkThermalSensor;
typedef struct
{
uint8_t enabled;
uint64_t applicationId;
SysClkProfile profile;
uint32_t freqs[SysClkModule_EnumMax];
uint32_t overrideFreqs[SysClkModule_EnumMax];
uint32_t temps[SysClkThermalSensor_EnumMax];
uint32_t perfConfId;
} SysClkContext;
typedef enum
{
ReverseNX_NotFound = 0,
ReverseNX_SystemDefault = 0,
ReverseNX_Handheld,
ReverseNX_Docked,
} ReverseNXMode;
typedef struct
{
bool systemCoreBoostCPU;
bool batteryChargingDisabledOverride;
SysClkProfile realProfile;
} SysClkOcExtra;
#define FREQ_TABLE_MAX_ENTRY_COUNT 31
typedef struct
{
uint32_t freq[FREQ_TABLE_MAX_ENTRY_COUNT];
} SysClkFrequencyTable;
typedef enum {
SysClkOcGovernorConfig_AllDisabled = 0,
SysClkOcGovernorConfig_CPU_Shift = 0,
SysClkOcGovernorConfig_CPUOnly = 1 << SysClkOcGovernorConfig_CPU_Shift,
SysClkOcGovernorConfig_CPU = 1 << SysClkOcGovernorConfig_CPU_Shift,
SysClkOcGovernorConfig_GPU_Shift = 1,
SysClkOcGovernorConfig_GPUOnly = 1 << SysClkOcGovernorConfig_GPU_Shift,
SysClkOcGovernorConfig_GPU = 1 << SysClkOcGovernorConfig_GPU_Shift,
SysClkOcGovernorConfig_AllEnabled = 3,
SysClkOcGovernorConfig_Default = 3,
SysClkOcGovernorConfig_Mask = 3,
} SysClkOcGovernorConfig;
inline bool GetGovernorEnabled(SysClkOcGovernorConfig config, SysClkModule module) {
switch (module) {
case SysClkModule_CPU:
return (config >> SysClkOcGovernorConfig_CPU_Shift) & 1;
case SysClkModule_GPU:
return (config >> SysClkOcGovernorConfig_GPU_Shift) & 1;
case SysClkModule_MEM:
return false;
default:
return config != SysClkOcGovernorConfig_AllDisabled;
}
}
inline SysClkOcGovernorConfig ToggleGovernor(SysClkOcGovernorConfig prev, SysClkModule module, bool state) {
uint8_t shift;
switch (module) {
case SysClkModule_CPU:
shift = SysClkOcGovernorConfig_CPU_Shift;
break;
case SysClkModule_GPU:
shift = SysClkOcGovernorConfig_GPU_Shift;
break;
case SysClkModule_MEM:
return prev;
default:
return state ? SysClkOcGovernorConfig_AllEnabled : SysClkOcGovernorConfig_AllDisabled;
}
return (SysClkOcGovernorConfig)((prev & ~(1 << shift)) | state << shift);
}
typedef struct
{
union {
uint32_t mhz[(size_t)SysClkProfile_EnumMax * (size_t)SysClkModule_EnumMax];
uint32_t mhzMap[SysClkProfile_EnumMax][SysClkModule_EnumMax];
};
SysClkOcGovernorConfig governorConfig;
} SysClkTitleProfileList;
#define SYSCLK_GLOBAL_PROFILE_TID 0xA111111111111111
extern uint32_t g_freq_table_mem_hz[];
extern uint32_t g_freq_table_cpu_hz[];
extern uint32_t g_freq_table_gpu_hz[];
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)
{
switch(module)
{
case SysClkModule_CPU:
return pretty ? "CPU" : "cpu";
case SysClkModule_GPU:
return pretty ? "GPU" : "gpu";
case SysClkModule_MEM:
return pretty ? "Memory" : "mem";
default:
return NULL;
}
}
static inline const char* sysclkFormatThermalSensor(SysClkThermalSensor thermSensor, bool pretty)
{
switch(thermSensor)
{
case SysClkThermalSensor_SOC:
return pretty ? "SOC" : "soc";
case SysClkThermalSensor_PCB:
return pretty ? "PCB" : "pcb";
case SysClkThermalSensor_Skin:
return pretty ? "Skin" : "skin";
default:
return NULL;
}
}
static inline const char* sysclkFormatProfile(SysClkProfile profile, bool pretty)
{
switch(profile)
{
case SysClkProfile_Docked:
return pretty ? "Docked" : "docked";
case SysClkProfile_Handheld:
return pretty ? "Handheld" : "handheld";
case SysClkProfile_HandheldCharging:
return pretty ? "Charging" : "handheld_charging";
case SysClkProfile_HandheldChargingUSB:
return pretty ? "USB Charger" : "handheld_charging_usb";
case SysClkProfile_HandheldChargingOfficial:
return pretty ? "Official Charger" : "handheld_charging_official";
default:
return NULL;
}
}

View File

@@ -1,111 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
const uint32_t CHARGING_CURRENT_MA_LIMIT = 2000;
typedef enum {
SysClkConfigValue_PollingIntervalMs = 0,
SysClkConfigValue_TempLogIntervalMs,
SysClkConfigValue_CsvWriteIntervalMs,
SysClkConfigValue_AutoCPUBoost,
SysClkConfigValue_SyncReverseNXMode,
SysClkConfigValue_AllowUnsafeFrequencies,
SysClkConfigValue_ChargingCurrentLimit,
SysClkConfigValue_ChargingLimitPercentage,
SysClkConfigValue_GovernorExperimental,
SysClkConfigValue_GovernorHandheldOnly,
SysClkConfigValue_EnumMax,
} SysClkConfigValue;
typedef struct {
uint64_t values[SysClkConfigValue_EnumMax];
} SysClkConfigValueList;
static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pretty)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return pretty ? "Polling Interval (ms)" : "poll_interval_ms";
case SysClkConfigValue_TempLogIntervalMs:
return pretty ? "Temperature logging interval (ms)" : "temp_log_interval_ms";
case SysClkConfigValue_CsvWriteIntervalMs:
return pretty ? "CSV write interval (ms)" : "csv_write_interval_ms";
case SysClkConfigValue_AutoCPUBoost:
return pretty ? "Auto CPU Boost" : "auto_cpu_boost";
case SysClkConfigValue_SyncReverseNXMode:
return pretty ? "Sync ReverseNX Mode Sync" : "sync_reversenx_mode";
case SysClkConfigValue_AllowUnsafeFrequencies:
return pretty ? "Allow Unsafe Frequencies" : "allow_unsafe_freq";
case SysClkConfigValue_ChargingCurrentLimit:
return pretty ? "Charging Current Limit (mA)" : "charging_current";
case SysClkConfigValue_ChargingLimitPercentage:
return pretty ? "Charging Limit (%%)" : "charging_limit_perc";
case SysClkConfigValue_GovernorExperimental:
return pretty ? "Frequency Governor (Experimental)" : "governor_experimental";
case SysClkConfigValue_GovernorHandheldOnly:
return pretty ? "Frequency Governor Handheld Only" : "governor_handheld_only";
default:
return NULL;
}
}
static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return 500ULL;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
case SysClkConfigValue_AllowUnsafeFrequencies:
case SysClkConfigValue_GovernorExperimental:
case SysClkConfigValue_GovernorHandheldOnly:
case SysClkConfigValue_AutoCPUBoost:
return 0ULL;
case SysClkConfigValue_SyncReverseNXMode:
return 1ULL;
case SysClkConfigValue_ChargingCurrentLimit:
return 2000ULL;
case SysClkConfigValue_ChargingLimitPercentage:
return 100ULL;
default:
return 0ULL;
}
}
static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t input)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return input > 0;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
return true;
case SysClkConfigValue_AutoCPUBoost:
case SysClkConfigValue_SyncReverseNXMode:
case SysClkConfigValue_AllowUnsafeFrequencies:
case SysClkConfigValue_GovernorExperimental:
case SysClkConfigValue_GovernorHandheldOnly:
return (input & 0x1) == input;
case SysClkConfigValue_ChargingCurrentLimit:
return (input >= 100 && input <= CHARGING_CURRENT_MA_LIMIT && input % 100 == 0);
case SysClkConfigValue_ChargingLimitPercentage:
return (input <= 100 && input >= 20);
default:
return false;
}
}

View File

@@ -1,57 +0,0 @@
#pragma once
#include <switch.h>
// To use i2c service, sm and i2c should be intialized via smInitialize() and i2cInitialize().
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val);
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out);
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out);
// Max17050 fuel gauge
float I2c_Max17050_GetBatteryCurrent();
const u8 MAX17050_CURRENT_REG = 0x0A;
// Buck Converter
typedef enum I2c_BuckConverter_Reg {
I2c_Max77620_SD1VOLT_REG = 0x17, // Used for Erista DDR VDDQ+VDD2 / Mariko VDD2
I2c_Max77621_VOLT_REG = 0x00,
I2c_Max77812_CPUVOLT_REG = 0x26,
I2c_Max77812_GPUVOLT_REG = 0x23,
I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4), used for Mariko VDDQ
} I2c_BuckConverter_Reg;
typedef struct I2c_BuckConverter_Domain {
I2cDevice device;
I2c_BuckConverter_Reg reg;
u8 volt_mask;
u32 uv_step;
u32 uv_min;
u32 uv_max;
u8 por_val;
} I2c_BuckConverter_Domain;
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDDQ = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 650000, 0x78 };
const I2c_BuckConverter_Domain I2c_Mariko_DRAM_VDD2 = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
// Bq24193 Battery management
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw);
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma);
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma);
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma);
const u32 MA_RANGE_MIN = 512;
const u32 MA_RANGE_MAX = 4544;
const u8 BQ24193_CHARGE_CURRENT_CONTROL_REG = 0x2;

View File

@@ -1,77 +0,0 @@
#pragma once
#include <switch.h>
typedef enum {
PsmPDC_NewPDO = 1, //Received new Power Data Object
PsmPDC_NoPD = 2, //No Power Delivery source is detected
PsmPDC_AcceptedRDO = 3 //Received and accepted Request Data Object
} PsmChargeInfoPDC; //BM92T series
typedef enum {
PsmPowerRole_Sink = 1,
PsmPowerRole_Source = 2
} PsmPowerRole;
const char* PsmPowerRoleToStr(PsmPowerRole role);
typedef enum {
PsmInfoChargerType_None = 0,
PsmInfoChargerType_PD = 1,
PsmInfoChargerType_TypeC_1500mA = 2,
PsmInfoChargerType_TypeC_3000mA = 3,
PsmInfoChargerType_DCP = 4,
PsmInfoChargerType_CDP = 5,
PsmInfoChargerType_SDP = 6,
PsmInfoChargerType_Apple_500mA = 7,
PsmInfoChargerType_Apple_1000mA = 8,
PsmInfoChargerType_Apple_2000mA = 9
} PsmInfoChargerType;
const char* PsmInfoChargerTypeToStr(PsmInfoChargerType type);
typedef enum {
PsmFlags_NoHub = BIT(0), //If hub is disconnected
PsmFlags_Rail = BIT(8), //At least one Joy-con is charging from rail
PsmFlags_SPDSRC = BIT(12), //OTG
PsmFlags_ACC = BIT(16) //Accessory
} PsmChargeInfoFlags;
typedef struct {
int32_t InputCurrentLimit; //Input (Sink) current limit in mA
int32_t VBUSCurrentLimit; //Output (Source/VBUS/OTG) current limit in mA
int32_t ChargeCurrentLimit; //Battery charging current limit in mA (512mA when Docked, 768mA when BatteryTemperature < 17.0 C)
int32_t ChargeVoltageLimit; //Battery charging voltage limit in mV (3952mV when BatteryTemperature >= 51.0 C)
int32_t unk_x10; //Possibly an emum, getting the same value as PowerRole in all tested cases
int32_t unk_x14; //Possibly flags
PsmChargeInfoPDC PDCState; //Power Delivery Controller State
int32_t BatteryTemperature; //Battery temperature in milli C
int32_t RawBatteryCharge; //Raw battery charged capacity per cent-mille (i.e. 100% = 100000 pcm)
int32_t VoltageAvg; //Voltage avg in mV (more in Notes)
int32_t BatteryAge; //Battery age (capacity full / capacity design) per cent-mille (i.e. 100% = 100000 pcm)
PsmPowerRole PowerRole;
PsmInfoChargerType ChargerType;
int32_t ChargerVoltageLimit; //Charger and external device voltage limit in mV
int32_t ChargerCurrentLimit; //Charger and external device current limit in mA
PsmChargeInfoFlags Flags; //Unknown flags
} PsmChargeInfo;
typedef enum {
Psm_EnableBatteryCharging = 2,
Psm_DisableBatteryCharging = 3,
Psm_EnableFastBatteryCharging = 10,
Psm_DisableFastBatteryCharging = 11,
Psm_GetBatteryChargeInfoFields = 17,
} IPsmServerCmd;
bool PsmIsChargerConnected(const PsmChargeInfo* info);
bool PsmIsCharging(const PsmChargeInfo* info);
typedef enum {
PsmBatteryState_Discharging,
PsmBatteryState_ChargingPaused,
PsmBatteryState_FastCharging
} PsmBatteryState;
PsmBatteryState PsmGetBatteryState(const PsmChargeInfo* info);
const char* PsmGetBatteryStateIcon(const PsmChargeInfo* info);

View File

@@ -1,186 +0,0 @@
#include <sysclk/i2c.h>
Result I2cSet_U8(I2cDevice dev, u8 reg, u8 val) {
// ams::fatal::srv::StopSoundTask::StopSound()
// I2C Bus Communication Reference: https://www.ti.com/lit/an/slva704/slva704.pdf
struct {
u8 reg;
u8 val;
} __attribute__((packed)) cmd;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
cmd.val = val;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
i2csessionClose(&_session);
return res;
}
Result I2cRead_OutU8(I2cDevice dev, u8 reg, u8 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u8 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
Result I2cRead_OutU16(I2cDevice dev, u8 reg, u16 *out) {
struct { u8 reg; } __attribute__((packed)) cmd;
struct { u16 val; } __attribute__((packed)) rec;
I2cSession _session;
Result res = i2cOpenSession(&_session, dev);
if (res)
return res;
cmd.reg = reg;
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
if (res) {
i2csessionClose(&_session);
return res;
}
res = i2csessionReceiveAuto(&_session, &rec, sizeof(rec), I2cTransactionOption_All);
i2csessionClose(&_session);
if (res) {
return res;
}
*out = rec.val;
return 0;
}
float I2c_Max17050_GetBatteryCurrent() {
u16 val;
Result res = I2cRead_OutU16(I2cDevice_Max17050, MAX17050_CURRENT_REG, &val);
if (res)
return 0.f;
const float SenseResistor = 5.; // in uOhm
const float CGain = 1.99993;
return (s16)val * (1.5625 / (SenseResistor * CGain));
}
u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
}
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u32 uvolt = mvolt * 1000;
if (uvolt < domain->uv_min)
uvolt = domain->uv_min;
if (uvolt > domain->uv_max)
uvolt = domain->uv_max;
return (uvolt - domain->uv_min) / domain->uv_step;
}
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
u8 val;
// Retry 5 times if received POR value
for (int i = 0; i < 5; i++) {
if (R_FAILED(I2cRead_OutU8(domain->device, domain->reg, &val)))
return 0u;
// Wait 1us
svcSleepThread(1E3);
if (!domain->por_val || val != domain->por_val)
break;
}
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
}
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
u8 val;
Result res = I2cRead_OutU8(domain->device, domain->reg, &val);
if (R_FAILED(res))
return res;
u8 multiplier = I2c_BuckConverter_MvOutToMultiplier(domain, mvolt);
val &= ~domain->volt_mask;
val |= multiplier & domain->volt_mask;
res = I2cSet_U8(domain->device, domain->reg, val);
if (R_FAILED(res))
return res;
// 5ms Ramp delay
svcSleepThread(5E6);
u8 new_val;
res = I2cRead_OutU8(domain->device, domain->reg, &new_val);
if (R_FAILED(res))
return res;
if (new_val != val)
return -1;
return 0;
}
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) {
// Adjustment is required
u8 raw = 0;
if (ma > MA_RANGE_MAX) // capping
ma = MA_RANGE_MAX;
bool pct20 = ma <= (MA_RANGE_MIN - 64);
if (pct20) {
ma = ma * 5;
raw |= 0x1;
}
ma -= ma % 100; // round to 100
ma -= (MA_RANGE_MIN - 64); // ceiling
raw |= (ma >> 6) << 2;
return raw;
};
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw) {
// No adjustment is allowed
u32 ma = (((raw >> 2)) << 6) + MA_RANGE_MIN;
bool pct20 = raw & 1;
if (pct20)
ma = ma * 20 / 100;
return ma;
};
Result I2c_Bq24193_GetFastChargeCurrentLimit(u32 *ma) {
u8 raw;
Result res = I2cRead_OutU8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, &raw);
if (res)
return res;
*ma = I2c_Bq24193_Convert_Raw_mA(raw);
return 0;
}
Result I2c_Bq24193_SetFastChargeCurrentLimit(u32 ma) {
u8 raw = I2c_Bq24193_Convert_mA_Raw(ma);
return I2cSet_U8(I2cDevice_Bq24193, BQ24193_CHARGE_CURRENT_CONTROL_REG, raw);
}

View File

@@ -1,50 +0,0 @@
#include <sysclk/psm_ext.h>
const char* PsmPowerRoleToStr(PsmPowerRole role) {
switch (role) {
case PsmPowerRole_Sink: return "Sink";
case PsmPowerRole_Source: return "Source";
default: return "Unknown";
}
}
const char* PsmInfoChargerTypeToStr(PsmInfoChargerType type) {
switch (type) {
case PsmInfoChargerType_None: return "None";
case PsmInfoChargerType_PD: return "USB-C PD";
case PsmInfoChargerType_TypeC_1500mA:
case PsmInfoChargerType_TypeC_3000mA: return "USB-C";
case PsmInfoChargerType_DCP: return "USB DCP";
case PsmInfoChargerType_CDP: return "USB CDP";
case PsmInfoChargerType_SDP: return "USB SDP";
case PsmInfoChargerType_Apple_500mA:
case PsmInfoChargerType_Apple_1000mA:
case PsmInfoChargerType_Apple_2000mA: return "Apple";
default: return "Unknown";
}
}
bool PsmIsChargerConnected(const PsmChargeInfo* info) {
return info->ChargerType != PsmInfoChargerType_None;
}
bool PsmIsCharging(const PsmChargeInfo* info) {
return PsmIsChargerConnected(info) && ((info->unk_x14 >> 8) & 1);
}
PsmBatteryState PsmGetBatteryState(const PsmChargeInfo* info) {
if (!PsmIsChargerConnected(info))
return PsmBatteryState_Discharging;
if (!PsmIsCharging(info))
return PsmBatteryState_ChargingPaused;
return PsmBatteryState_FastCharging;
}
const char* PsmGetBatteryStateIcon(const PsmChargeInfo* info) {
switch (PsmGetBatteryState(info)) {
case PsmBatteryState_Discharging: return "\u25c0"; // ◀
case PsmBatteryState_ChargingPaused:return "| |";
case PsmBatteryState_FastCharging: return "\u25b6"; // ▶
default: return "?";
}
}

View File

@@ -1,114 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include "base_menu_gui.h"
#include "fatal_gui.h"
BaseMenuGui::BaseMenuGui()
{
this->context = nullptr;
this->lastContextUpdate = 0;
this->listElement = nullptr;
}
BaseMenuGui::~BaseMenuGui()
{
if(this->context)
{
delete this->context;
}
}
void BaseMenuGui::preDraw(tsl::gfx::Renderer* renderer)
{
BaseGui::preDraw(renderer);
if(this->context)
{
char buf[32];
renderer->drawString("App ID: ", false, 40, 60, SMALL_TEXT_SIZE, DESC_COLOR);
snprintf(buf, sizeof(buf), "%016lX", context->applicationId);
renderer->drawString(buf, false, 100, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
renderer->drawString("Profile: ", false, 266, 60, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString(sysclkFormatProfile(context->profile, true), false, 322, 60, SMALL_TEXT_SIZE, VALUE_COLOR);
static struct
{
SysClkModule m;
std::uint32_t x;
} freqOffsets[SysClkModule_EnumMax] = {
{ SysClkModule_CPU, 80 },
{ SysClkModule_GPU, 200 },
{ SysClkModule_MEM, 320 },
};
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
{
std::uint32_t hz = this->context->freqs[freqOffsets[i].m];
snprintf(buf, sizeof(buf), "%u MHz", hz / 1000000);
renderer->drawString(buf, false, freqOffsets[i].x, 85, SMALL_TEXT_SIZE, VALUE_COLOR);
}
renderer->drawString("CPU:", false, 40, 85, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("GPU:", false, 160, 85, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("MEM:", false, 270, 85, SMALL_TEXT_SIZE, DESC_COLOR);
static struct
{
SysClkThermalSensor s;
std::uint32_t x;
} tempOffsets[SysClkModule_EnumMax] = {
{ SysClkThermalSensor_SOC, 80 },
{ SysClkThermalSensor_PCB, 200 },
{ SysClkThermalSensor_Skin, 320 },
};
renderer->drawString("SOC:", false, 40, 110, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("PCB:", false, 160, 110, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString("Skin:", false, 270, 110, SMALL_TEXT_SIZE, DESC_COLOR);
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
{
std::uint32_t millis = this->context->temps[tempOffsets[i].s];
snprintf(buf, sizeof(buf), "%u.%u °C", millis / 1000, (millis - millis / 1000 * 1000) / 100);
renderer->drawString(buf, false, tempOffsets[i].x, 110, SMALL_TEXT_SIZE, VALUE_COLOR);
}
}
}
void BaseMenuGui::refresh()
{
std::uint64_t ticks = armGetSystemTick();
if(armTicksToNs(ticks - this->lastContextUpdate) > 500000000UL)
{
this->lastContextUpdate = ticks;
if(!this->context)
{
this->context = new SysClkContext;
}
Result rc = sysclkIpcGetCurrentContext(this->context);
if(R_FAILED(rc))
{
FatalGui::openWithResultCode("sysclkIpcGetCurrentContext", rc);
return;
}
}
}
tsl::elm::Element* BaseMenuGui::baseUI()
{
tsl::elm::List* list = new tsl::elm::List();
this->listElement = list;
this->listUI();
return list;
}

View File

@@ -1,183 +0,0 @@
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include "misc_gui.h"
#include "fatal_gui.h"
#include "../format.h"
MiscGui::MiscGui()
{
smInitialize();
this->configList = new SysClkConfigValueList {};
this->chargeInfo = new PsmChargeInfo {};
this->i2cInfo = new I2cInfo {};
sysclkIpcGetIsMariko(&this->isMariko);
}
MiscGui::~MiscGui()
{
delete this->configList;
delete this->chargeInfo;
delete this->i2cInfo;
this->configToggles.clear();
smExit();
}
void MiscGui::addConfigToggle(SysClkConfigValue configVal, const char* altName = nullptr) {
const char* configName = altName ? altName : sysclkFormatConfigValue(configVal, true);
tsl::elm::ToggleListItem* toggle = new tsl::elm::ToggleListItem(configName, this->configList->values[configVal]);
toggle->setStateChangedListener([this, configVal](bool state) {
this->configList->values[configVal] = uint64_t(state);
Result rc = sysclkIpcSetConfigValues(this->configList);
if (R_FAILED(rc))
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
this->lastContextUpdate = armGetSystemTick();
});
this->listElement->addItem(toggle);
this->configToggles[configVal] = toggle;
}
void MiscGui::updateConfigToggles() {
for (const auto& [value, toggle] : this->configToggles) {
if (toggle != nullptr)
toggle->setState(this->configList->values[value]);
}
}
void MiscGui::listUI()
{
// Config list
sysclkIpcGetConfigValues(this->configList);
this->listElement->addItem(new tsl::elm::CategoryHeader("Config"));
addConfigToggle(SysClkConfigValue_AutoCPUBoost, this->isMariko ? nullptr : "Auto CPU Boost (Unsafe)");
addConfigToggle(SysClkConfigValue_SyncReverseNXMode);
addConfigToggle(SysClkConfigValue_GovernorExperimental);
// Charging Current
this->chargingCurrentHeader = new tsl::elm::CategoryHeader("");
this->listElement->addItem(this->chargingCurrentHeader);
constexpr size_t current_steps = CHARGING_CURRENT_MA_LIMIT / 100;
this->chargingCurrentBar = new StepTrackBarIcon("", current_steps + 1);
this->chargingCurrentBar->setProgress(this->configList->values[SysClkConfigValue_ChargingCurrentLimit]);
this->chargingCurrentBar->setValueChangedListener([this](u8 val) {
if (val < 1) {
val = 1;
this->chargingCurrentBar->setProgress(val);
}
if (val > current_steps) {
val = current_steps;
this->chargingCurrentBar->setProgress(val);
}
uint32_t current_ma = val * 100;
this->configList->values[SysClkConfigValue_ChargingCurrentLimit] = current_ma;
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Charging Current: %lu mA (Now: %+d mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], (int)this->i2cInfo->batCurrent);
this->chargingCurrentHeader->setText(chargingCurrentBarDesc);
Result rc = sysclkIpcSetConfigValues(this->configList);
if (R_FAILED(rc))
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
this->lastContextUpdate = armGetSystemTick();
});
this->listElement->addItem(this->chargingCurrentBar);
// Charging Limit
this->chargingLimitHeader = new tsl::elm::CategoryHeader("");
this->listElement->addItem(this->chargingLimitHeader);
this->chargingLimitBar = new StepTrackBarIcon("", 100 + 1);
this->chargingLimitBar->setProgress(this->configList->values[SysClkConfigValue_ChargingLimitPercentage]);
this->chargingLimitBar->setValueChangedListener([this](u8 val) {
if (val < 20) {
val = 20;
this->chargingLimitBar->setProgress(val);
}
this->configList->values[SysClkConfigValue_ChargingLimitPercentage] = val;
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
this->chargingLimitHeader->setText(chargingLimitBarDesc);
this->chargingLimitBar->setIcon(PsmGetBatteryStateIcon(this->chargeInfo));
Result rc = sysclkIpcSetConfigValues(this->configList);
if (R_FAILED(rc))
FatalGui::openWithResultCode("sysclkIpcSetConfigValues", rc);
this->lastContextUpdate = armGetSystemTick();
});
this->listElement->addItem(this->chargingLimitBar);
this->listElement->addItem(new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString("\uE016 Long-term use may render the battery gauge \ninaccurate!", false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR);
}), SMALL_TEXT_SIZE * 2 + 20);
// Temporary toggles
this->listElement->addItem(new tsl::elm::CategoryHeader("Temporary toggles"));
this->chargingDisabledOverrideToggle = new tsl::elm::ToggleListItem("Force Disable Charging", false);
chargingDisabledOverrideToggle->setStateChangedListener([this](bool state) {
Result rc = sysclkIpcSetBatteryChargingDisabledOverride(state);
if (R_FAILED(rc))
FatalGui::openWithResultCode("sysclkIpcSetBatteryChargingDisabledOverride", rc);
this->lastContextUpdate = armGetSystemTick();
});
this->listElement->addItem(this->chargingDisabledOverrideToggle);
this->backlightToggle = new tsl::elm::ToggleListItem("Screen Backlight", false);
backlightToggle->setStateChangedListener([this](bool state) {
LblUpdate(true);
});
this->listElement->addItem(this->backlightToggle);
// Info
this->listElement->addItem(new tsl::elm::CategoryHeader("Info"));
this->listElement->addItem(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
renderer->drawString(this->infoNames, false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR);
renderer->drawString(this->infoVals, false, x + 120, y + 20, SMALL_TEXT_SIZE, VALUE_COLOR);
}), SMALL_TEXT_SIZE * 12 + 20);
}
void MiscGui::refresh() {
BaseMenuGui::refresh();
if (this->context && ++frameCounter >= 60)
{
frameCounter = 0;
sysclkIpcGetConfigValues(this->configList);
updateConfigToggles();
PsmUpdate();
this->chargingLimitBar->setIcon(PsmGetBatteryStateIcon(this->chargeInfo));
bool chargingDisabledOverride;
Result rc = sysclkIpcGetBatteryChargingDisabledOverride(&chargingDisabledOverride);
if (R_FAILED(rc))
FatalGui::openWithResultCode("sysclkIpcGetBatteryChargingDisabledOverride", rc);
this->chargingDisabledOverrideToggle->setState(chargingDisabledOverride);
LblUpdate();
this->backlightToggle->setState(lblstatus);
this->chargingCurrentBar->setProgress(this->configList->values[SysClkConfigValue_ChargingCurrentLimit] / 100);
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Charging Current: %lu mA (Now: %+d mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], (int)this->i2cInfo->batCurrent);
this->chargingCurrentHeader->setText(chargingCurrentBarDesc);
this->chargingLimitBar->setProgress(this->configList->values[SysClkConfigValue_ChargingLimitPercentage]);
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
this->chargingLimitHeader->setText(chargingLimitBarDesc);
I2cGetInfo(this->i2cInfo);
UpdateInfo(this->infoVals, sizeof(this->infoVals));
}
}

View File

@@ -1,182 +0,0 @@
/* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include "../../ipc.h"
#include "base_menu_gui.h"
#include <inttypes.h>
class StepTrackBarIcon : public tsl::elm::StepTrackBar {
public:
StepTrackBarIcon(const char icon[3], size_t numSteps):
tsl::elm::StepTrackBar(icon, numSteps) { }
const char* getIcon() { return this->m_icon; }
void setIcon(const char* icon) { this->m_icon = icon; }
};
class MiscGui : public BaseMenuGui
{
public:
MiscGui();
~MiscGui();
void listUI() override;
void refresh() override;
protected:
typedef struct {
float batCurrent;
u32 cpuVolt;
u32 gpuVolt;
u32 emcVddq;
u32 memVdd2;
} I2cInfo;
void PsmUpdate(uint32_t dispatchId = 0)
{
psmInitialize();
if (dispatchId)
{
serviceDispatch(psmGetServiceSession(), dispatchId);
svcSleepThread(1000);
}
serviceDispatchOut(psmGetServiceSession(), 17, *(this->chargeInfo));
psmGetBatteryChargePercentage(&(this->batteryChargePerc));
psmExit();
}
void I2cGetInfo(I2cInfo* i2cInfo)
{
i2cInitialize();
float batCurrent = I2c_Max17050_GetBatteryCurrent();
i2cInfo->batCurrent = std::abs(batCurrent) < 10. ? 0. : batCurrent;
if (isMariko) {
i2cInfo->cpuVolt = I2c_BuckConverter_GetMvOut(&I2c_Mariko_CPU);
i2cInfo->gpuVolt = I2c_BuckConverter_GetMvOut(&I2c_Mariko_GPU);
i2cInfo->emcVddq = I2c_BuckConverter_GetMvOut(&I2c_Mariko_DRAM_VDDQ);
i2cInfo->memVdd2 = I2c_BuckConverter_GetMvOut(&I2c_Mariko_DRAM_VDD2);
} else {
i2cInfo->cpuVolt = I2c_BuckConverter_GetMvOut(&I2c_Erista_CPU);
i2cInfo->gpuVolt = I2c_BuckConverter_GetMvOut(&I2c_Erista_GPU);
i2cInfo->emcVddq = I2c_BuckConverter_GetMvOut(&I2c_Erista_DRAM);
i2cInfo->memVdd2 = i2cInfo->emcVddq;
}
I2c_Bq24193_GetFastChargeCurrentLimit(reinterpret_cast<u32 *>(&(chargeInfo->ChargeCurrentLimit)));
i2cExit();
}
void UpdateInfo(char* out, size_t outsize)
{
float chargerVoltLimit = (float)chargeInfo->ChargerVoltageLimit / 1000;
float chargerCurrLimit = (float)chargeInfo->ChargerCurrentLimit / 1000;
float chargerOutWatts = chargerVoltLimit * chargerCurrLimit;
char chargeVoltLimit[20] = "";
if (chargeInfo->ChargeVoltageLimit)
snprintf(chargeVoltLimit, sizeof(chargeVoltLimit), ", %umV", chargeInfo->ChargeVoltageLimit);
char chargWattsInfo[30] = "";
if (chargeInfo->ChargerType)
snprintf(chargWattsInfo, sizeof(chargWattsInfo), " %.1fV/%.1fA (%.1fW)", chargerVoltLimit, chargerCurrLimit, chargerOutWatts);
char batCurInfo[30] = "";
snprintf(batCurInfo, sizeof(batCurInfo), "%+.2fmA (%+.2fW)",
i2cInfo->batCurrent, i2cInfo->batCurrent * (float)chargeInfo->VoltageAvg / 1000'000);
snprintf(out, outsize,
"%s%s\n"
"%.3fV %.2f\u00B0C\n"
"+%umA, -%umA\n"
"+%umA%s\n"
"%.2f%%\n"
"%.2f%%\n"
"%s\n"
"%s\n\n"
"%dmV\n"
"%dmV\n"
"Vddq %dmV, Vdd2 %dmV\n"
,
PsmInfoChargerTypeToStr(chargeInfo->ChargerType), chargWattsInfo,
(float)chargeInfo->VoltageAvg / 1000, (float)chargeInfo->BatteryTemperature / 1000,
chargeInfo->InputCurrentLimit, chargeInfo->VBUSCurrentLimit,
chargeInfo->ChargeCurrentLimit, chargeVoltLimit,
(float)chargeInfo->RawBatteryCharge / 1000,
(float)chargeInfo->BatteryAge / 1000,
PsmPowerRoleToStr(chargeInfo->PowerRole),
batCurInfo,
i2cInfo->cpuVolt,
i2cInfo->gpuVolt,
i2cInfo->emcVddq, i2cInfo->memVdd2
);
}
void PsmChargingToggler(bool* enable)
{
if (!PsmIsChargerConnected(this->chargeInfo))
{
*enable = false;
return;
}
PsmUpdate(*enable ? 2 : 3);
*enable = (PsmIsCharging(this->chargeInfo) == *enable);
}
void LblUpdate(bool shouldSwitch = false)
{
lblInitialize();
lblGetBacklightSwitchStatus(&lblstatus);
if (shouldSwitch)
lblstatus ? lblSwitchBacklightOff(0) : lblSwitchBacklightOn(0);
lblExit();
}
bool isMariko = false;
std::map<SysClkConfigValue, tsl::elm::ToggleListItem*> configToggles;
void addConfigToggle(SysClkConfigValue, const char*);
void updateConfigToggles();
tsl::elm::ToggleListItem *chargingDisabledOverrideToggle, *backlightToggle;
tsl::elm::CategoryHeader *chargingCurrentHeader, *chargingLimitHeader;
StepTrackBarIcon *chargingCurrentBar, *chargingLimitBar;
SysClkConfigValueList* configList;
PsmChargeInfo* chargeInfo;
I2cInfo* i2cInfo;
LblBacklightSwitchStatus lblstatus = LblBacklightSwitchStatus_Disabled;
const char* infoNames =
"Charger:\n"\
"Battery:\n"\
"Current Limit:\n"\
"Charging Limit:\n"\
"Raw Charge:\n"\
"Battery Age:\n"\
"Power Role:\n"\
"Current Flow:\n\n"\
"CPU Volt:\n"\
"GPU Volt:\n"\
"DRAM Volt:";
char infoVals[300] = "";
char chargingLimitBarDesc[40] = "";
char chargingCurrentBarDesc[50] = "";
u32 batteryChargePerc = 0;
u8 frameCounter = 60;
};

View File

@@ -1,158 +0,0 @@
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
*
* Copyright (c) CompuPhase, 2008-2017
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $
*/
#ifndef MININI_H
#define MININI_H
#include "minGlue.h"
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
#include <tchar.h>
#define mTCHAR TCHAR
#else
/* force TCHAR to be "char", but only for minIni */
#define mTCHAR char
#endif
#if !defined INI_BUFFERSIZE
#define INI_BUFFERSIZE 512
#endif
#if defined __cplusplus
extern "C" {
#endif
int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
#if defined INI_REAL
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
#endif
#if !defined INI_READONLY
int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
int ini_putsection(const mTCHAR *Section, const mTCHAR **Keys, const mTCHAR **Values, const mTCHAR *Filename);
#if defined INI_REAL
int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
#endif
#endif /* INI_READONLY */
#if !defined INI_NOBROWSE
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData);
int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename);
#endif /* INI_NOBROWSE */
#if defined __cplusplus
}
#endif
#if defined __cplusplus
#if defined __WXWINDOWS__
#include "wxMinIni.h"
#else
#include <string>
/* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */
class minIni
{
public:
minIni(const std::string& filename) : iniFilename(filename)
{ }
bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const
{ return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; }
long getl(const std::string& Section, const std::string& Key, long DefValue=0) const
{ return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
int geti(const std::string& Section, const std::string& Key, int DefValue=0) const
{ return static_cast<int>(this->getl(Section, Key, long(DefValue))); }
std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const
{
char buffer[INI_BUFFERSIZE];
ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getsection(int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getkey(const std::string& Section, int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
#if defined INI_REAL
INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const
{ return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
#endif
#if ! defined INI_READONLY
bool put(const std::string& Section, const std::string& Key, long Value)
{ return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, int Value)
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, bool Value)
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const std::string& Value)
{ return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const char* Value)
{ return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#if defined INI_REAL
bool put(const std::string& Section, const std::string& Key, INI_REAL Value)
{ return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#endif
bool del(const std::string& Section, const std::string& Key)
{ return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; }
bool del(const std::string& Section)
{ return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; }
#endif
#if !defined INI_NOBROWSE
bool browse(INI_CALLBACK Callback, void *UserData) const
{ return ini_browse(Callback, UserData, iniFilename.c_str()) != 0; }
#endif
private:
std::string iniFilename;
};
#endif /* __WXWINDOWS__ */
#endif /* __cplusplus */
#endif /* MININI_H */

View File

@@ -1,384 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include <nxExt.h>
#include "errors.h"
#include "clock_manager.h"
#include "file_utils.h"
#include "clocks.h"
#include "process_management.h"
#include <cstring>
ClockManager* ClockManager::instance = NULL;
ClockManager* ClockManager::GetInstance()
{
return instance;
}
void ClockManager::Exit()
{
if(instance)
{
delete instance;
}
}
void ClockManager::Initialize()
{
if(!instance)
{
instance = new ClockManager();
}
}
ClockManager::ClockManager()
{
this->config = Config::CreateDefault();
this->context = new SysClkContext;
this->context->applicationId = 0;
this->context->profile = SysClkProfile_Handheld;
this->context->enabled = false;
for(unsigned int i = 0; i < SysClkModule_EnumMax; i++)
{
this->context->freqs[i] = 0;
this->context->overrideFreqs[i] = 0;
}
this->context->perfConfId = 0;
this->running = false;
this->lastTempLogNs = 0;
this->lastCsvWriteNs = 0;
this->oc = new SysClkOcExtra;
this->oc->systemCoreBoostCPU = false;
this->oc->batteryChargingDisabledOverride = false;
this->oc->realProfile = SysClkProfile_Handheld;
this->rnxSync = new ReverseNXSync;
this->governor = new Governor();
}
ClockManager::~ClockManager()
{
delete this->governor;
delete this->rnxSync;
delete this->oc;
delete this->context;
delete this->config;
}
void ClockManager::SetRunning(bool running)
{
this->running = running;
}
bool ClockManager::Running()
{
return this->running;
}
uint32_t ClockManager::GetHz(SysClkModule module)
{
/* Temp override setting */
uint32_t hz = this->context->overrideFreqs[module];
/* Per-Game setting */
if (!hz)
hz = this->config->GetAutoClockHz(this->context->applicationId, module, this->context->profile);
/* Global profile */
if (!hz)
hz = this->config->GetAutoClockHz(SYSCLK_GLOBAL_PROFILE_TID, module, this->context->profile);
/* Return pre-set hz */
ReverseNXMode mode;
if (!hz && (mode = this->rnxSync->GetMode()))
{
switch (module)
{
case SysClkModule_CPU:
hz = 1020'000'000;
break;
case SysClkModule_GPU:
hz = (mode == ReverseNX_Docked ||
this->oc->realProfile == SysClkProfile_Docked) ?
768'000'000 : 460'800'000;
break;
case SysClkModule_MEM:
hz = MEM_CLOCK_DOCK;
break;
default:
break;
}
}
if (hz)
{
/* Considering realProfile frequency limit */
hz = Clocks::GetNearestHz(module, this->oc->realProfile, hz);
}
/* Handle CPU Auto Boost, no user-defined hz required */
if (module == SysClkModule_CPU)
{
if (this->oc->systemCoreBoostCPU && hz < Clocks::boostCpuFreq)
return Clocks::boostCpuFreq;
if (!hz)
/* Trigger RefreshContext() and Tick(), resetting default CPU frequency */
return 1020'000'000;
}
return hz;
}
void ClockManager::Tick()
{
std::scoped_lock lock{this->contextMutex};
if (this->RefreshContext() && this->context->enabled)
{
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
uint32_t hz = GetHz((SysClkModule)module);
if (module == SysClkModule_CPU) {
this->governor->SetMinHz(*Clocks::freqRange[module].first, SysClkModule_CPU);
if (Clocks::GetIsMariko() && hz > (uint32_t)1020'000'000) {
this->governor->SetMinHz(1020'000'000, SysClkModule_CPU);
}
}
this->governor->SetMaxHz(hz, (SysClkModule)module);
if (hz && hz != this->context->freqs[module] && !this->governor->IsHandledByGovernor((SysClkModule)module))
{
// Skip setting CPU or GPU clocks in CpuBoostMode if CPU <= boostCPUFreq or GPU >= 76.8MHz
bool skipBoost = apmExtIsBoostMode(this->context->perfConfId) &&
((module == SysClkModule_CPU && hz <= Clocks::boostCpuFreq) || module == SysClkModule_GPU);
if (!skipBoost) {
FileUtils::LogLine("[mgr] %s clock set : %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
Clocks::SetHz((SysClkModule)module, hz);
uint32_t hz_now = Clocks::GetCurrentHz((SysClkModule)module);
if (hz != hz_now)
FileUtils::LogLine("[mgr] Cannot set %s clock to %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
this->context->freqs[module] = hz_now;
}
}
}
}
}
void ClockManager::WaitForNextTick()
{
/* Self-check system core (#3) usage via idleticks at intervals (Not enabled at higher CPU freq or without charger) */
uint64_t tickWaitTimeMs = this->GetConfig()->GetConfigValue(SysClkConfigValue_PollingIntervalMs);
if (this->governor->IsHandledByGovernor(SysClkModule_CPU)) {
svcSleepThread(tickWaitTimeMs * 1000'000ULL);
return;
}
bool boostOK =
this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost) &&
this->context->enabled &&
this->oc->realProfile != SysClkProfile_Handheld &&
this->context->freqs[SysClkModule_CPU] <= Clocks::boostCpuFreq;
if (boostOK) {
uint32_t core3Util = CpuCoreUtil(3, tickWaitTimeMs * 1000'000ULL).Get();
bool lastBoost = this->oc->systemCoreBoostCPU;
this->oc->systemCoreBoostCPU = (core3Util >= BOOST_THRESHOLD);
if (lastBoost && !this->oc->systemCoreBoostCPU)
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
if (!lastBoost && this->oc->systemCoreBoostCPU)
Clocks::SetHz(SysClkModule_CPU, Clocks::boostCpuFreq);
return;
}
if (this->oc->systemCoreBoostCPU) {
this->oc->systemCoreBoostCPU = false;
Clocks::SetHz(SysClkModule_CPU, GetHz(SysClkModule_CPU));
}
svcSleepThread(tickWaitTimeMs * 1000'000ULL);
}
bool ClockManager::RefreshContext()
{
PsmExt::ChargingHandler(this->GetInstance());
bool hasChanged = false;
SysClkProfile realProfile = Clocks::GetCurrentProfile();
if (realProfile != this->oc->realProfile)
{
FileUtils::LogLine("[mgr] Profile change: %s", Clocks::GetProfileName(realProfile, true));
this->oc->realProfile = realProfile;
// Signal that power state has been changed, reset the override
this->SetBatteryChargingDisabledOverride(false);
hasChanged = true;
}
hasChanged = this->config->Refresh();
if (hasChanged) {
this->rnxSync->ToggleSync(this->GetConfig()->GetConfigValue(SysClkConfigValue_SyncReverseNXMode));
bool allowUnsafe = this->GetConfig()->GetConfigValue(SysClkConfigValue_AllowUnsafeFrequencies);
Clocks::SetAllowUnsafe(allowUnsafe);
this->governor->SetAutoCPUBoost(this->GetConfig()->GetConfigValue(SysClkConfigValue_AutoCPUBoost));
this->governor->SetCPUBoostHz(Clocks::GetNearestHz(SysClkModule_CPU, this->oc->realProfile, Clocks::boostCpuFreq));
}
bool enabled = this->GetConfig()->Enabled();
if(enabled != this->context->enabled)
{
this->context->enabled = enabled;
FileUtils::LogLine("[mgr] " TARGET " status: %s", enabled ? "enabled" : "disabled");
hasChanged = true;
}
std::uint64_t applicationId = ProcessManagement::GetCurrentApplicationId();
if (applicationId != this->context->applicationId)
{
FileUtils::LogLine("[mgr] TitleID change: %016lX", applicationId);
this->context->applicationId = applicationId;
hasChanged = true;
/* Clear ReverseNX state */
this->rnxSync->Reset(applicationId);
}
SysClkOcGovernorConfig governorConfig = SysClkOcGovernorConfig_AllDisabled;
if (this->GetConfig()->GetConfigValue(SysClkConfigValue_GovernorExperimental)) {
auto governorHandheldOnly = this->GetConfig()->GetConfigValue(SysClkConfigValue_GovernorHandheldOnly);
governorConfig = SysClkOcGovernorConfig_Default;
SysClkOcGovernorConfig governorConfigTitle = this->GetConfig()->GetTitleGovernorConfig(applicationId);
if (governorConfig != governorConfigTitle)
governorConfig = governorConfigTitle;
// Set governor config to disabled if Handheld Only is true
if (governorHandheldOnly && (realProfile != SysClkProfile_Handheld))
governorConfig = SysClkOcGovernorConfig_AllDisabled;
}
this->governor->SetConfig(governorConfig);
/* Update PerformanceConfigurationId */
{
uint32_t confId = 0;
Result rc = 0;
rc = apmExtGetCurrentPerformanceConfiguration(&confId);
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
if (this->context->perfConfId != confId)
{
this->context->perfConfId = confId;
this->governor->SetPerfConf(confId);
hasChanged = true;
}
}
{
SysClkProfile current = this->context->profile;
SysClkProfile expected = this->rnxSync->GetProfile(this->oc->realProfile);
this->context->profile = expected;
if (current != expected)
hasChanged = true;
}
// let ptm module handle boost clocks rather than resetting
if (hasChanged && !apmExtIsBoostMode(this->context->perfConfId)) {
Clocks::ResetToStock();
}
std::uint32_t hz = 0;
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
hz = Clocks::GetCurrentHz((SysClkModule)module);
if (hz != 0 && hz != this->context->freqs[module])
{
this->context->freqs[module] = hz;
if (!this->governor->IsHandledByGovernor((SysClkModule)module)) {
FileUtils::LogLine("[mgr] %s clock change: %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
hasChanged = true;
}
}
hz = this->GetConfig()->GetOverrideHz((SysClkModule)module);
if (hz != this->context->overrideFreqs[module])
{
if(hz)
{
FileUtils::LogLine("[mgr] %s override change: %u.%u MHz", Clocks::GetModuleName((SysClkModule)module, true), hz/1000000, hz/100000 - hz/1000000*10);
}
else
{
FileUtils::LogLine("[mgr] %s override disabled", Clocks::GetModuleName((SysClkModule)module, true));
Clocks::ResetToStock(module);
}
this->context->overrideFreqs[module] = hz;
hasChanged = true;
}
}
// temperatures do not and should not force a refresh, hasChanged untouched
std::uint32_t millis = 0;
std::uint64_t ns = armTicksToNs(armGetSystemTick());
std::uint64_t tempLogInterval = this->GetConfig()->GetConfigValue(SysClkConfigValue_TempLogIntervalMs) * 1000000ULL;
bool shouldLogTemp = tempLogInterval && ((ns - this->lastTempLogNs) > tempLogInterval);
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++)
{
millis = Clocks::GetTemperatureMilli((SysClkThermalSensor)sensor);
if(shouldLogTemp)
{
FileUtils::LogLine("[mgr] %s temp: %u.%u °C", Clocks::GetThermalSensorName((SysClkThermalSensor)sensor, true), millis/1000, (millis - millis/1000*1000) / 100);
}
this->context->temps[sensor] = millis;
}
if(shouldLogTemp)
{
this->lastTempLogNs = ns;
}
std::uint64_t csvWriteInterval = this->GetConfig()->GetConfigValue(SysClkConfigValue_CsvWriteIntervalMs) * 1000000ULL;
if(csvWriteInterval && ((ns - this->lastCsvWriteNs) > csvWriteInterval))
{
FileUtils::WriteContextToCsv(this->context);
this->lastCsvWriteNs = ns;
}
return hasChanged;
}
void ClockManager::SetRNXRTMode(ReverseNXMode mode) {
this->rnxSync->SetRTMode(mode);
}
SysClkContext ClockManager::GetCurrentContext()
{
std::scoped_lock lock{this->contextMutex};
return *this->context;
}
Config* ClockManager::GetConfig()
{
return this->config;
}
bool ClockManager::GetBatteryChargingDisabledOverride() {
return this->oc->batteryChargingDisabledOverride;
}
Result ClockManager::SetBatteryChargingDisabledOverride(bool toggle_true) {
this->oc->batteryChargingDisabledOverride = toggle_true;
return 0;
}

View File

@@ -1,452 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include <cstring>
#include <nxExt.h>
#include "clocks.h"
#include "errors.h"
#include "file_utils.h"
Result Clocks::GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max)
{
switch (module) {
case SysClkModule_CPU:
case SysClkModule_GPU:
case SysClkModule_MEM:
*min = freqRange[module].min;
*max = freqRange[module].max[profile];
break;
default:
ERROR_THROW("No such PcvModule: %u", module);
}
if (!*min || !*max || *max < *min || size_t(*max - *min + 1) > sizeof(SysClkFrequencyTable))
return SYSCLK_ERROR(InternalFrequencyTableError);
return 0;
}
void Clocks::UpdateFreqRange() {
freqRange[SysClkModule_MEM].InitDefault(SysClkModule_MEM);
if (isMariko) {
freqRange[SysClkModule_MEM].first = freqRange[SysClkModule_MEM].min = freqRange[SysClkModule_MEM].FindFreq(1600'000'000);
}
freqRange[SysClkModule_CPU].InitDefault(SysClkModule_CPU);
uint32_t* cpu_max_freq = freqRange[SysClkModule_CPU].last;
uint32_t CPU_SAFE_MAX = isMariko ? 1963'500'000 : 1785'000'000;
uint32_t CPU_UNSAFE_MAX[SysClkProfile_EnumMax];
for (auto &m : CPU_UNSAFE_MAX) {
m = *cpu_max_freq;
}
if (!isMariko) {
CPU_UNSAFE_MAX[SysClkProfile_Handheld] = 1785'000'000;
}
freqRange[SysClkModule_GPU].InitDefault(SysClkModule_GPU);
uint32_t* gpu_max_freq = freqRange[SysClkModule_GPU].last;
uint32_t GPU_SAFE_MAX[SysClkProfile_EnumMax];
if (isMariko) {
for (auto &m : GPU_SAFE_MAX) {
m = 998'400'000;
}
} else {
GPU_SAFE_MAX[SysClkProfile_Handheld] = \
GPU_SAFE_MAX[SysClkProfile_HandheldCharging] = 460'800'000;
GPU_SAFE_MAX[SysClkProfile_HandheldChargingUSB] = 768'000'000;
GPU_SAFE_MAX[SysClkProfile_HandheldChargingOfficial] = \
GPU_SAFE_MAX[SysClkProfile_Docked] = 921'600'000;
};
uint32_t GPU_UNSAFE_MAX[SysClkProfile_EnumMax];
for (auto &m : GPU_UNSAFE_MAX) {
m = *gpu_max_freq;
}
if (isMariko) {
GPU_UNSAFE_MAX[SysClkProfile_Handheld] = 998'400'000;
} else {
memcpy(GPU_UNSAFE_MAX, GPU_SAFE_MAX, sizeof(GPU_UNSAFE_MAX));
GPU_UNSAFE_MAX[SysClkProfile_HandheldChargingOfficial] = \
GPU_UNSAFE_MAX[SysClkProfile_Docked] = *gpu_max_freq;
}
const bool use_unsafe = allowUnsafe;
for (int i = 0; i < int(SysClkProfile_EnumMax); i++) {
freqRange[SysClkModule_CPU].max[i] = std::min(cpu_max_freq,
freqRange[SysClkModule_CPU].FindFreq(use_unsafe ? CPU_UNSAFE_MAX[i] : CPU_SAFE_MAX, SysClkProfile(i)));
freqRange[SysClkModule_GPU].max[i] = std::min(gpu_max_freq,
freqRange[SysClkModule_GPU].FindFreq(use_unsafe ? GPU_UNSAFE_MAX[i] : GPU_SAFE_MAX[i], SysClkProfile(i)));
}
}
Result Clocks::GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table) {
uint32_t* min = NULL;
uint32_t* max = NULL;
if (Result res = GetRange(module, profile, &min, &max)) {
return res;
}
memset(out_table, 0, sizeof(SysClkFrequencyTable));
uint32_t* p = min;
size_t idx = 0;
while(p <= max)
out_table->freq[idx++] = *p++;
return 0;
}
void Clocks::SetAllowUnsafe(bool allow) {
if (allowUnsafe != allow) {
allowUnsafe = allow;
UpdateFreqRange();
}
};
void Clocks::Initialize()
{
Result rc = 0;
u64 hardware_type = 0;
rc = splInitialize();
ASSERT_RESULT_OK(rc, "splInitialize");
rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type);
ASSERT_RESULT_OK(rc, "splGetConfig");
splExit();
switch (hardware_type) {
case 0: // Icosa
case 1: // Copper
isMariko = false;
break;
case 2: // Hoag
case 3: // Iowa
case 4: // Calcio
case 5: // Aula
isMariko = true;
break;
default:
ERROR_THROW("Unknown hardware type: 0x%X!", hardware_type);
return;
}
if(hosversionAtLeast(8,0,0))
{
rc = clkrstInitialize();
ASSERT_RESULT_OK(rc, "pcvInitialize");
}
else
{
rc = pcvInitialize();
ASSERT_RESULT_OK(rc, "pcvInitialize");
}
rc = apmExtInitialize();
ASSERT_RESULT_OK(rc, "apmExtInitialize");
rc = psmInitialize();
ASSERT_RESULT_OK(rc, "psmInitialize");
rc = tsInitialize();
ASSERT_RESULT_OK(rc, "tsInitialize");
if(hosversionAtLeast(5,0,0))
{
rc = tcInitialize();
ASSERT_RESULT_OK(rc, "tcInitialize");
}
FileUtils::ParseLoaderKip();
UpdateFreqRange();
}
void Clocks::Exit()
{
if(hosversionAtLeast(8,0,0))
{
pcvExit();
}
else
{
clkrstExit();
}
apmExtExit();
psmExit();
tsExit();
if(hosversionAtLeast(5,0,0))
{
tcExit();
}
}
const char* Clocks::GetModuleName(SysClkModule module, bool pretty)
{
const char* result = sysclkFormatModule(module, pretty);
if(!result)
{
ERROR_THROW("No such SysClkModule: %u", module);
}
return result;
}
const char* Clocks::GetProfileName(SysClkProfile profile, bool pretty)
{
const char* result = sysclkFormatProfile(profile, pretty);
if(!result)
{
ERROR_THROW("No such SysClkProfile: %u", profile);
}
return result;
}
const char* Clocks::GetThermalSensorName(SysClkThermalSensor sensor, bool pretty)
{
const char* result = sysclkFormatThermalSensor(sensor, pretty);
if(!result)
{
ERROR_THROW("No such SysClkThermalSensor: %u", sensor);
}
return result;
}
PcvModule Clocks::GetPcvModule(SysClkModule sysclkModule)
{
switch(sysclkModule)
{
case SysClkModule_CPU:
return PcvModule_CpuBus;
case SysClkModule_GPU:
return PcvModule_GPU;
case SysClkModule_MEM:
return PcvModule_EMC;
default:
ERROR_THROW("No such SysClkModule: %u", sysclkModule);
}
return (PcvModule)0;
}
PcvModuleId Clocks::GetPcvModuleId(SysClkModule sysclkModule)
{
PcvModuleId pcvModuleId;
Result rc = pcvGetModuleId(&pcvModuleId, GetPcvModule(sysclkModule));
ASSERT_RESULT_OK(rc, "pcvGetModuleId");
return pcvModuleId;
}
SysClkApmConfiguration* Clocks::GetEmbeddedApmConfig(uint32_t confId)
{
SysClkApmConfiguration* apmConfiguration = NULL;
for(size_t i = 0; sysclk_g_apm_configurations[i].id; i++)
{
if(sysclk_g_apm_configurations[i].id == confId)
{
apmConfiguration = &sysclk_g_apm_configurations[i];
break;
}
}
if(!apmConfiguration)
{
ERROR_THROW("Unknown apm configuration: %x", confId);
}
return apmConfiguration;
}
uint32_t Clocks::GetStockClock(SysClkApmConfiguration* apm, SysClkModule module)
{
switch (module) {
case SysClkModule_CPU:
return apm->cpu_hz;
case SysClkModule_GPU:
return apm->gpu_hz;
case SysClkModule_MEM:
return GetIsMariko() ? MEM_CLOCK_MARIKO_MIN : apm->mem_hz;
default:
ERROR_THROW("Unknown SysClkModule: %x", module);
return 0;
}
}
void Clocks::ResetToStock(unsigned int module)
{
if(hosversionAtLeast(9,0,0))
{
std::uint32_t confId = 0;
Result rc = apmExtGetCurrentPerformanceConfiguration(&confId);
ASSERT_RESULT_OK(rc, "apmExtGetCurrentPerformanceConfiguration");
SysClkApmConfiguration* apmConfiguration = GetEmbeddedApmConfig(confId);
if (module == SysClkModule_EnumMax || module == SysClkModule_CPU)
{
Clocks::SetHz(SysClkModule_CPU, GetStockClock(apmConfiguration, SysClkModule_CPU));
}
if (module == SysClkModule_EnumMax || module == SysClkModule_GPU)
{
Clocks::SetHz(SysClkModule_GPU, GetStockClock(apmConfiguration, SysClkModule_GPU));
}
if (module == SysClkModule_EnumMax || module == SysClkModule_MEM)
{
Clocks::SetHz(SysClkModule_MEM, GetStockClock(apmConfiguration, SysClkModule_MEM));
}
}
else
{
Result rc = 0;
std::uint32_t mode = 0;
rc = apmExtGetPerformanceMode(&mode);
ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode");
rc = apmExtSysRequestPerformanceMode(mode);
ASSERT_RESULT_OK(rc, "apmExtSysRequestPerformanceMode");
}
}
SysClkProfile Clocks::GetCurrentProfile()
{
std::uint32_t mode = 0;
Result rc = apmExtGetPerformanceMode(&mode);
ASSERT_RESULT_OK(rc, "apmExtGetPerformanceMode");
if(mode)
{
return SysClkProfile_Docked;
}
PsmChargerType chargerType;
rc = psmGetChargerType(&chargerType);
ASSERT_RESULT_OK(rc, "psmGetChargerType");
switch(chargerType)
{
case PsmChargerType_EnoughPower:
return SysClkProfile_HandheldChargingOfficial;
case PsmChargerType_LowPower:
case PsmChargerType_NotSupported:
return SysClkProfile_HandheldChargingUSB;
default:
return SysClkProfile_Handheld;
}
}
void Clocks::SetHz(SysClkModule module, std::uint32_t hz)
{
Result rc = 0;
if(hosversionAtLeast(8,0,0))
{
ClkrstSession session = {0};
rc = clkrstOpenSession(&session, Clocks::GetPcvModuleId(module), 3);
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
rc = clkrstSetClockRate(&session, hz);
ASSERT_RESULT_OK(rc, "clkrstSetClockRate");
clkrstCloseSession(&session);
}
else
{
rc = pcvSetClockRate(Clocks::GetPcvModule(module), hz);
ASSERT_RESULT_OK(rc, "pcvSetClockRate");
}
}
std::uint32_t Clocks::GetCurrentHz(SysClkModule module)
{
Result rc = 0;
std::uint32_t hz = 0;
if(hosversionAtLeast(8,0,0))
{
ClkrstSession session = {0};
rc = clkrstOpenSession(&session, Clocks::GetPcvModuleId(module), 3);
ASSERT_RESULT_OK(rc, "clkrstOpenSession");
rc = clkrstGetClockRate(&session, &hz);
ASSERT_RESULT_OK(rc, "clkrstGetClockRate");
clkrstCloseSession(&session);
}
else
{
rc = pcvGetClockRate(Clocks::GetPcvModule(module), &hz);
ASSERT_RESULT_OK(rc, "pcvGetClockRate");
}
return hz;
}
std::uint32_t Clocks::GetNearestHz(SysClkModule module, SysClkProfile profile, std::uint32_t inHz)
{
uint32_t *min = nullptr, *max = nullptr;
if (GetRange(module, profile, &min, &max))
ERROR_THROW("table lookup failed for SysClkModule: %u", module);
return *GetNearestHzPtr(min, max, inHz);
}
std::int32_t Clocks::GetTsTemperatureMilli(TsLocation location)
{
Result rc;
std::int32_t millis = 0;
if(hosversionAtLeast(14,0,0))
{
rc = tsGetTemperature(location, &millis);
ASSERT_RESULT_OK(rc, "tsGetTemperature(%u)", location);
millis *= 1000;
}
else
{
rc = tsGetTemperatureMilliC(location, &millis);
ASSERT_RESULT_OK(rc, "tsGetTemperatureMilliC(%u)", location);
}
return millis;
}
std::uint32_t Clocks::GetTemperatureMilli(SysClkThermalSensor sensor)
{
std::int32_t millis = 0;
if(sensor == SysClkThermalSensor_SOC)
{
millis = GetTsTemperatureMilli(TsLocation_External);
}
else if(sensor == SysClkThermalSensor_PCB)
{
millis = GetTsTemperatureMilli(TsLocation_Internal);
}
else if(sensor == SysClkThermalSensor_Skin)
{
if(hosversionAtLeast(5,0,0))
{
Result rc = tcGetSkinTemperatureMilliC(&millis);
ASSERT_RESULT_OK(rc, "tcGetSkinTemperatureMilliC");
}
}
else
{
ERROR_THROW("No such SysClkThermalSensor: %u", sensor);
}
return std::max(0, millis);
}

View File

@@ -1,106 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <cstdint>
#include <switch.h>
#include <sysclk.h>
#define MAX_MEM_CLOCK 1862'400'000
#define MEM_CLOCK_MARIKO_MIN 1600'000'000
#define MEM_CLOCK_DOCK 1600'000'000
#define BOOST_THRESHOLD 95'0
class Clocks
{
public:
static inline uint32_t boostCpuFreq = 1785000000;
static inline uint32_t maxMemFreq = 0;
static inline uint32_t* GetNearestHzPtr(uint32_t* hzListStart, uint32_t* hzListEnd, uint32_t freq) {
uint32_t* p = hzListStart;
while (p < hzListEnd) {
if (freq <= *p)
return p;
p++;
}
return hzListEnd;
}
static inline SysClkFrequencyTable freqTable[SysClkModule_EnumMax] = {
{}, // CPU
{}, // GPU
{ // MEM
665600000,
800000000,
1065600000,
1331200000,
1600000000,
},
};
typedef struct FreqRange {
uint32_t* first;
uint32_t* last;
uint32_t* min;
uint32_t* max[SysClkProfile_EnumMax];
void InitDefault(SysClkModule module) {
SysClkFrequencyTable* table_head = &freqTable[module];
uint32_t* p = this->first = this->min = &table_head->freq[0];
// Get pointer to last value
for (int i = 0; i < FREQ_TABLE_MAX_ENTRY_COUNT; i++) {
if (!*(++p)) {
--p;
break;
}
}
this->last = p;
for (auto& m: this->max) {
m = p;
}
};
uint32_t* FindFreq(uint32_t freq, SysClkProfile profile = SysClkProfile_Docked) {
return GetNearestHzPtr(this->min, this->max[profile], freq);
};
} FreqRange;
static inline FreqRange freqRange[SysClkModule_EnumMax];
static void UpdateFreqRange();
static Result GetRange(SysClkModule module, SysClkProfile profile, uint32_t** min, uint32_t** max);
static Result GetTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table);
static void SetAllowUnsafe(bool allow);
static bool GetIsMariko() { return isMariko; };
static void Exit();
static void Initialize();
static SysClkApmConfiguration* GetEmbeddedApmConfig(uint32_t confId);
static uint32_t GetStockClock(SysClkApmConfiguration* apm, SysClkModule module);
static void ResetToStock(unsigned int module = SysClkModule_EnumMax);
static SysClkProfile GetCurrentProfile();
static std::uint32_t GetCurrentHz(SysClkModule module);
static void SetHz(SysClkModule module, std::uint32_t hz);
static const char* GetProfileName(SysClkProfile profile, bool pretty);
static const char* GetModuleName(SysClkModule module, bool pretty);
static const char* GetThermalSensorName(SysClkThermalSensor sensor, bool pretty);
static std::uint32_t GetNearestHz(SysClkModule module, SysClkProfile profile, std::uint32_t inHz);
static std::uint32_t GetTemperatureMilli(SysClkThermalSensor sensor);
protected:
static inline bool allowUnsafe;
static inline bool isMariko;
static std::int32_t GetTsTemperatureMilli(TsLocation location);
static PcvModule GetPcvModule(SysClkModule sysclkModule);
static PcvModuleId GetPcvModuleId(SysClkModule sysclkModule);
static std::uint32_t GetMaxAllowedHz(SysClkModule module, SysClkProfile profile);
};

View File

@@ -1,404 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#include "file_utils.h"
#include "clocks.h"
#include <dirent.h>
#include <nxExt.h>
#include "errors.h"
static LockableMutex g_log_mutex;
static LockableMutex g_csv_mutex;
static std::atomic_bool g_has_initialized = false;
static bool g_log_enabled = false;
static std::uint64_t g_last_flag_check = 0;
extern "C" void __libnx_init_time(void);
static void _FileUtils_InitializeThreadFunc(void *args)
{
FileUtils::Initialize();
}
bool FileUtils::IsInitialized()
{
return g_has_initialized;
}
void FileUtils::LogLine(const char *format, ...)
{
va_list args;
va_start(args, format);
if (g_has_initialized)
{
g_log_mutex.Lock();
FileUtils::RefreshFlags(false);
if(g_log_enabled)
{
FILE *file = fopen(FILE_LOG_FILE_PATH, "a");
if (file)
{
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
struct tm* nowTm = localtime(&now.tv_sec);
fprintf(file, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld] ", nowTm->tm_year+1900, nowTm->tm_mon+1, nowTm->tm_mday, nowTm->tm_hour, nowTm->tm_min, nowTm->tm_sec, now.tv_nsec / 1000000UL);
vfprintf(file, format, args);
fprintf(file, "\n");
fclose(file);
}
}
g_log_mutex.Unlock();
}
va_end(args);
}
void FileUtils::WriteContextToCsv(const SysClkContext* context)
{
std::scoped_lock lock{g_csv_mutex};
FILE *file = fopen(FILE_CONTEXT_CSV_PATH, "a");
if (file)
{
// Print header
if(!ftell(file))
{
fprintf(file, "timestamp,profile,app_tid");
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
fprintf(file, ",%s_hz", sysclkFormatModule((SysClkModule)module, false));
}
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++)
{
fprintf(file, ",%s_milliC", sysclkFormatThermalSensor((SysClkThermalSensor)sensor, false));
}
fprintf(file, "\n");
}
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
fprintf(file, "%ld%03ld,%s,%016lx", now.tv_sec, now.tv_nsec / 1000000UL, sysclkFormatProfile(context->profile, false), context->applicationId);
for (unsigned int module = 0; module < SysClkModule_EnumMax; module++)
{
fprintf(file, ",%d", context->freqs[module]);
}
for (unsigned int sensor = 0; sensor < SysClkThermalSensor_EnumMax; sensor++)
{
fprintf(file, ",%d", context->temps[sensor]);
}
fprintf(file, "\n");
fclose(file);
}
}
void FileUtils::RefreshFlags(bool force)
{
std::uint64_t now = armTicksToNs(armGetSystemTick());
if(!force && (now - g_last_flag_check) < FILE_FLAG_CHECK_INTERVAL_NS)
{
return;
}
FILE *file = fopen(FILE_LOG_FLAG_PATH, "r");
if (file)
{
g_log_enabled = true;
fclose(file);
} else {
g_log_enabled = false;
}
g_last_flag_check = now;
}
void FileUtils::InitializeAsync()
{
Thread initThread = {0};
threadCreate(&initThread, _FileUtils_InitializeThreadFunc, NULL, NULL, 0x2000, 0x15, 0);
threadStart(&initThread);
}
Result FileUtils::Initialize()
{
Result rc = 0;
if (R_SUCCEEDED(rc))
{
rc = timeInitialize();
}
__libnx_init_time();
timeExit();
if (R_SUCCEEDED(rc))
{
rc = fsInitialize();
}
if (R_SUCCEEDED(rc))
{
rc = fsdevMountSdmc();
}
if (R_SUCCEEDED(rc))
{
FileUtils::RefreshFlags(true);
g_has_initialized = true;
FileUtils::LogLine("=== " TARGET " " TARGET_VERSION " ===");
}
return rc;
}
void FileUtils::Exit()
{
if (!g_has_initialized)
{
return;
}
g_has_initialized = false;
g_log_enabled = false;
fsdevUnmountAll();
fsExit();
}
void FileUtils::ParseLoaderKip() {
const char* dirs[] = { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" };
char* full_path = new char[0x200];
SCOPE_EXIT { delete[] full_path; };
for (auto const& dir : dirs) {
struct dirent *entry = NULL;
DIR *dp = opendir(dir);
if (!dp)
continue;
SCOPE_EXIT { closedir(dp); };
while ((entry = readdir(dp))) {
if (entry->d_type != DT_REG)
continue;
snprintf(full_path, 0x200, "%s%s", dir, entry->d_name);
FILE* fp = fopen(full_path, "r");
if (!fp)
continue;
fseek(fp, 0, SEEK_END);
long res = ftell(fp);
fclose(fp);
if (res == -1)
continue;
size_t filesize = (size_t)res;
if (filesize < 0x1000 || filesize > 512 * 1024)
continue;
const char kip_ext[] = {'.', 'k', 'i', 'p'};
size_t file_name_len = strnlen(reinterpret_cast<const char*>(&entry->d_name), 256);
const char* file_ext = &entry->d_name[file_name_len - sizeof(kip_ext)];
if (strncasecmp((const char*)kip_ext, file_ext, sizeof(kip_ext)))
continue;
if (R_SUCCEEDED(CustParser(full_path, filesize))) {
LogLine("Parsed cust config from \"%s\"", full_path);
return;
}
}
}
ERROR_THROW("Cannot locate loader.kip in /, /atmosphere/, /atmosphere/kips/ and /bootloader/");
}
Result FileUtils::CustParser(const char* filepath, size_t filesize) {
enum ParseError {
ParseError_Success = 0,
ParseError_OpenReadFailed,
ParseError_WrongKipMagic,
ParseError_CustNotFound,
ParseError_WrongCustRev,
};
FILE* fp = fopen(filepath, "r");
if (!fp)
return ParseError_OpenReadFailed;
SCOPE_EXIT { fclose(fp); };
constexpr uint8_t KIP_MAGIC[] = {'K', 'I', 'P', '1', 'L', 'o', 'a', 'd', 'e', 'r'};
constexpr size_t BLOCK_SIZE = 0x1000;
char* tmp_block = new char[BLOCK_SIZE];
SCOPE_EXIT { delete[] tmp_block; };
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC)))
return ParseError_WrongKipMagic;
CustTable table {};
fpos_t cust_pos = 0;
long block_pos = 0;
while ((block_pos = ftell(fp)) >= 0 && (size_t)block_pos < filesize) {
for (size_t i = 0; i < BLOCK_SIZE; i += sizeof(table.cust)) {
if (memcmp(table.cust, &tmp_block[i], sizeof(table.cust)))
continue;
fgetpos(fp, &cust_pos);
cust_pos = cust_pos + i - BLOCK_SIZE;
goto found;
}
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
}
found:
if (!cust_pos)
return ParseError_CustNotFound;
memset(reinterpret_cast<void*>(&table), 0, sizeof(CustTable));
fsetpos(fp, &cust_pos);
if (!fread(reinterpret_cast<char*>(&table), 1, sizeof(CustTable), fp))
return ParseError_OpenReadFailed;
if (table.custRev != CUST_REV)
return ParseError_WrongCustRev;
if (table.commonCpuBoostClock)
Clocks::boostCpuFreq = table.commonCpuBoostClock * 1000;
CustomizeCpuDvfsTable* cpu_dvfs_table = nullptr;
CustomizeGpuDvfsTable* gpu_dvfs_table = nullptr;
if (Clocks::GetIsMariko()) {
if (table.marikoEmcMaxClock)
Clocks::maxMemFreq = table.marikoEmcMaxClock * 1000;
if (table.marikoEmcVddqVolt && table.marikoEmcVddqVolt >= 550'000 && table.marikoEmcVddqVolt <= 650'000) {
u32 mvolt = table.marikoEmcVddqVolt / 1000;
Result res = I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDDQ, mvolt);
LogLine("Set EMC Vddq volt to %u mV: %s", mvolt, R_FAILED(res) ? "Failed" : "OK");
}
if (table.commonEmcMemVolt && table.commonEmcMemVolt >= 1100'000 && table.commonEmcMemVolt <= 1250'000) {
u32 mvolt = table.commonEmcMemVolt / 1000;
Result res = I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM_VDD2, mvolt);
LogLine("Set MEM Vdd2 volt to %u mV: %s", mvolt, R_FAILED(res) ? "Failed" : "OK");
}
cpu_dvfs_table = table.marikoCpuUV ? &table.marikoCpuDvfsTableSLT : &table.marikoCpuDvfsTable;
switch (table.marikoGpuUV) {
case 0:
gpu_dvfs_table = &table.marikoGpuDvfsTable;
break;
case 1:
gpu_dvfs_table = &table.marikoGpuDvfsTableSLT;
break;
case 2:
gpu_dvfs_table = &table.marikoGpuDvfsTableHiOPT;
break;
default:
gpu_dvfs_table = &table.marikoGpuDvfsTable;
break;
}
} else {
if (table.eristaEmcMaxClock)
Clocks::maxMemFreq = table.eristaEmcMaxClock * 1000;
cpu_dvfs_table = &table.eristaCpuDvfsTable;
gpu_dvfs_table = &table.eristaGpuDvfsTable;
}
// Fill Clocks::freqTable
cvb_entry_t* cpu_dvfs_entry = reinterpret_cast<cvb_entry_t *>(cpu_dvfs_table);
for (size_t i = 0, j = 0; i < FREQ_TABLE_MAX_ENTRY_COUNT; i++) {
// Skip CPU frequencies < 408 MHz that are not usable
uint32_t freq = cpu_dvfs_entry[i].freq;
if (freq < 408'000)
continue;
Clocks::freqTable[SysClkModule_CPU].freq[j++] = freq * 1000;
}
cvb_entry_t* gpu_dvfs_entry = reinterpret_cast<cvb_entry_t *>(gpu_dvfs_table);
for (size_t i = 0; i < FREQ_TABLE_MAX_ENTRY_COUNT; i++) {
Clocks::freqTable[SysClkModule_GPU].freq[i] = gpu_dvfs_entry[i].freq * 1000;
}
// Appending maximum mem freq to freqTable
uint32_t* mem_entry = &Clocks::freqTable[SysClkModule_MEM].freq[0];
while (*(++mem_entry));
*mem_entry = Clocks::maxMemFreq;
return ParseError_Success;
}
Result FileUtils::mkdir_p(const char* dirpath) {
// https://gist.github.com/JonathonReinhart/8c0d90191c38af2dcadb102c4e202950
auto mkdir_wrapper = [](char* path) {
errno = 0;
size_t len = strnlen(path, 0x1000);
bool isCWDir = (len == 0) || (len == 1 && (path[0] == '.' || path[0] == '/'));
if (isCWDir)
return 0;
if (R_SUCCEEDED(mkdir(path, S_IRWXU)))
return 0;
struct stat st;
if (errno == EEXIST &&
R_SUCCEEDED(stat(path, &st)) &&
S_ISDIR(st.st_mode)) {
errno = 0;
return 0;
}
errno = ENOTDIR;
return -1;
};
errno = 0;
Result res = 0;
size_t path_len = strnlen(dirpath, 0x1000);
char* path_copy = new char[path_len];
SCOPE_EXIT { delete[] path_copy; };
memcpy(path_copy, dirpath, path_len);
char* p = path_copy;
while (*p) {
if (*p == '/') {
// Temporarily truncate
*p = '\0';
if (R_FAILED(mkdir_wrapper(path_copy))) {
res = -1;
return res;
}
*p = '/';
}
p++;
}
if (R_FAILED(mkdir_wrapper(path_copy)))
res = -1;
return res;
}

View File

@@ -1,97 +0,0 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <switch.h>
#include <time.h>
#include <vector>
#include <string>
#include <cstring>
#include <atomic>
#include <cstdarg>
#include <sysclk.h>
#define FILE_CONFIG_DIR "/config/sys-clk-oc"
#define FILE_FLAG_CHECK_INTERVAL_NS 5000000000ULL
#define FILE_CONTEXT_CSV_PATH FILE_CONFIG_DIR "/context.csv"
#define FILE_LOG_FLAG_PATH FILE_CONFIG_DIR "/log.flag"
#define FILE_LOG_FILE_PATH FILE_CONFIG_DIR "/log.txt"
typedef struct cvb_coefficients {
s32 c0 = 0;
s32 c1 = 0;
s32 c2 = 0;
s32 c3 = 0;
s32 c4 = 0;
s32 c5 = 0;
} cvb_coefficients;
typedef struct cvb_entry_t {
u64 freq;
cvb_coefficients cvb_dfll_param;
cvb_coefficients cvb_pll_param;
} cvb_entry_t;
static_assert(sizeof(cvb_entry_t) == 0x38);
using CustomizeCpuDvfsTable = cvb_entry_t[FREQ_TABLE_MAX_ENTRY_COUNT];
using CustomizeGpuDvfsTable = cvb_entry_t[FREQ_TABLE_MAX_ENTRY_COUNT];
constexpr uint32_t CUST_REV = 10;
typedef struct CustTable {
u8 cust[4] = {'C', 'U', 'S', 'T'};
u32 custRev;
u32 mtcConf;
u32 commonCpuBoostClock;
u32 commonEmcMemVolt;
u32 eristaCpuMaxVolt;
u32 eristaEmcMaxClock;
u32 marikoCpuMaxVolt;
u32 marikoEmcMaxClock;
u32 marikoEmcVddqVolt;
u32 marikoCpuUV;
u32 marikoGpuUV;
u32 marikoEmcDvbShift;
u32 ramTimingPresetOne;
u32 ramTimingPresetTwo;
u32 ramTimingPresetThree;
u32 ramTimingPresetFour;
u32 ramTimingPresetFive;
u32 ramTimingPresetSix;
u32 ramTimingPresetSeven;
u32 marikoGpuVoltArray[17];
CustomizeCpuDvfsTable eristaCpuDvfsTable;
CustomizeCpuDvfsTable marikoCpuDvfsTable;
CustomizeCpuDvfsTable marikoCpuDvfsTableSLT;
CustomizeGpuDvfsTable eristaGpuDvfsTable;
CustomizeGpuDvfsTable marikoGpuDvfsTable;
CustomizeGpuDvfsTable marikoGpuDvfsTableSLT;
CustomizeGpuDvfsTable marikoGpuDvfsTableHiOPT;
//void* eristaMtcTable;
//void* marikoMtcTable;
} CustTable;
//static_assert(sizeof(CustTable) == sizeof(u8) * 4 + sizeof(u32) * 9 + sizeof(CustomizeCpuDvfsTable) * 4 + sizeof(void*) * 2);
//static_assert(sizeof(CustTable) == 7000);
class FileUtils
{
public:
static void Exit();
static Result Initialize();
static bool IsInitialized();
static void InitializeAsync();
static void LogLine(const char *format, ...);
static void WriteContextToCsv(const SysClkContext* context);
static void ParseLoaderKip();
static Result mkdir_p(const char* dirpath);
protected:
static void RefreshFlags(bool force);
static Result CustParser(const char* path, size_t filesize);
};

View File

@@ -1,358 +0,0 @@
#include "oc_extra.h"
CpuCoreUtil::CpuCoreUtil(int coreid = -2, uint64_t ns = 1000'000ULL)
: m_core_id(coreid), m_wait_time_ns(ns) { }
uint32_t CpuCoreUtil::Get() {
struct _ctx {
uint64_t systick;
uint64_t idletick;
} begin, end;
begin.systick = armGetSystemTick();
begin.idletick = GetIdleTickCount();
svcSleepThread(m_wait_time_ns);
end.systick = armGetSystemTick();
end.idletick = GetIdleTickCount();
uint64_t diff_idletick = end.idletick - begin.idletick;
uint64_t diff_systick = end.systick - begin.systick;
return UTIL_MAX - diff_idletick * 10 * 100ULL / diff_systick;
}
uint64_t CpuCoreUtil::GetIdleTickCount() {
uint64_t idletick = 0;
svcGetInfo(&idletick, InfoType_IdleTickCount, INVALID_HANDLE, m_core_id);
return idletick;
}
GpuCoreUtil::GpuCoreUtil(uint32_t nvgpu_field)
: m_nvgpu_field(nvgpu_field) { }
uint32_t GpuCoreUtil::Get() {
uint32_t load;
nvIoctl(m_nvgpu_field, NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD, &load);
return load;
}
ReverseNXSync::ReverseNXSync()
: m_rt_mode(ReverseNX_NotFound), m_tool_mode(ReverseNX_NotFound) {
FILE *fp = fopen("/atmosphere/contents/0000000000534C56/flags/boot2.flag", "r");
m_tool_enabled = fp ? true : false;
if (fp)
fclose(fp);
}
SysClkProfile ReverseNXSync::GetProfile(SysClkProfile real) {
switch (this->GetMode()) {
case ReverseNX_Docked:
return SysClkProfile_Docked;
case ReverseNX_Handheld:
if (real == SysClkProfile_Docked)
return SysClkProfile_HandheldChargingOfficial;
default:
return real;
}
}
ReverseNXMode ReverseNXSync::GetMode() {
if (!this->m_sync_enabled)
return ReverseNX_NotFound;
if (this->m_rt_mode)
return this->m_rt_mode;
return this->m_tool_mode;
}
ReverseNXMode ReverseNXSync::GetToolModeFromPatch(const char* patch_path) {
constexpr uint32_t DOCKED_MAGIC = 0x320003E0;
constexpr uint32_t HANDHELD_MAGIC = 0x52A00000;
FILE *fp = fopen(patch_path, "rb");
if (fp) {
uint32_t buf = 0;
fread(&buf, sizeof(buf), 1, fp);
fclose(fp);
if (buf == DOCKED_MAGIC)
return ReverseNX_Docked;
if (buf == HANDHELD_MAGIC)
return ReverseNX_Handheld;
}
return ReverseNX_NotFound;
}
ReverseNXMode ReverseNXSync::RecheckToolMode() {
ReverseNXMode mode = ReverseNX_NotFound;
if (this->m_tool_enabled) {
const char* fileName = "_ZN2nn2oe16GetOperationModeEv.asm64"; // or _ZN2nn2oe18GetPerformanceModeEv.asm64
const char* filePath = new char[72];
SCOPE_EXIT { delete[] filePath; };
/* Check per-game patch */
snprintf((char*)filePath, 72, "/SaltySD/patches/%016lX/%s", this->m_app_id, fileName);
mode = this->GetToolModeFromPatch(filePath);
if (!mode) {
/* Check global patch */
snprintf((char*)filePath, 72, "/SaltySD/patches/%s", fileName);
mode = this->GetToolModeFromPatch(filePath);
}
}
return mode;
}
void PsmExt::ChargingHandler(ClockManager* instance) {
u32 current;
Result res = I2c_Bq24193_GetFastChargeCurrentLimit(&current);
if (R_SUCCEEDED(res)) {
current -= current % 100;
u32 chargingCurrent = instance->GetConfig()->GetConfigValue(SysClkConfigValue_ChargingCurrentLimit);
if (current != chargingCurrent)
I2c_Bq24193_SetFastChargeCurrentLimit(chargingCurrent);
}
PsmChargeInfo* info = new PsmChargeInfo;
Service* session = psmGetServiceSession();
serviceDispatchOut(session, Psm_GetBatteryChargeInfoFields, *info);
if (PsmIsChargerConnected(info)) {
u32 chargeNow = 0;
if (R_SUCCEEDED(psmGetBatteryChargePercentage(&chargeNow))) {
bool isCharging = PsmIsCharging(info);
u32 chargingLimit = instance->GetConfig()->GetConfigValue(SysClkConfigValue_ChargingLimitPercentage);
bool forceDisabled = instance->GetBatteryChargingDisabledOverride();
if (isCharging && (forceDisabled || chargingLimit <= chargeNow))
serviceDispatch(session, Psm_DisableBatteryCharging);
if (!isCharging && chargingLimit > chargeNow)
serviceDispatch(session, Psm_EnableBatteryCharging);
}
}
delete info;
}
namespace GovernorImpl {
// Schedutil: https://github.com/torvalds/linux/blob/master/kernel/sched/cpufreq_schedutil.c
// C = 1.25, tipping-point 80.0% (used in Linux schedutil), 1.25 -> 1 + (1 >> 2)
// C = 1.5, tipping-point 66.7%, 1.5 -> 1 + (1 >> 1)
// Utilization is frequency-invariant :
// target_freq = C * max_freq * util / max
// Approximate the would-be frequency-invariant utilization (normalized) :
// target_freq = C * curr_freq * util_raw / max
void BaseGovernor::ApplyNewFreqFromNormUtil(uint32_t normUtil) {
uint32_t curr_hz = m_target_hz;
auto FindHzInTable = [](uint32_t* list, uint32_t hz) -> uint32_t {
uint32_t* p = list;
for (; *p != 0; p++) {
if (hz <= *p)
return *p;
}
return *(--p);
};
//uint32_t next_freq = m_ref_hz / UTIL_MAX * normUtil;
uint32_t next_freq = max_hz / UTIL_MAX * normUtil;
next_freq += next_freq >> 1;
uint32_t new_hz;
if (next_freq >= max_hz)
new_hz = max_hz;
else if (next_freq <= min_hz)
new_hz = min_hz;
else
new_hz = FindHzInTable(m_hz_list, next_freq);
if (new_hz != curr_hz)
ApplyTargetFreq(new_hz);
}
void CpuGovernor::GovernorWorker::Start() {
if (this->running)
return;
this->running = true;
Result rc = 0;
for (int id = 0; id < CORE_NUMS; id++) {
WorkerContext* s = &contexts[id];
s->super = this->super;
s->id = id;
int prio = (id == CORE_NUMS - 1) ? 0x3F : 0x3B; // Pre-emptive MT
rc = threadCreate(&threads[id], &WorkerContext::Loop, (void*)s, NULL, 0x400, prio, id);
ASSERT_RESULT_OK(rc, "threadCreate");
rc = threadStart(&threads[id]);
ASSERT_RESULT_OK(rc, "threadStart");
}
}
void CpuGovernor::GovernorWorker::Stop() {
if (!this->running)
return;
this->running = false;
svcSleepThread(TICK_TIME_NS);
for (auto &t : threads) {
threadWaitForExit(&t);
threadClose(&t);
}
}
void CpuGovernor::Apply() {
uint32_t util = 0;
for (auto& ctx : this->m_worker.contexts) {
uint32_t core_util = ctx.util;
if (util < core_util)
util = core_util;
}
this->m_util.Update(util);
if (this->auto_boost && this->m_worker.contexts[SYS_CORE_ID].util > BOOST_THRESHOLD)
this->ApplyBoost();
else
this->ApplyNewFreqFromNormUtil(this->m_util.Get());
}
void CpuGovernor::WorkerContext::Loop(void* args) {
WorkerContext* s = static_cast<WorkerContext*>(args);
CpuGovernor* self = s->super;
GovernorWorker* worker = &(self->m_worker);
int coreid = s->id;
while (worker->running) {
uint64_t tick = s->tick = armGetSystemTick();
s->util = self->CalcNormalizedUtil(CpuCoreUtil(coreid, TICK_TIME_NS).Get());
if (apmExtIsCPUBoosted(self->m_manager->GetPerfConf())) {
svcSleepThread(TICK_TIME_NS);
continue;
}
// Check if other cores are stuck
for (int id = 0; id < CORE_NUMS; id++) {
if (id == coreid)
continue;
uint64_t diff = std::abs((int64_t)worker->contexts[id].tick - (int64_t)tick);
if (diff < SYSTICK_HZ / SAMPLE_RATE * 10)
continue;
// Stuck on system core and auto boost enabled, apply boost
if (id == SYS_CORE_ID && self->auto_boost) {
self->ApplyBoost();
break;
}
// Stuck on other cores or auto boost disabled, apply max hz
self->ApplyTargetFreq(self->max_hz);
break;
}
}
}
void GpuGovernor::Apply() {
uint32_t util = this->CalcNormalizedUtil(GpuCoreUtil(m_nvgpu_field).Get());
this->m_util.Update(util);
this->ApplyNewFreqFromNormUtil(this->m_util.Get());
}
}
void Governor::SetConfig(SysClkOcGovernorConfig config) {
if (m_config == config)
return;
m_config = config;
m_cpu_gov->m_worker.onConfigUpdated(config);
m_manager.onConfigUpdated(config);
};
void Governor::SetPerfConf(uint32_t id) {
m_perf_conf_id = id;
m_apm_conf = Clocks::GetEmbeddedApmConfig(id);
}
void Governor::SetMaxHz(uint32_t maxHz, SysClkModule module) {
if (!maxHz) // Fallback to apm configuration
maxHz = Clocks::GetStockClock(m_apm_conf, (SysClkModule)module);
switch (module) {
case SysClkModule_CPU:
m_cpu_gov->max_hz = maxHz;
break;
case SysClkModule_GPU:
m_gpu_gov->max_hz = maxHz;
m_gpu_gov->min_hz = (maxHz <= 153'600'000) ? maxHz : 153'600'000;
break;
default:
break;
}
}
void Governor::SetMinHz(uint32_t minHz, SysClkModule module) {
if (module == SysClkModule_CPU) {
m_cpu_gov->min_hz = minHz;
}
}
void Governor::GovernorManager::Start() {
if (this->running)
return;
this->running = true;
Result rc = threadCreate(&thread, &ContextManager, (void*)this, NULL, 0x400, 0x3F, 3);
ASSERT_RESULT_OK(rc, "threadCreate");
rc = threadStart(&thread);
ASSERT_RESULT_OK(rc, "threadStart");
}
void Governor::GovernorManager::Stop() {
if (!this->running)
return;
this->running = false;
svcSleepThread(TICK_TIME_NS);
threadWaitForExit(&thread);
threadClose(&thread);
}
void Governor::GovernorManager::ContextManager(void* args) {
Governor* self = static_cast<Governor*>(args);
constexpr uint64_t UPDATE_CONTEXT_RATE = SAMPLE_RATE / 2;
uint64_t update_ticks = UPDATE_CONTEXT_RATE;
bool cpuBoosted = false, gpuThrottled = false;
while (self->m_manager.running) {
bool shouldUpdateContext = ++update_ticks >= UPDATE_CONTEXT_RATE;
if (shouldUpdateContext) {
update_ticks = 0;
uint32_t hz = self->m_gpu_gov->RefreshContext();
// Sleep mode detected, wait 10 ticks
while (!hz) {
svcSleepThread(10 * TICK_TIME_NS);
hz = self->m_gpu_gov->RefreshContext();
}
uint32_t perf_conf = self->GetPerfConf();
if ((gpuThrottled = apmExtIsBoostMode(perf_conf)) && self->IsHandledByGovernor(SysClkModule_GPU))
self->m_gpu_gov->ApplyBoost();
if ((cpuBoosted = apmExtIsCPUBoosted(perf_conf)) && self->IsHandledByGovernor(SysClkModule_CPU))
self->m_cpu_gov->ApplyBoost();
}
if (!gpuThrottled && self->IsHandledByGovernor(SysClkModule_GPU))
self->m_gpu_gov->Apply();
if (!cpuBoosted && self->IsHandledByGovernor(SysClkModule_CPU))
self->m_cpu_gov->Apply();
svcSleepThread(TICK_TIME_NS);
}
};

View File

@@ -1,367 +0,0 @@
#pragma once
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <nxExt.h>
#include <sysclk.h>
#include <switch.h>
#include "errors.h"
#include "file_utils.h"
#include "clocks.h"
// Forward declaration
class ClockManager;
class Governor;
#include "clock_manager.h"
class CpuCoreUtil {
public:
CpuCoreUtil (int coreid, uint64_t ns);
uint32_t Get();
protected:
const int m_core_id;
const uint64_t m_wait_time_ns;
static constexpr uint64_t IDLETICKS_PER_MS = 192;
static constexpr uint32_t UTIL_MAX = 100'0;
uint64_t GetIdleTickCount();
};
class GpuCoreUtil {
public:
GpuCoreUtil (uint32_t nvgpu_field);
uint32_t Get();
protected:
uint32_t m_nvgpu_field;
static constexpr uint64_t NVGPU_GPU_IOCTL_PMU_GET_GPU_LOAD = 0x80044715;
};
class ReverseNXSync {
public:
ReverseNXSync ();
void ToggleSync(bool enable) { m_sync_enabled = enable; };
void Reset(uint64_t app_id) { m_app_id = app_id; SetRTMode(ReverseNX_NotFound); GetToolMode(); }
ReverseNXMode GetRTMode() { return m_rt_mode; };
void SetRTMode(ReverseNXMode mode) { m_rt_mode = mode; };
ReverseNXMode GetToolMode() { return m_tool_mode = RecheckToolMode(); };
SysClkProfile GetProfile(SysClkProfile real);
ReverseNXMode GetMode();
protected:
std::atomic<ReverseNXMode> m_rt_mode;
ReverseNXMode m_tool_mode;
uint64_t m_app_id = 0;
bool m_tool_enabled;
bool m_sync_enabled;
ReverseNXMode GetToolModeFromPatch(const char* patch_path);
ReverseNXMode RecheckToolMode();
};
namespace PsmExt {
void ChargingHandler(ClockManager* instance);
}
constexpr uint64_t SAMPLE_RATE = 200;
constexpr uint64_t TICK_TIME_NS = 1000'000'000 / SAMPLE_RATE;
constexpr uint64_t SYSTICK_HZ = 19200000;
namespace GovernorImpl {
constexpr uint32_t UTIL_MAX = 1000;
class BaseGovernor {
public:
BaseGovernor(SysClkModule module) : m_module(module) {
m_hz_list = Clocks::freqTable[module].freq;
m_ref_hz = *Clocks::freqRange[module].last;
};
uint32_t RefreshContext() { return this->m_target_hz = Clocks::GetCurrentHz(this->m_module); };
uint32_t min_hz, max_hz, boost_hz;
protected:
uint32_t CalcNormalizedUtil(uint32_t rawUtil) {
//return ((uint64_t)rawUtil * m_target_hz / m_ref_hz);
return ((uint64_t)rawUtil * m_target_hz / max_hz);
};
void ApplyNewFreqFromNormUtil(uint32_t norm);
void ApplyTargetFreq(uint32_t hz) {
if (!hz)
return;
m_target_hz = hz;
Clocks::SetHz(m_module, hz);
};
SysClkModule m_module;
uint32_t* m_hz_list;
uint32_t m_target_hz, m_ref_hz;
friend Governor;
};
class CpuGovernor : public BaseGovernor {
public:
CpuGovernor(Governor* manager)
: BaseGovernor(SysClkModule_CPU), m_manager(manager) {
boost_hz = Clocks::boostCpuFreq;
m_worker.super = this;
};
~CpuGovernor() { this->m_worker.Stop(); };
void Apply();
void ApplyBoost() {
ApplyTargetFreq((max_hz > boost_hz) ? max_hz : boost_hz);
};
bool auto_boost;
protected:
static constexpr int CORE_NUMS = 4;
static constexpr int SYS_CORE_ID = CORE_NUMS - 1;
// PELT: https://github.com/torvalds/linux/blob/master/kernel/sched/pelt.c
// Util_acc_n = Util_0 + Util_1 * D + Util_2 * D^2 + ... + Util_n * D^n
// To approximate D (decay multiplier):
// After 50 ms (if SAMPLE_RATE == 200, 10 samples)
// UTIL_MAX * D^10 ≈ 1 (UTIL_MAX decayed to 1)
// D = 4129 / 8192
// Util_acc_max = Util_acc_inf = 2012
typedef struct PeltUtil {
uint32_t util_acc = 0;
static constexpr uint32_t DECAY_DIVIDENT = 4129;
static constexpr uint32_t DECAY_DIVISOR = 8192;
static constexpr uint32_t UTIL_ACC_MAX = 2012;
uint32_t Get() { return (util_acc * UTIL_MAX / UTIL_ACC_MAX); };
void Update(uint32_t util) { util_acc = util_acc * DECAY_DIVIDENT / DECAY_DIVISOR + util; };
} PeltUtil;
PeltUtil m_util;
typedef struct {
CpuGovernor*super;
int id;
uint32_t util;
uint64_t tick;
static void Loop(void* args);
} WorkerContext;
typedef struct GovernorWorker {
Thread threads[CORE_NUMS];
WorkerContext contexts[CORE_NUMS];
bool running;
CpuGovernor* super;
void Start();
void Stop();
void onConfigUpdated(SysClkOcGovernorConfig config) {
bool expected = (config >> SysClkOcGovernorConfig_CPU_Shift) & 1;
if (expected != running)
expected ? Start() : Stop();
};
} GovernorWorker;
GovernorWorker m_worker;
Governor* m_manager;
friend Governor;
};
class GpuGovernor : public BaseGovernor {
public:
GpuGovernor() : BaseGovernor(SysClkModule_GPU) {
min_hz = 153'600'000;
boost_hz = 76'800'000;
nvInitialize();
Result rc = nvOpen(&m_nvgpu_field, "/dev/nvhost-ctrl-gpu");
if (R_FAILED(rc)) {
ASSERT_RESULT_OK(rc, "nvOpen");
nvExit();
}
};
~GpuGovernor() {
nvClose(m_nvgpu_field);
nvExit();
};
void ApplyBoost() {
ApplyTargetFreq(boost_hz);
};
void Apply();
protected:
// Get average value from a sliding window in O(1)
template <typename T, size_t WINDOW_SIZE>
class SWindowAvg {
public:
SWindowAvg() {}
void Add(T item) {
T pop = m_queue[m_next];
m_queue[m_next] = item;
m_next = (m_next + 1) % WINDOW_SIZE;
m_sum -= pop;
m_sum += item;
}
T Get() { return m_sum / WINDOW_SIZE; }
protected:
size_t m_next = 0;
T m_sum = 0;
T m_queue[WINDOW_SIZE] = {};
};
// Get max value from a sliding window in O(1)
template <typename T, size_t WINDOW_SIZE>
class SWindowMax {
protected:
typedef struct {
T item;
T max;
} s_Entry;
struct s_Stack {
s_Entry m_stack[WINDOW_SIZE] = {};
size_t m_next = WINDOW_SIZE;
bool empty() { return m_next == 0; };
s_Entry top() { return m_stack[m_next-1]; };
s_Entry pop() { return m_stack[--m_next]; };
void push(s_Entry item) {
if (m_next == WINDOW_SIZE)
return;
m_stack[m_next++] = item;
};
};
s_Stack enqStack;
s_Stack deqStack;
void Push(s_Stack& stack, T item) {
s_Entry n = {
.item = item,
.max = enqStack.empty() ? item : std::max(item, enqStack.top().max)
};
stack.push(n);
}
T Pop() {
if (deqStack.empty()) {
while (!enqStack.empty())
Push(deqStack, enqStack.pop().max);
}
return deqStack.pop().item;
}
public:
SWindowMax() {}
void Add(T item) { Pop(); Push(enqStack, item); }
T Get() {
if (!enqStack.empty()) {
T enqMax = enqStack.top().max;
if (!deqStack.empty()) {
T deqMax = deqStack.top().max;
return std::max(deqMax, enqMax);
}
return enqMax;
}
if (!deqStack.empty())
return deqStack.top().max;
return 0;
}
};
typedef struct MaxWindow {
SWindowMax<uint32_t, 32> window {};
uint32_t util_acc = 0;
// After 160 ms (if SAMPLE_RATE == 200, 32 samples)
// UTIL_MAX * D^32 ≈ 1 (UTIL_MAX decayed to 1)
// D = 6880 / 8192
// Util_acc_max = Util_acc_inf = 6145
static constexpr uint32_t DECAY_DIVIDENT = 6880;
static constexpr uint32_t DECAY_DIVISOR = 8192;
static constexpr uint32_t UTIL_ACC_MAX = 6145;
uint32_t Get() { return ((util_acc * UTIL_MAX / UTIL_ACC_MAX) + window.Get()) / 2; };
void Update(uint32_t util) { window.Add(util); util_acc = util_acc * DECAY_DIVIDENT / DECAY_DIVISOR + util; };
} MaxWindow;
MaxWindow m_util;
uint32_t m_nvgpu_field;
};
}
class Governor {
public:
Governor() {
m_cpu_gov = new GovernorImpl::CpuGovernor(this);
m_gpu_gov = new GovernorImpl::GpuGovernor();
};
~Governor() {
m_manager.Stop();
delete m_cpu_gov;
delete m_gpu_gov;
};
SysClkOcGovernorConfig GetConfig() { return m_config; };
inline bool IsHandledByGovernor(SysClkModule module) { return GetGovernorEnabled(this->GetConfig(), module); };
void SetConfig(SysClkOcGovernorConfig config);
void SetPerfConf(uint32_t id);
uint32_t GetPerfConf() { return m_perf_conf_id; };
void SetMaxHz(uint32_t maxHz, SysClkModule module);
void SetMinHz(uint32_t minHz, SysClkModule module);
void SetAutoCPUBoost(bool enabled) { m_cpu_gov->auto_boost = enabled; };
void SetCPUBoostHz(uint32_t boostHz) { m_cpu_gov->boost_hz = boostHz; };
protected:
typedef struct GovernorManager {
bool running = false;
Thread thread;
void Start();
void Stop();
void onConfigUpdated(SysClkOcGovernorConfig config) {
bool shouldRun = (config != SysClkOcGovernorConfig_AllDisabled);
shouldRun ? Start() : Stop();
};
static void ContextManager(void* args);
} GovernorManager;
GovernorManager m_manager;
SysClkOcGovernorConfig m_config = SysClkOcGovernorConfig_AllDisabled;
uint32_t m_perf_conf_id;
SysClkApmConfiguration* m_apm_conf;
GovernorImpl::CpuGovernor* m_cpu_gov;
GovernorImpl::GpuGovernor* m_gpu_gov;
};

5
Source/sys-clk-OC/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/dist
.DS_Store
Thumbs.db
desktop.ini
.vscode

View File

@@ -0,0 +1,17 @@
image: $CI_SERVER_HOST:4567/libretro/infrastructure/libretro-build-libnx-devkitpro:latest
variables:
PACKAGE_FOLDER: "sys-clk"
stages:
- package
nightly:
stage: package
script:
- bash build.sh $PACKAGE_FOLDER
artifacts:
name: $PACKAGE_FOLDER
expire_in: 24 hours
paths:
- $PACKAGE_FOLDER

View File

@@ -1,114 +1,18 @@
# sys-clk-OC
Switch sysmodule allowing you to set cpu/gpu clocks according to the running application and docked state.
# sys-clk-oc
Switch sysmodule allowing you to set cpu/gpu/mem clocks according to the running application and docked state.
## Clock table (MHz)
official means HOS official, unless specified
### CPU clocks
* 2397 → OC max for Mariko (with CPU UV)
* 2295 → OC max for Mariko
* 2193
* 2091 → OC max for Erista
* 1963 → official and safe max for Mariko
* 1887
* 1785 → official boost mode, safe max for Erista
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev OC
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612
### GPU clocks
* 1305 → N/A
* 1267 → official max for Mariko (Tegra X1+ official max)
* 1228 → recommended max for Hiopt
* 1152
* 1075 → recommended max for SLT
* 998 → safe max for Mariko, max for Erista (Tegra X1 official max)
* 921 → safe max for Erista
* 844
* 768 → official docked
* 691
* 614 → recommended Mariko max for handheld
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
### MEM clocks
From Hekate Minerva module [sys_sdrammtc.c](https://github.com/CTCaer/hekate/blob/master/modules/hekate_libsys_minerva/sys_sdrammtc.c#L65)
- 3200 → l4t and closed version max for Mariko
- 2931
- 2665
- 2502 → max for Mariko
- 2400
- 2361 → l4t and closed version max for Erista
- 2131 → JEDEC. max for Erista and official max for Mariko. lpddr4(x) official max
- 2099
- 2064
- 1996 → OCS mariko default
- 1932
- 1894
- 1862 → JEDEC. official max for Erista; OCS erista default
- 1795
- 1728
- 1600 → official docked & official boost mode
- 1331 → JEDEC. official handheld
- 1065
- 800
- 665
## Capping
To protect the battery from excessive strain, clocks requested from config may be capped before applying, depending on your current profile:
### Erista (Safe)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1785 | 1785 | 1785 | 1785 |
| **GPU** | 460 | 768 | 921 | 921 |
### Erista (Unsafe allowed)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1785 | 1785 | - | - |
| **GPU** | 460 | 768 | - | - |
### Mariko (Safe)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1963 | 1963 | 1963 | 1963 |
| **GPU** | 768 | 921 | 998 | 998 |
### Mariko (Unsafe allowed)
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-------:|:--------:|:--------------:|:-------------------:|:------:|
| **MEM** | - | - | - | - |
| **CPU** | 1963 | 1963 | - | - |
| **GPU** | 768 | 921 | - | - |
## Exclusive Features for sys-clk-oc
### Real Volts
voltage readings from devices: CPU/GPU/MEM/SOC
### Real Temps
temperature readings from thermal sensors: CPU/GPU/MEM/PLL/AO
### Cpu volt bug fix
fixes bug present in official driver
### Reversenx sync
automatically changes profile when reversenx state is changed
## Installation
@@ -135,10 +39,14 @@ Copy the `atmosphere`, and `switch` folders at the root of your sdcard, overwrit
`/config/sys-clk/context.csv`
* sys-clk manager app (accessible from the hbmenu)
`/switch/sys-clk-manager.nro`
* sys-clk overlay (accessible from anywhere by invoking the [Tesla menu](https://gbatemp.net/threads/tesla-the-nintendo-switch-overlay-menu.557362/))
`/switch/.overlays/sys-clk-overlay.ovl`
* sys-clk core sysmodule
`/atmosphere/contents/00FF0000636C6BFF/exefs.nsp`
@@ -146,7 +54,7 @@ Copy the `atmosphere`, and `switch` folders at the root of your sdcard, overwrit
## Config
Presets can be customized by adding them to the ini config file located at `/config/sys-clk/config.ini`, using the following template for each app
Presets can be customized by adding them to the ini config file located at `/config/sys-clk/config.ini`, using the following template for each app
```
[Application Title ID]
@@ -171,7 +79,7 @@ handheld_mem=
A list of games title id can be found in the [Switchbrew wiki](https://switchbrew.org/wiki/Title_list/Games).
* Frequencies are expressed in mhz, and will be scaled to the nearest possible values, described in the clock table below.
* If any key is omitted, value is empty or set to 0, it will be ignored, and stock clocks will apply.
* If charging, sys-clk will look for the frequencies in that order, picking the first found
* If charging, sys-clk will look for the frequencies in that order, picking the first found
1. Charger specific config (USB or Official) `handheld_charging_usb_X` or `handheld_charging_official_X`
2. Non specific charging config `handheld_charging_X`
3. Handheld config `handheld_X`
@@ -179,6 +87,7 @@ A list of games title id can be found in the [Switchbrew wiki](https://switchbre
### Example 1: Zelda BOTW
* Overclock CPU when docked or charging
* Overclock MEM to docked clocks when handheld
Leads to a smoother framerate overall (ex: in the korok forest)
@@ -197,17 +106,79 @@ handheld_mem=1600
[0100BA0003EEA000]
handheld_cpu=816
handheld_gpu=153
handheld_mem=800
```
### Advanced
The `[values]` section allows you to alter timings in sys-clk, you should not need to edit any of these unless you know what you are doing. Possible values are:
| Key | Desc | Default |
|:------------------------:|-------------------------------------------------------------------------------|:---------:|
|**allow_unsafe_freq** | Allow unsafe frequencies (CPU > 1963.5 MHz, GPU > 921.6 MHz) | OFF |
|**uncapped_clocks** | Remove CPU/GPU clock cappings | OFF |
|**override_boost_mode** | Override boost mode frequency with user set values (CPU/GPU) | OFF |
|**temp_log_interval_ms** | Defines how often sys-clk log temperatures, in milliseconds (`0` to disable) | 0 ms |
|**csv_write_interval_ms** | Defines how often sys-clk writes to the CSV, in milliseconds (`0` to disable) | 0 ms |
|**poll_interval_ms** | Defines how fast sys-clk checks and applies profiles, in milliseconds | 500 ms |
| Key | Desc | Default |
|:-----------------------:|-------------------------------------------------------------------------------|:-------:|
|**temp_log_interval_ms** | Defines how often sys-clk logs temperatures, in milliseconds (`0` to disable) | 0 ms |
|**freq_log_interval_ms** | Defines how often sys-clk logs real freqs, in milliseconds (`0` to disable) | 0 ms |
|**power_log_interval_ms**| Defines how often sys-clk logs power usage, in milliseconds (`0` to disable) | 0 ms |
|**csv_write_interval_ms**| Defines how often sys-clk writes to the CSV, in milliseconds (`0` to disable) | 0 ms |
|**poll_interval_ms** | Defines how fast sys-clk checks and applies profiles, in milliseconds | 300 ms |
|**uncapped_clocks** | Removes clock cappings | OFF |
|**override_boost_mode** | Overrides official boost mode with user set profile clocks | OFF |
|**auto_cpu_boost** | Sets cpu clock to boost clock when core#3 load ≥ 90% | OFF |
|**sync_reversenx** | Overrides profile to match reversenx state | ON |
## Capping
To protect the battery from excessive strain, clocks requested from config may be capped before applying, depending on your current profile:
### Erista:
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-----:|:--------:|:--------------:|:-------------------:|:------:|
|**MEM**| - | - | - | - |
|**CPU**| 1785 MHz | 1785 MHz | - | - |
|**GPU**| 460 MHz | 768 MHz | - | - |
### Mariko:
| | Handheld | Charging (USB) | Charging (Official) | Docked |
|:-----:|:--------:|:--------------:|:-------------------:|:------:|
|**MEM**| - | - | - | - |
|**CPU**| 1963 MHz | 1963 MHz | - | - |
|**GPU**| 768 MHz | 921 MHz | - | - |
## Clock table (MHz)
### MEM clocks
* 1600 → official docked, boost mode, max clock
* 1331 → official handheld
* 1065
* 800
* 665
### CPU clocks
* 1785 → max clock, boost mode
* 1683
* 1581
* 1428
* 1326
* 1224 → sdev oc
* 1122
* 1020 → official docked & handheld
* 918
* 816
* 714
* 612
### GPU clocks
* 921 → max clock
* 844
* 768 → official docked
* 691
* 614
* 537
* 460 → max handheld
* 384 → official handheld
* 307 → official handheld
* 230
* 153
* 76 → boost mode
**Notes:**

View File

@@ -3,7 +3,7 @@ set -e
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DIST_DIR="$ROOT_DIR/dist"
CORES=$(nproc --all)
CORES="$(nproc --all)"
if [[ -n "$1" ]]; then
DIST_DIR="$1"
@@ -13,16 +13,24 @@ echo "DIST_DIR: $DIST_DIR"
echo "CORES: $CORES"
echo "*** sysmodule ***"
TITLE_ID="00FF0000636C6BFF"
TITLE_ID="$(grep -oP '"title_id":\s*"0x\K(\w+)' "$ROOT_DIR/sysmodule/perms.json")"
pushd "$ROOT_DIR/sysmodule"
make -j$CORES
popd > /dev/null
mkdir -p "$DIST_DIR/atmosphere/contents/$TITLE_ID/flags"
cp -vf "$ROOT_DIR/sysmodule/out/sys-clk-OC.nsp" "$DIST_DIR/atmosphere/contents/$TITLE_ID/exefs.nsp"
cp -vf "$ROOT_DIR/sysmodule/out/sys-clk.nsp" "$DIST_DIR/atmosphere/contents/$TITLE_ID/exefs.nsp"
>"$DIST_DIR/atmosphere/contents/$TITLE_ID/flags/boot2.flag"
echo "*** manager ***"
pushd "$ROOT_DIR/manager"
make -j$CORES
popd > /dev/null
mkdir -p "$DIST_DIR/switch"
cp -vf "$ROOT_DIR/manager/sys-clk-manager.nro" "$DIST_DIR/switch/sys-clk-manager.nro"
echo "*** overlay ***"
pushd "$ROOT_DIR/overlay"
make -j$CORES
@@ -32,7 +40,6 @@ mkdir -p "$DIST_DIR/switch/.overlays"
cp -vf "$ROOT_DIR/overlay/out/sys-clk-overlay.ovl" "$DIST_DIR/switch/.overlays/sys-clk-overlay.ovl"
echo "*** assets ***"
mkdir -p "$DIST_DIR/config/sys-clk-oc"
cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/sys-clk-oc/config.ini.template"
>"$DIST_DIR/config/sys-clk-oc/log.flag"
mkdir -p "$DIST_DIR/config/sys-clk"
cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/sys-clk/config.ini.template"
cp -vf "$ROOT_DIR/README.md" "$DIST_DIR/README.md"

View File

@@ -11,17 +11,15 @@
#pragma once
#ifdef __cplusplus
#include "cpp_util.hpp"
extern "C" {
#endif
#include "sysclk/ipc.h"
#include "sysclk/clocks.h"
#include "sysclk/board.h"
#include "sysclk/clock_manager.h"
#include "sysclk/apm.h"
#include "sysclk/config.h"
#include "sysclk/errors.h"
#include "sysclk/i2c.h"
#include "sysclk/psm_ext.h"
#ifdef __cplusplus
}

View File

@@ -10,7 +10,7 @@
#pragma once
#include "clocks.h"
#include "board.h"
typedef struct {
uint32_t id;
@@ -19,4 +19,4 @@ typedef struct {
uint32_t mem_hz;
} SysClkApmConfiguration;
extern SysClkApmConfiguration sysclk_g_apm_configurations[];
extern SysClkApmConfiguration sysclk_g_apm_configurations[];

View File

@@ -0,0 +1,119 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef enum
{
SysClkSocType_Erista = 0,
SysClkSocType_Mariko,
SysClkSocType_EnumMax
} SysClkSocType;
typedef enum
{
SysClkProfile_Handheld = 0,
SysClkProfile_HandheldCharging,
SysClkProfile_HandheldChargingUSB,
SysClkProfile_HandheldChargingOfficial,
SysClkProfile_Docked,
SysClkProfile_EnumMax
} SysClkProfile;
typedef enum
{
SysClkModule_CPU = 0,
SysClkModule_GPU,
SysClkModule_MEM,
SysClkModule_EnumMax
} SysClkModule;
typedef enum
{
SysClkThermalSensor_SOC = 0,
SysClkThermalSensor_PCB,
SysClkThermalSensor_Skin,
SysClkThermalSensor_EnumMax
} SysClkThermalSensor;
typedef enum
{
SysClkPowerSensor_Now = 0,
SysClkPowerSensor_Avg,
SysClkPowerSensor_EnumMax
} SysClkPowerSensor;
#define SYSCLK_ENUM_VALID(n, v) ((v) < n##_EnumMax)
static inline const char* sysclkFormatModule(SysClkModule module, bool pretty)
{
switch(module)
{
case SysClkModule_CPU:
return pretty ? "CPU" : "cpu";
case SysClkModule_GPU:
return pretty ? "GPU" : "gpu";
case SysClkModule_MEM:
return pretty ? "Memory" : "mem";
default:
return NULL;
}
}
static inline const char* sysclkFormatThermalSensor(SysClkThermalSensor thermSensor, bool pretty)
{
switch(thermSensor)
{
case SysClkThermalSensor_SOC:
return pretty ? "SOC" : "soc";
case SysClkThermalSensor_PCB:
return pretty ? "PCB" : "pcb";
case SysClkThermalSensor_Skin:
return pretty ? "Skin" : "skin";
default:
return NULL;
}
}
static inline const char* sysclkFormatPowerSensor(SysClkPowerSensor powSensor, bool pretty)
{
switch(powSensor)
{
case SysClkPowerSensor_Now:
return pretty ? "Now" : "now";
case SysClkPowerSensor_Avg:
return pretty ? "Avg" : "avg";
default:
return NULL;
}
}
static inline const char* sysclkFormatProfile(SysClkProfile profile, bool pretty)
{
switch(profile)
{
case SysClkProfile_Docked:
return pretty ? "Docked" : "docked";
case SysClkProfile_Handheld:
return pretty ? "Handheld" : "handheld";
case SysClkProfile_HandheldCharging:
return pretty ? "Charging" : "handheld_charging";
case SysClkProfile_HandheldChargingUSB:
return pretty ? "USB Charger" : "handheld_charging_usb";
case SysClkProfile_HandheldChargingOfficial:
return pretty ? "Official Charger" : "handheld_charging_official";
default:
return NULL;
}
}

View File

@@ -10,13 +10,9 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
#include "../config.h"
#include "../clocks.h"
#include "../board.h"
#include "../ipc.h"
bool sysclkIpcRunning();
@@ -34,17 +30,9 @@ Result sysclkIpcGetProfiles(u64 tid, SysClkTitleProfileList* out_profiles);
Result sysclkIpcSetProfiles(u64 tid, SysClkTitleProfileList* profiles);
Result sysclkIpcGetConfigValues(SysClkConfigValueList* out_configValues);
Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues);
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode);
Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table);
Result sysclkIpcGetIsMariko(bool* out_is_mariko);
Result sysclkIpcGetBatteryChargingDisabledOverride(bool* out_is_true);
Result sysclkIpcSetBatteryChargingDisabledOverride(bool toggle_true);
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount);
static inline Result sysclkIpcRemoveOverride(SysClkModule module)
{
return sysclkIpcSetOverride(module, 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,36 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include "board.h"
typedef struct
{
uint8_t enabled;
uint64_t applicationId;
SysClkProfile profile;
uint32_t freqs[SysClkModule_EnumMax];
uint32_t realFreqs[SysClkModule_EnumMax];
uint32_t overrideFreqs[SysClkModule_EnumMax];
uint32_t temps[SysClkThermalSensor_EnumMax];
int32_t power[SysClkPowerSensor_EnumMax];
} SysClkContext;
typedef struct
{
union {
uint32_t mhz[SysClkProfile_EnumMax * SysClkModule_EnumMax];
uint32_t mhzMap[SysClkProfile_EnumMax][SysClkModule_EnumMax];
};
} SysClkTitleProfileList;
#define SYSCLK_FREQ_LIST_MAX 32

View File

@@ -0,0 +1,78 @@
/*
* --------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <p-sam@d3vs.net>, <natinusala@gmail.com>, <m4x@m4xw.net>
* wrote this file. As long as you retain this notice you can do whatever you
* want with this stuff. If you meet any of us some day, and you think this
* stuff is worth it, you can buy us a beer in return. - The sys-clk authors
* --------------------------------------------------------------------------
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef enum {
SysClkConfigValue_PollingIntervalMs = 0,
SysClkConfigValue_TempLogIntervalMs,
SysClkConfigValue_FreqLogIntervalMs,
SysClkConfigValue_PowerLogIntervalMs,
SysClkConfigValue_CsvWriteIntervalMs,
SysClkConfigValue_EnumMax,
} SysClkConfigValue;
typedef struct {
uint64_t values[SysClkConfigValue_EnumMax];
} SysClkConfigValueList;
static inline const char* sysclkFormatConfigValue(SysClkConfigValue val, bool pretty)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return pretty ? "Polling Interval (ms)" : "poll_interval_ms";
case SysClkConfigValue_TempLogIntervalMs:
return pretty ? "Temperature logging interval (ms)" : "temp_log_interval_ms";
case SysClkConfigValue_FreqLogIntervalMs:
return pretty ? "Frequency logging interval (ms)" : "freq_log_interval_ms";
case SysClkConfigValue_PowerLogIntervalMs:
return pretty ? "Power logging interval (ms)" : "power_log_interval_ms";
case SysClkConfigValue_CsvWriteIntervalMs:
return pretty ? "CSV write interval (ms)" : "csv_write_interval_ms";
default:
return NULL;
}
}
static inline uint64_t sysclkDefaultConfigValue(SysClkConfigValue val)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return 300ULL;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_FreqLogIntervalMs:
case SysClkConfigValue_PowerLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
return 0ULL;
default:
return 0ULL;
}
}
static inline uint64_t sysclkValidConfigValue(SysClkConfigValue val, uint64_t input)
{
switch(val)
{
case SysClkConfigValue_PollingIntervalMs:
return input > 0;
case SysClkConfigValue_TempLogIntervalMs:
case SysClkConfigValue_FreqLogIntervalMs:
case SysClkConfigValue_PowerLogIntervalMs:
case SysClkConfigValue_CsvWriteIntervalMs:
return input >= 0;
default:
return false;
}
}

View File

@@ -18,5 +18,4 @@ typedef enum
SysClkError_Generic = 0,
SysClkError_ConfigNotLoaded = 1,
SysClkError_ConfigSaveFailed = 2,
SysClkError_InternalFrequencyTableError = 3,
} SysClkError;

View File

@@ -11,10 +11,11 @@
#pragma once
#include <stdint.h>
#include "clocks.h"
#include "board.h"
#include "clock_manager.h"
#define SYSCLK_IPC_API_VERSION 2
#define SYSCLK_IPC_SERVICE_NAME "sysclkOC"
#define SYSCLK_IPC_API_VERSION 3
#define SYSCLK_IPC_SERVICE_NAME "sys:clk"
enum SysClkIpcCmd
{
@@ -29,13 +30,10 @@ enum SysClkIpcCmd
SysClkIpcCmd_SetOverride = 8,
SysClkIpcCmd_GetConfigValues = 9,
SysClkIpcCmd_SetConfigValues = 10,
SysClkIpcCmd_SetReverseNXRTMode = 11,
SysClkIpcCmd_GetFrequencyTable = 12,
SysClkIpcCmd_GetIsMariko = 13,
SysClkIpcCmd_GetBatteryChargingDisabledOverride = 14,
SysClkIpcCmd_SetBatteryChargingDisabledOverride = 15,
SysClkIpcCmd_GetFreqList = 11,
};
typedef struct
{
uint64_t tid;
@@ -51,5 +49,5 @@ typedef struct
typedef struct
{
SysClkModule module;
SysClkProfile profile;
} SysClkIpc_GetFrequencyTable_Args;
uint32_t maxCount;
} SysClkIpc_GetFreqList_Args;

View File

@@ -17,7 +17,7 @@ SysClkApmConfiguration sysclk_g_apm_configurations[] = {
{0x00020000, 1020000000, 230400000, 1600000000},
{0x00020001, 1020000000, 307200000, 1600000000},
{0x00020002, 1224000000, 230400000, 1600000000},
{0x00020003, 1020000000, 307000000, 1331200000},
{0x00020003, 1020000000, 307200000, 1331200000},
{0x00020004, 1020000000, 384000000, 1331200000},
{0x00020005, 1020000000, 307200000, 1065600000},
{0x00020006, 1020000000, 384000000, 1065600000},

View File

@@ -115,31 +115,14 @@ Result sysclkIpcSetConfigValues(SysClkConfigValueList* configValues)
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetConfigValues, *configValues);
}
Result sysclkIpcSetReverseNXRTMode(ReverseNXMode mode)
Result sysclkIpcGetFreqList(SysClkModule module, u32* list, u32 maxCount, u32* outCount)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetReverseNXRTMode, mode);
}
Result sysclkIpcGetFrequencyTable(SysClkModule module, SysClkProfile profile, SysClkFrequencyTable* out_table)
{
SysClkIpc_GetFrequencyTable_Args args = {
SysClkIpc_GetFreqList_Args args = {
.module = module,
.profile = profile,
.maxCount = maxCount
};
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetFrequencyTable, args, *out_table);
}
Result sysclkIpcGetIsMariko(bool* out_is_mariko)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetIsMariko, *out_is_mariko);
}
Result sysclkIpcGetBatteryChargingDisabledOverride(bool* out_is_true)
{
return serviceDispatchOut(&g_sysclkSrv, SysClkIpcCmd_GetBatteryChargingDisabledOverride, *out_is_true);
}
Result sysclkIpcSetBatteryChargingDisabledOverride(bool toggle_true)
{
return serviceDispatchIn(&g_sysclkSrv, SysClkIpcCmd_SetBatteryChargingDisabledOverride, toggle_true);
}
return serviceDispatchInOut(&g_sysclkSrv, SysClkIpcCmd_GetFreqList, args, *outCount,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = {{list, maxCount * sizeof(u32)}},
);
}

View File

@@ -6,11 +6,14 @@ csv_write_interval_ms=0
; Example #1: BOTW
; Overclock CPU when docked
; Overclock MEM to docked clocks when handheld
;[01007EF00011E000]
;docked_cpu=1224
;handheld_mem=1600
; Example #2: Picross
; Underclock to save battery
;[0100BA0003EEA000]
;handheld_cpu=816
;handheld_gpu=153
;handheld_gpu=153
;handheld_mem=800

9
Source/sys-clk-OC/manager/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.*/
build/
build.nx/
*~
*.bak
*.nro
*.nacp
*.elf
.vscode

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@@ -0,0 +1,245 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
TARGET := sys-clk-manager
BUILD := build.nx
SOURCES := src ../common/src ../common/src/client
RESOURCES := resources
DATA := data
INCLUDES := ../common/include
APP_TITLE := sys-clk manager
APP_AUTHOR := RetroNX Team
ROMFS := $(BUILD)/romfs
BOREALIS_PATH := lib/borealis
BOREALIS_RESOURCES := romfs:/borealis/
APP_RESOURCES := romfs:/
#---------------------------------------------------------------------------------
# version control constants
#---------------------------------------------------------------------------------
TARGET_VERSION := $(shell git describe --dirty --always --tags)
APP_VERSION := $(TARGET_VERSION)
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__ \
-DAPP_TITLE="\"$(APP_TITLE)\"" \
-DBOREALIS_RESOURCES="\"$(BOREALIS_RESOURCES)\"" \
-DAPP_RESOURCES="\"$(APP_RESOURCES)\""
CXXFLAGS := $(CFLAGS) -std=c++1z
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
include $(TOPDIR)/$(BOREALIS_PATH)/library/borealis.mk
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) $(ROMFS) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(ROMFS):
@[ -d $@ ] || mkdir -p $@
@echo Merging ROMFS...
@cp -ruf $(CURDIR)/$(BOREALIS_PATH)/resources/. $(CURDIR)/$(ROMFS)/borealis/
@cp -ruf $(CURDIR)/$(RESOURCES)/. $(CURDIR)/$(ROMFS)/
$(BUILD): $(ROMFS)
@[ -d $@ ] || mkdir -p $@
@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(APP_JSON)),)
all : $(OUTPUT).nro
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
else
all : $(OUTPUT).nsp
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
$(OUTPUT).nso : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -0,0 +1 @@
# sys-clk-manager

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -0,0 +1,21 @@
---
AccessModifierOffset: -2
AlignConsecutiveAssignments: 'true'
BasedOnStyle: WebKit
BreakBeforeBraces: Allman
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<borealis/.*\.hpp>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: 'true'
PointerAlignment: Left
SortIncludes: 'true'
Standard: Cpp11
...

View File

@@ -0,0 +1 @@
*.glsl text eol=lf

View File

@@ -0,0 +1,10 @@
.*/
build/
build.nx/
*~
*.bak
*.nro
*.nacp
*.elf
.vscode
builddir

View File

@@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
;
[subrepo]
remote = https://github.com/natinusala/borealis
branch = master
commit = 2ec4957301f702635feac64111dcd212d2a37ec6
parent = ec9981362c84ff6d44bb574f311f1d994dc80d9c
method = rebase
cmdver = 0.4.0

View File

@@ -0,0 +1,17 @@
Copyright (c) 2019 fincs
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@@ -0,0 +1,231 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
TARGET := borealis_example
BUILD := build.nx
SOURCES := example
DATA := data
ICON := resources/icon/borealis.jpg
INCLUDES := example
APP_TITLE := borealis example
APP_AUTHOR := natinusala
APP_VERSION := 1.0
ROMFS := resources
BOREALIS_PATH := .
BOREALIS_RESOURCES := romfs:/
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__ \
-DBOREALIS_RESOURCES="\"$(BOREALIS_RESOURCES)\""
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=c++1z -O2
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
include $(TOPDIR)/library/borealis.mk
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(APP_JSON)),)
all : $(OUTPUT).nro
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
else
all : $(OUTPUT).nsp
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
$(OUTPUT).nso : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -0,0 +1,65 @@
# borealis
Hardware accelerated, Nintendo Switch inspired UI library for PC and Nintendo Switch. Powered by nanovg. Skeleton based on the [hybrid glfw app](https://github.com/fincs/hybrid_app) by fincs.
The library is still in early development and WILL lack features and contain bugs. Feel free to report them in the issues, or make a pull request if you happen to fix some.
You can see the planned features in the Projects tab.
Documentation is available [right here](https://github.com/natinusala/borealis/wiki). Warning: may not be up to date.
## Building the example for Switch
To build for Switch, a standard development environment must first be set up. In order to do so, [refer to the Getting Started guide](https://devkitpro.org/wiki/Getting_Started).
```bash
(sudo) (dkp-)pacman -S switch-glfw switch-mesa switch-glm
make -j
nxlink -s borealis_example.nro
```
## Building the example for PC
To build for PC, the following components are required:
- meson/ninja build system
- A C++ compiler supporting the C++17 standard
- GLFW version 3.3 or higher (as a static library)
- GLM version 0.9.8 or higher
Please refer to the usual sources of information for your particular operating system. Usually the commands needed to build this project will look like this:
```bash
meson build
ninja -C build
./build/borealis_example
```
Also, please note that the `resources` folder must be available in the working directory, otherwise the program will fail to find the shaders.
### Building the example for Windows using msys2
msys2 provides all packages needed to build this project:
```bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-meson mingw-w64-x86_64-ninja mingw-w64-x86_64-pkg-config mingw-w64-x86_64-glfw mingw-w64-x86_64-glm
meson build
ninja -C build
./build/borealis_example
```
### Including in your project (TL;DR: see the example makefile in this repo)
0. Your project must be built as C++17 (`-std=c++1z`). You also need to remove `-fno-rtti` and `-fno-exceptions` if you have them
1. Use a submodule (or even better, a [subrepo](https://github.com/ingydotnet/git-subrepo)) to clone this repository in your project
2. Copy the `resources` folder to the root of your project
3. For PC (meson):
1. take a standard meson file
2. use `subdir` to import the library folder
3. use the `borealis_files`, `borealis_dependencies` and `borealis_include` variables for respectively objects to build, dependencies (glfw...) and includes directory
4. add a `BOREALIS_RESOURCES` define pointing to the resources folder at runtime (so `resources`)
4. For Switch:
1. take a standard homebrew makefile
2. add a `BOREALIS_PATH` variable containing the subfolder you put the library in
3. use `include` to load `borealis.mk` (after `LIBDIRS` and `BOREALIS_PATH`)
4. set `ROMFS` to the resources folder
5. add a `BOREALIS_RESOURCES` define pointing to the resources folder at runtime (so `romfs:/`)

View File

@@ -0,0 +1,171 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <borealis.hpp>
#include <string>
#include "sample_installer_page.hpp"
#include "sample_loading_page.hpp"
std::vector<std::string> NOTIFICATIONS = {
"You have cool hair",
"I like your shoes",
"borealis is powered by nanovg",
"The Triforce is an inside job",
"Pozznx will trigger in one day and twelve hours",
"Aurora Borealis? At this time of day, at this time of year, in this part of the gaming market, located entirely within your Switch?!",
"May I see it?",
"Hmm, Steamed Hams!"
};
int main(int argc, char* argv[])
{
// Init the app
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
if (!brls::Application::init("Borealis example"))
{
brls::Logger::error("Unable to init Borealis application");
return EXIT_FAILURE;
}
// Create a sample view
brls::TabFrame* rootFrame = new brls::TabFrame();
rootFrame->setTitle("Borealis Example App");
rootFrame->setIcon(BOREALIS_ASSET("icon/borealis.jpg"));
brls::List* testList = new brls::List();
brls::ListItem* dialogItem = new brls::ListItem("Open a dialog");
dialogItem->getClickEvent()->subscribe([](brls::View* view) {
brls::Dialog* dialog = new brls::Dialog("Warning: PozzNX will wipe all data on your Switch and render it inoperable, do you want to proceed?");
brls::GenericEvent::Callback closeCallback = [dialog](brls::View* view) {
dialog->close();
brls::Application::notify("Running PozzNX...");
};
dialog->addButton("Continue", closeCallback);
dialog->addButton("Continue", closeCallback);
dialog->addButton("Continue", closeCallback);
dialog->setCancelable(false);
dialog->open();
});
brls::ListItem* notificationItem = new brls::ListItem("Post a random notification");
notificationItem->getClickEvent()->subscribe([](brls::View* view) {
std::string notification = NOTIFICATIONS[std::rand() % NOTIFICATIONS.size()];
brls::Application::notify(notification);
});
brls::ListItem* themeItem = new brls::ListItem("TV Resolution");
themeItem->setValue("Automatic");
brls::SelectListItem* jankItem = new brls::SelectListItem(
"User Interface Jank",
{ "Native", "Minimal", "Regular", "Maximum", "SX OS", "Windows Vista", "iOS 14" });
brls::ListItem* crashItem = new brls::ListItem("Divide by 0", "Can the Switch do it?");
crashItem->getClickEvent()->subscribe([](brls::View* view) { brls::Application::crash("The software was closed because an error occured:\nSIGABRT (signal 6)"); });
brls::ListItem* popupItem = new brls::ListItem("Open popup");
popupItem->getClickEvent()->subscribe([](brls::View* view) {
brls::TabFrame* popupTabFrame = new brls::TabFrame();
popupTabFrame->addTab("Red", new brls::Rectangle(nvgRGB(255, 0, 0)));
popupTabFrame->addTab("Green", new brls::Rectangle(nvgRGB(0, 255, 0)));
popupTabFrame->addTab("Blue", new brls::Rectangle(nvgRGB(0, 0, 255)));
brls::PopupFrame::open("Popup title", BOREALIS_ASSET("icon/borealis.jpg"), popupTabFrame, "Subtitle left", "Subtitle right");
});
brls::ListItem* installerItem = new brls::ListItem("Open example installer");
installerItem->getClickEvent()->subscribe([](brls::View* view) {
brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame();
stagedFrame->setTitle("My great installer");
stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "Go to step 2"));
stagedFrame->addStage(new SampleLoadingPage(stagedFrame));
stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "Finish"));
brls::Application::pushView(stagedFrame);
});
brls::SelectListItem* layerSelectItem = new brls::SelectListItem("Select Layer", { "Layer 1", "Layer 2" });
testList->addView(dialogItem);
testList->addView(notificationItem);
testList->addView(themeItem);
testList->addView(jankItem);
testList->addView(crashItem);
testList->addView(installerItem);
testList->addView(popupItem);
brls::Label* testLabel = new brls::Label(brls::LabelStyle::REGULAR, "For more information about how to use Nintendo Switch and its features, please refer to the Nintendo Support Website on your smart device or PC.", true);
testList->addView(testLabel);
brls::ListItem* actionTestItem = new brls::ListItem("Custom Actions");
actionTestItem->registerAction("Show notification", brls::Key::L, [] {
brls::Application::notify("Custom Action triggered");
return true;
});
testList->addView(actionTestItem);
brls::LayerView* testLayers = new brls::LayerView();
brls::List* layerList1 = new brls::List();
brls::List* layerList2 = new brls::List();
layerList1->addView(new brls::Header("Layer 1", false));
layerList1->addView(new brls::ListItem("Item 1"));
layerList1->addView(new brls::ListItem("Item 2"));
layerList1->addView(new brls::ListItem("Item 3"));
layerList2->addView(new brls::Header("Layer 2", false));
layerList2->addView(new brls::ListItem("Item 1"));
layerList2->addView(new brls::ListItem("Item 2"));
layerList2->addView(new brls::ListItem("Item 3"));
testLayers->addLayer(layerList1);
testLayers->addLayer(layerList2);
layerSelectItem->getValueSelectedEvent()->subscribe([=](size_t selection) {
testLayers->changeLayer(selection);
});
testList->addView(layerSelectItem);
rootFrame->addTab("First tab", testList);
rootFrame->addTab("Second tab", testLayers);
rootFrame->addSeparator();
rootFrame->addTab("Third tab", new brls::Rectangle(nvgRGB(255, 0, 0)));
rootFrame->addTab("Fourth tab", new brls::Rectangle(nvgRGB(0, 255, 0)));
// Add the root view to the stack
brls::Application::pushView(rootFrame);
// Run the app
while (brls::Application::mainLoop())
;
// Exit
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,75 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 Billy Laws
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "sample_installer_page.hpp"
#include <math.h>
SampleInstallerPage::SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label)
{
// Label
this->button = (new brls::Button(brls::ButtonStyle::BORDERLESS))->setLabel(label)->setImage(BOREALIS_ASSET("icon/borealis.jpg"));
this->button->setParent(this);
this->button->getClickEvent()->subscribe([frame](View* view) {
if (frame->isLastStage())
brls::Application::popView();
else
frame->nextStage();
});
this->label = new brls::Label(brls::LabelStyle::DIALOG, "Here, you would normally do useful things", true);
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
this->label->setParent(this);
}
void SampleInstallerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
{
this->label->frame(ctx);
this->button->frame(ctx);
}
brls::View* SampleInstallerPage::getDefaultFocus()
{
return this->button;
}
void SampleInstallerPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
{
this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth));
this->label->invalidate(true);
this->label->setBoundaries(
this->x + this->width / 2 - this->label->getWidth() / 2,
this->y + (this->height - style->AppletFrame.footerHeight) / 2,
this->label->getWidth(),
this->label->getHeight());
this->button->setBoundaries(
this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2,
this->y + this->height / 2 + style->CrashFrame.buttonHeight,
style->CrashFrame.buttonWidth,
style->CrashFrame.buttonHeight);
this->button->invalidate();
}
SampleInstallerPage::~SampleInstallerPage()
{
delete this->label;
delete this->button;
}

View File

@@ -0,0 +1,38 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 Billy Laws
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis.hpp>
class SampleInstallerPage : public brls::View
{
private:
brls::Button* button;
brls::Label* label;
public:
SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label);
~SampleInstallerPage();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override;
brls::View* getDefaultFocus() override;
};

View File

@@ -0,0 +1,80 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 Billy Laws
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "sample_loading_page.hpp"
#include <math.h>
SampleLoadingPage::SampleLoadingPage(brls::StagedAppletFrame* frame)
: frame(frame)
{
// Label
this->progressDisp = new brls::ProgressDisplay();
this->progressDisp->setProgress(this->progressValue, 1000);
this->progressDisp->setParent(this);
this->label = new brls::Label(brls::LabelStyle::DIALOG, "Example loading display", true);
this->label->setHorizontalAlign(NVG_ALIGN_CENTER);
this->label->setParent(this);
}
void SampleLoadingPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx)
{
if (progressValue == 500)
this->frame->nextStage();
this->progressValue++;
this->progressDisp->setProgress(this->progressValue, 500);
this->progressDisp->frame(ctx);
this->label->frame(ctx);
}
void SampleLoadingPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash)
{
this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth));
this->label->invalidate(true);
this->label->setBoundaries(
this->x + this->width / 2 - this->label->getWidth() / 2,
this->y + (this->height - style->AppletFrame.footerHeight) / 2,
this->label->getWidth(),
this->label->getHeight());
this->progressDisp->setBoundaries(
this->x + this->width / 2 - style->CrashFrame.buttonWidth,
this->y + this->height / 2,
style->CrashFrame.buttonWidth * 2,
style->CrashFrame.buttonHeight);
}
void SampleLoadingPage::willAppear(bool resetState)
{
this->progressDisp->willAppear(resetState);
}
void SampleLoadingPage::willDisappear(bool resetState)
{
this->progressDisp->willDisappear(resetState);
}
SampleLoadingPage::~SampleLoadingPage()
{
delete this->progressDisp;
delete this->label;
}

View File

@@ -0,0 +1,42 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 Billy Laws
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis.hpp>
class SampleLoadingPage : public brls::View
{
private:
brls::StagedAppletFrame* frame;
brls::ProgressDisplay* progressDisp;
brls::Label* label;
int progressValue = 0;
public:
SampleLoadingPage(brls::StagedAppletFrame* frame);
~SampleLoadingPage();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override;
void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override;
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
};

View File

@@ -0,0 +1,18 @@
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(BOREALIS_PATH)/$(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
LIBS := -lglfw3 -lEGL -lglapi -ldrm_nouveau -lm $(LIBS)
SOURCES := $(SOURCES) \
$(current_dir)/lib \
$(current_dir)/lib/extern/glad \
$(current_dir)/lib/extern/nanovg \
$(current_dir)/lib/extern/libretro-common/compat \
$(current_dir)/lib/extern/libretro-common/encodings \
$(current_dir)/lib/extern/libretro-common/features
INCLUDES := $(INCLUDES) \
$(current_dir)/include \
$(current_dir)/include/borealis/extern/glad \
$(current_dir)/include/borealis/extern/nanovg \
$(current_dir)/include/borealis/extern/libretro-common

View File

@@ -0,0 +1,56 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef BOREALIS_RESOURCES
#error BOREALIS_RESOURCES define missing
#endif
#define BOREALIS_ASSET(_str) BOREALIS_RESOURCES _str
// Library
#include <borealis/applet_frame.hpp>
#include <borealis/application.hpp>
#include <borealis/box_layout.hpp>
#include <borealis/button.hpp>
#include <borealis/crash_frame.hpp>
#include <borealis/dialog.hpp>
#include <borealis/dropdown.hpp>
#include <borealis/event.hpp>
#include <borealis/header.hpp>
#include <borealis/image.hpp>
#include <borealis/label.hpp>
#include <borealis/layer_view.hpp>
#include <borealis/list.hpp>
#include <borealis/logger.hpp>
#include <borealis/material_icon.hpp>
#include <borealis/notification_manager.hpp>
#include <borealis/popup_frame.hpp>
#include <borealis/progress_display.hpp>
#include <borealis/progress_spinner.hpp>
#include <borealis/rectangle.hpp>
#include <borealis/repeating_task.hpp>
#include <borealis/sidebar.hpp>
#include <borealis/staged_applet_frame.hpp>
#include <borealis/style.hpp>
#include <borealis/tab_frame.hpp>
#include <borealis/table.hpp>
#include <borealis/theme.hpp>
#include <borealis/thumbnail_frame.hpp>
#include <borealis/view.hpp>

View File

@@ -0,0 +1,68 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2020 WerWolv
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <string>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
namespace brls
{
class View;
typedef std::function<bool(void)> ActionListener;
// ZL and ZR do not exist here because GLFW doesn't know them
enum class Key
{
A = GLFW_GAMEPAD_BUTTON_A,
B = GLFW_GAMEPAD_BUTTON_B,
X = GLFW_GAMEPAD_BUTTON_X,
Y = GLFW_GAMEPAD_BUTTON_Y,
LSTICK = GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
RSTICK = GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
L = GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
R = GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
PLUS = GLFW_GAMEPAD_BUTTON_START,
MINUS = GLFW_GAMEPAD_BUTTON_BACK,
DLEFT = GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
DUP = GLFW_GAMEPAD_BUTTON_DPAD_UP,
DRIGHT = GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
DDOWN = GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
};
struct Action
{
Key key;
std::string hintText;
bool available;
bool hidden;
ActionListener actionListener;
bool operator==(const Key other)
{
return this->key == other;
}
};
} // namespace brls

View File

@@ -0,0 +1,178 @@
/* RetroArch - A frontend for libretro.
* Borealis, a Nintendo Switch UI Library
* Copyright (C) 2014-2017 - Jean-André Santoni
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2019 - natinusala
Copyright (C) 2019 - p-sam
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <functional>
namespace brls
{
typedef float (*easing_cb)(float, float, float, float);
typedef std::function<void(void*)> tween_cb;
enum menu_animation_ctl_state
{
MENU_ANIMATION_CTL_NONE = 0,
MENU_ANIMATION_CTL_DEINIT,
MENU_ANIMATION_CTL_CLEAR_ACTIVE,
MENU_ANIMATION_CTL_SET_ACTIVE
};
enum menu_animation_easing_type
{
/* Linear */
EASING_LINEAR = 0,
/* Quad */
EASING_IN_QUAD,
EASING_OUT_QUAD,
EASING_IN_OUT_QUAD,
EASING_OUT_IN_QUAD,
/* Cubic */
EASING_IN_CUBIC,
EASING_OUT_CUBIC,
EASING_IN_OUT_CUBIC,
EASING_OUT_IN_CUBIC,
/* Quart */
EASING_IN_QUART,
EASING_OUT_QUART,
EASING_IN_OUT_QUART,
EASING_OUT_IN_QUART,
/* Quint */
EASING_IN_QUINT,
EASING_OUT_QUINT,
EASING_IN_OUT_QUINT,
EASING_OUT_IN_QUINT,
/* Sine */
EASING_IN_SINE,
EASING_OUT_SINE,
EASING_IN_OUT_SINE,
EASING_OUT_IN_SINE,
/* Expo */
EASING_IN_EXPO,
EASING_OUT_EXPO,
EASING_IN_OUT_EXPO,
EASING_OUT_IN_EXPO,
/* Circ */
EASING_IN_CIRC,
EASING_OUT_CIRC,
EASING_IN_OUT_CIRC,
EASING_OUT_IN_CIRC,
/* Bounce */
EASING_IN_BOUNCE,
EASING_OUT_BOUNCE,
EASING_IN_OUT_BOUNCE,
EASING_OUT_IN_BOUNCE,
EASING_LAST
};
/* TODO:
* Add a reverse loop ticker for languages
* that read right to left */
enum menu_animation_ticker_type
{
TICKER_TYPE_BOUNCE = 0,
TICKER_TYPE_LOOP,
TICKER_TYPE_LAST
};
typedef uintptr_t menu_animation_ctx_tag;
typedef struct menu_animation_ctx_subject
{
size_t count;
const void* data;
} menu_animation_ctx_subject_t;
typedef struct menu_animation_ctx_entry
{
enum menu_animation_easing_type easing_enum;
uintptr_t tag;
float duration;
float target_value;
float* subject;
tween_cb cb;
tween_cb tick;
void* userdata;
} menu_animation_ctx_entry_t;
typedef struct menu_animation_ctx_ticker
{
bool selected;
size_t len;
uint64_t idx;
enum menu_animation_ticker_type type_enum;
char* s;
const char* str;
const char* spacer;
} menu_animation_ctx_ticker_t;
typedef float menu_timer_t;
typedef struct menu_timer_ctx_entry
{
float duration;
tween_cb cb;
tween_cb tick;
void* userdata;
} menu_timer_ctx_entry_t;
typedef struct menu_delayed_animation
{
menu_timer_t timer;
menu_animation_ctx_entry_t entry;
} menu_delayed_animation_t;
void menu_timer_start(menu_timer_t* timer, menu_timer_ctx_entry_t* timer_entry);
void menu_timer_kill(menu_timer_t* timer);
void menu_animation_init(void);
void menu_animation_free(void);
bool menu_animation_update(void);
bool menu_animation_ticker(menu_animation_ctx_ticker_t* ticker);
float menu_animation_get_delta_time(void);
bool menu_animation_is_active(void);
bool menu_animation_kill_by_tag(menu_animation_ctx_tag* tag);
void menu_animation_kill_by_subject(menu_animation_ctx_subject_t* subject);
bool menu_animation_push(menu_animation_ctx_entry_t* entry);
void menu_animation_push_delayed(unsigned delay, menu_animation_ctx_entry_t* entry);
bool menu_animation_ctl(enum menu_animation_ctl_state state, void* data);
uint64_t menu_animation_get_ticker_idx(void);
uint64_t menu_animation_get_ticker_slow_idx(void);
void menu_animation_get_highlight(float* gradient_x, float* gradient_y, float* color);
} // namespace brls

View File

@@ -0,0 +1,94 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/frame_context.hpp>
#include <borealis/hint.hpp>
#include <borealis/image.hpp>
#include <borealis/view.hpp>
#include <string>
namespace brls
{
enum class HeaderStyle
{
REGULAR,
POPUP // Only meant for PopupFrames. Using it in other contexts might cause weird behaviour
};
// A Horizon settings-like frame, with header and footer (no sidebar)
class AppletFrame : public View
{
private:
std::string title = "";
std::string footerText = "";
std::string subTitleLeft = "", subTitleRight = "";
View* icon = nullptr;
Hint* hint = nullptr;
View* contentView = nullptr;
bool slideOut = false;
bool slideIn = false;
ViewAnimation animation;
protected:
HeaderStyle headerStyle = HeaderStyle::REGULAR;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
unsigned leftPadding = 0;
unsigned rightPadding = 0;
public:
AppletFrame(bool padLeft, bool padRight);
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
View* getDefaultFocus() override;
virtual bool onCancel();
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE) override;
void hide(std::function<void(void)> cb, bool animated = true, ViewAnimation animation = ViewAnimation::FADE) override;
void onWindowSizeChanged() override;
void setTitle(std::string title);
void setFooterText(std::string footerText);
void setSubtitle(std::string left, std::string right);
void setIcon(unsigned char* buffer, size_t bufferSize);
void setIcon(std::string imagePath);
void setIcon(View* view);
virtual void setContentView(View* view);
bool hasContentView();
void setHeaderStyle(HeaderStyle headerStyle);
void setAnimateHint(bool animate)
{
this->hint->setAnimate(animate);
}
~AppletFrame();
};
} // namespace brls

View File

@@ -0,0 +1,204 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <nanovg.h>
#include <borealis/animations.hpp>
#include <borealis/frame_context.hpp>
#include <borealis/hint.hpp>
#include <borealis/label.hpp>
#include <borealis/logger.hpp>
#include <borealis/notification_manager.hpp>
#include <borealis/style.hpp>
#include <borealis/task_manager.hpp>
#include <borealis/theme.hpp>
#include <borealis/view.hpp>
#include <map>
#include <vector>
namespace brls
{
// The top-right framerate counter
class FramerateCounter : public Label
{
private:
retro_time_t lastSecond = 0;
unsigned frames = 0;
public:
FramerateCounter();
void frame(FrameContext* ctx) override;
};
class Application
{
public:
//Init with default style and theme (as close to HOS as possible)
static bool init(std::string title);
// Init with given style and theme
static bool init(std::string title, Style style, Theme theme);
static bool mainLoop();
/**
* Pushes a view on this applications's view stack
*
* The view will automatically be resized to take
* the whole screen and layout() will be called
*
* The view will gain focus if applicable
*/
static void pushView(View* view, ViewAnimation animation = ViewAnimation::FADE);
/**
* Pops the last pushed view from the stack
* and gives focus back where it was before
*/
static void popView(
ViewAnimation animation = ViewAnimation::FADE, std::function<void(void)> cb = []() {});
/**
* Gives the focus to the given view
* or clears the focus if given nullptr
*/
static void giveFocus(View* view);
static Style* getStyle();
static void setTheme(Theme theme);
static ThemeValues* getThemeValues();
static ThemeValues* getThemeValuesForVariant(ThemeVariant variant);
static ThemeVariant getThemeVariant();
static int loadFont(const char* fontName, const char* filePath);
static int loadFontFromMemory(const char* fontName, void* data, size_t size, bool freeData);
static int findFont(const char* fontName);
static FontStash* getFontStash();
static void notify(std::string text);
static void onGamepadButtonPressed(char button, bool repeating);
/**
* "Crashes" the app (displays a fullscreen CrashFrame)
*/
static void crash(std::string text);
static void quit();
/**
* Blocks any and all user inputs
*/
static void blockInputs();
/**
* Unblocks inputs after a call to
* blockInputs()
*/
static void unblockInputs();
static NVGcontext* getNVGContext();
static TaskManager* getTaskManager();
static NotificationManager* getNotificationManager();
static void setCommonFooter(std::string footer);
static std::string* getCommonFooter();
static void setDisplayFramerate(bool enabled);
static void toggleFramerateDisplay();
static void setMaximumFPS(unsigned fps);
// public so that the glfw callback can access it
inline static unsigned contentWidth, contentHeight;
inline static float windowScale;
static void resizeFramerateCounter();
static void resizeNotificationManager();
static GenericEvent* getGlobalFocusChangeEvent();
static VoidEvent* getGlobalHintsUpdateEvent();
static View* getCurrentFocus();
static std::string getTitle();
private:
inline static GLFWwindow* window;
inline static NVGcontext* vg;
inline static std::string title;
inline static TaskManager* taskManager;
inline static NotificationManager* notificationManager;
inline static FontStash fontStash;
inline static std::vector<View*> viewStack;
inline static std::vector<View*> focusStack;
inline static unsigned windowWidth, windowHeight;
inline static View* currentFocus;
inline static Theme currentTheme;
inline static ThemeVariant currentThemeVariant;
inline static GLFWgamepadstate oldGamepad;
inline static GLFWgamepadstate gamepad;
inline static Style currentStyle;
inline static unsigned blockInputsTokens = 0; // any value > 0 means inputs are blocked
inline static std::string commonFooter = "";
inline static FramerateCounter* framerateCounter = nullptr;
inline static float frameTime = 0.0f;
inline static View* repetitionOldFocus = nullptr;
inline static GenericEvent globalFocusChangeEvent;
inline static VoidEvent globalHintsUpdateEvent;
static void navigate(FocusDirection direction);
static void onWindowSizeChanged();
static void frame();
static void clear();
static void exit();
/**
* Handles actions for the currently focused view and
* the given button
* Returns true if at least one action has been fired
*/
static bool handleAction(char button);
};
} // namespace brls

View File

@@ -0,0 +1,173 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 WerWolv
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/view.hpp>
#include <vector>
namespace brls
{
enum class BoxLayoutOrientation
{
VERTICAL,
HORIZONTAL
};
// TODO: Implement all gravity options for both orientations
enum class BoxLayoutGravity
{
DEFAULT, // left for horizontal, top for vertical
LEFT,
RIGHT,
TOP,
BOTTOM,
CENTER
};
class BoxLayoutChild
{
public:
View* view;
bool fill; // should the child fill the remaining space?
};
// A basic horizontal or vertical box layout :
// - Children can currently only be stretched to full width (vertical) or height (horizontal)
// - Only works with children with fixed width (horizontal) or height (vertical)
// TODO: More complex alignment and/or stretching parameters to children
class BoxLayout : public View
{
private:
BoxLayoutOrientation orientation;
unsigned spacing = 0;
bool resize = false; // should the view be resized according to children size after a layout?
BoxLayoutGravity gravity = BoxLayoutGravity::DEFAULT;
protected:
std::vector<BoxLayoutChild*> children;
size_t originalDefaultFocus = 0;
size_t defaultFocusedIndex = 0;
bool childFocused = false;
bool rememberFocus = false;
unsigned marginTop = 0;
unsigned marginRight = 0;
unsigned marginBottom = 0;
unsigned marginLeft = 0;
/**
* Should the BoxLayout apply spacing after
* this view?
*/
virtual void customSpacing(View* current, View* next, int* spacing) {}
public:
BoxLayout(BoxLayoutOrientation orientation, size_t defaultFocus = 0);
~BoxLayout();
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
View* getNextFocus(FocusDirection direction, void* parentUserdata) override;
View* getDefaultFocus() override;
void onChildFocusGained(View* child) override;
void onChildFocusLost(View* child) override;
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
void onWindowSizeChanged() override;
/**
* Sets gravity
*/
void setGravity(BoxLayoutGravity gravity);
/**
* Sets spacing between views
*/
void setSpacing(unsigned spacing);
unsigned getSpacing();
/**
* Sets margins around views
* Bottom (vertical) or right (horizontal) are
* only effective if the last child is set to fill
*/
void setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left);
void setMarginBottom(unsigned bottom);
/**
* Adds a view to this box layout
* If fill is set to true, the child will
* fill the remaining space
*/
void addView(View* view, bool fill = false, bool resetState = false);
/**
* Removes the view at specified
* The view will be freed if free
* is set to true (defaults to true)
*
* Warning: this method isn't correctly
* implemented - currently removing a view will
* most likely result in memory corruption
*/
void removeView(int index, bool free = true);
/**
* Removes all views
* from this layout
*/
void clear(bool free = true);
/**
* Returns true if this layout
* doesn't contain any views
*/
bool isEmpty();
bool isChildFocused();
void setFocusedIndex(unsigned index);
size_t getViewsCount();
View* getChild(size_t i);
/**
* If enabled, will force the layout to resize itself
* to match the children size
* Mandatory for using in a ScrollView
*/
void setResize(bool resize);
/**
* Should the default focus be set to the originally focused
* view (until the layout disappears)?
*/
void setRememberFocus(bool rememberFocus);
};
} // namespace brls

View File

@@ -0,0 +1,99 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/image.hpp>
#include <borealis/label.hpp>
#include <borealis/view.hpp>
namespace brls
{
enum class ButtonStyle
{
PLAIN = 0, // regular, plain button
BORDERED, // text and a border
BORDERLESS, // only text
CRASH, // same as borderless but with a different text color
DIALOG // same as borderless but with a different text color
};
enum class ButtonState
{
ENABLED = 0,
DISABLED
};
// A button
class Button : public View
{
private:
ButtonStyle style;
Label* label = nullptr;
Image* image = nullptr;
GenericEvent clickEvent;
LabelStyle getLabelStyle();
ButtonState state = ButtonState::ENABLED;
float cornerRadiusOverride = 0;
public:
Button(ButtonStyle style);
~Button();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
virtual bool onClick();
void layout(NVGcontext* vg, Style* style, FontStash* stash);
void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left) override;
ButtonState getState();
void setState(ButtonState state);
Button* setLabel(std::string label);
Button* setImage(std::string path);
Button* setImage(unsigned char* buffer, size_t bufferSize);
GenericEvent* getClickEvent();
View* getDefaultFocus() override
{
return this;
}
void setCornerRadius(float cornerRadius);
void getHighlightMetrics(Style* style, float* cornerRadius) override
{
if (cornerRadiusOverride)
*cornerRadius = cornerRadiusOverride;
else
*cornerRadius = style->Button.cornerRadius;
}
bool isHighlightBackgroundEnabled() override
{
return false;
}
};
} // namespace brls

View File

@@ -0,0 +1,55 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/button.hpp>
#include <borealis/hint.hpp>
#include <borealis/label.hpp>
#include <borealis/view.hpp>
namespace brls
{
// A screen similar to the "The software has closed" dialog
// pressing OK will exit the app
class CrashFrame : public View
{
private:
Label* label;
Button* button;
Hint* hint;
public:
CrashFrame(std::string text);
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void onShowAnimationEnd() override;
View* getDefaultFocus() override;
bool isTranslucent() override
{
return true; // have it always translucent to disable fade out animation
}
~CrashFrame();
};
} // namespace brls

View File

@@ -0,0 +1,95 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/box_layout.hpp>
#include <borealis/view.hpp>
namespace brls
{
// TODO: Add a "can be cancelled with B" flag
// TODO: Add buttons at creation time
// TODO: Add the blurred dialog type once the blur is finished
class DialogButton
{
public:
std::string label;
GenericEvent::Callback cb;
};
// A modal dialog with zero to three buttons
// and anything as content
// Create the dialog then use open() and close()
class Dialog : public View
{
private:
View* contentView = nullptr;
unsigned frameX, frameY, frameWidth, frameHeight;
std::vector<DialogButton*> buttons;
BoxLayout* verticalButtonsLayout = nullptr;
BoxLayout* horizontalButtonsLayout = nullptr;
void rebuildButtons();
unsigned getButtonsHeight();
bool cancelable = true;
public:
Dialog(std::string text);
Dialog(View* contentView);
~Dialog();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
View* getDefaultFocus() override;
virtual bool onCancel();
/**
* Adds a button to this dialog, with a maximum of three
* The position depends on the add order
*
* Adding a button after the dialog has been opened is
* NOT SUPPORTED
*/
void addButton(std::string label, GenericEvent::Callback cb);
/**
* A cancelable dialog is closed when
* the user presses B (defaults to true)
*
* A dialog without any buttons cannot
* be cancelable
*/
void setCancelable(bool cancelable);
void open();
void close(std::function<void(void)> cb = []() {});
bool isTranslucent() override
{
return true;
}
};
} // namespace brls

View File

@@ -0,0 +1,80 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019-2020 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/event.hpp>
#include <borealis/list.hpp>
#include <borealis/view.hpp>
#include <string>
namespace brls
{
// Fired when the user has selected a value
//
// Parameter is either the selected value index
// or -1 if the user cancelled
//
// Assume that the Dropdown is deleted
// as soon as this function is called
typedef Event<int> ValueSelectedEvent;
// Allows the user to select between multiple
// values
// Use Dropdown::open()
class Dropdown : public View
{
private:
Dropdown(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, size_t selected = 0);
std::string title;
int valuesCount;
ValueSelectedEvent valueEvent;
List* list;
Hint* hint;
float topOffset; // for slide in animation
protected:
unsigned getShowAnimationDuration(ViewAnimation animation) override;
public:
~Dropdown();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
View* getDefaultFocus() override;
virtual bool onCancel();
void show(std::function<void(void)> cb, bool animate = true, ViewAnimation animation = ViewAnimation::FADE) override;
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
static void open(std::string title, std::vector<std::string> values, ValueSelectedEvent::Callback cb, int selected = -1);
bool isTranslucent() override
{
return true || View::isTranslucent();
}
};
} // namespace brls

View File

@@ -0,0 +1,75 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2020 natinusala
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <algorithm>
#include <functional>
#include <list>
namespace brls
{
// Simple observer pattern implementation
//
// Usage:
// 1. typedef your event type
// 2. create as many events as you want using that type
// 3. call subscribe on the events with your observers
// 4. call fire when you want to fire the events
// it wil return true if at least one subscriber exists
// for that event
template <typename... Ts>
class Event
{
public:
typedef std::function<void(Ts...)> Callback;
typedef std::list<Callback> CallbacksList;
typedef typename CallbacksList::iterator Subscription;
Subscription subscribe(Callback cb);
void unsubscribe(Subscription subscription);
bool fire(Ts... args);
private:
CallbacksList callbacks;
};
template <typename... Ts>
typename Event<Ts...>::Subscription Event<Ts...>::subscribe(Event<Ts...>::Callback cb)
{
this->callbacks.push_back(cb);
return --this->callbacks.end();
}
template <typename... Ts>
void Event<Ts...>::unsubscribe(Event<Ts...>::Subscription subscription)
{
this->callbacks.erase(subscription);
}
template <typename... Ts>
bool Event<Ts...>::fire(Ts... args)
{
for (Callback cb : this->callbacks)
cb(args...);
return !this->callbacks.empty();
}
}; // namespace brls

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (boolean.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_BOOLEAN_H
#define __LIBRETRO_SDK_BOOLEAN_H
#ifndef __cplusplus
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include <stdbool.h>
#endif
#endif
#endif

View File

@@ -0,0 +1,59 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (strl.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
#define __LIBRETRO_SDK_COMPAT_STRL_H
#include <string.h>
#include <stddef.h>
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
#include "../../../config.h"
#endif
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
#ifdef __MACH__
#ifndef HAVE_STRL
#define HAVE_STRL
#endif
#endif
#ifndef HAVE_STRL
/* Avoid possible naming collisions during link since
* we prefer to use the actual name. */
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
size_t strlcpy(char *dest, const char *source, size_t size);
size_t strlcat(char *dest, const char *source, size_t size);
#endif
char *strldup(const char *s, size_t n);
RETRO_END_DECLS
#endif

View File

@@ -0,0 +1,67 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (utf.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_ENCODINGS_UTF_H
#define _LIBRETRO_ENCODINGS_UTF_H
#include <stdint.h>
#include <stddef.h>
#include <boolean.h>
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
enum CodePage
{
CODEPAGE_LOCAL = 0, /* CP_ACP */
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
};
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
const char *in, size_t in_size);
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size);
size_t utf8len(const char *string);
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
const char *utf8skip(const char *str, size_t chars);
uint32_t utf8_walk(const char **string);
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
char* utf8_to_local_string_alloc(const char *str);
char* local_to_utf8_string_alloc(const char *str);
wchar_t* utf8_to_utf16_string_alloc(const char *str);
char* utf16_to_utf8_string_alloc(const wchar_t *str);
RETRO_END_DECLS
#endif

View File

@@ -0,0 +1,75 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (features_cpu.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_SDK_CPU_INFO_H
#define _LIBRETRO_SDK_CPU_INFO_H
#include <retro_common_api.h>
#include <stdint.h>
#include <libretro.h>
RETRO_BEGIN_DECLS
/**
* cpu_features_get_perf_counter:
*
* Gets performance counter.
*
* Returns: performance counter.
**/
retro_perf_tick_t cpu_features_get_perf_counter(void);
/**
* cpu_features_get_time_usec:
*
* Gets time in microseconds, from an undefined epoch.
* The epoch may change between computers or across reboots.
*
* Returns: time in microseconds
**/
retro_time_t cpu_features_get_time_usec(void);
/**
* cpu_features_get:
*
* Gets CPU features.
*
* Returns: bitmask of all CPU features available.
**/
uint64_t cpu_features_get(void);
/**
* cpu_features_get_core_amount:
*
* Gets the amount of available CPU cores.
*
* Returns: amount of CPU cores available.
**/
unsigned cpu_features_get_core_amount(void);
void cpu_features_get_model_name(char *name, int len);
RETRO_END_DECLS
#endif

View File

@@ -0,0 +1,37 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_assert.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __RETRO_ASSERT_H
#define __RETRO_ASSERT_H
#include <assert.h>
#ifdef RARCH_INTERNAL
#include <stdio.h>
#define retro_assert(cond) do { \
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
} while(0)
#else
#define retro_assert(cond) assert(cond)
#endif
#endif

View File

@@ -0,0 +1,117 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_common_api.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
/*
This file is designed to normalize the libretro-common compiling environment
for public API headers. This should be leaner than a normal compiling environment,
since it gets #included into other project's sources.
*/
/* ------------------------------------ */
/*
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
headers to enable them to get used by c++ sources.
However, we want to support building this library as C++ as well, so a
special technique is called for.
*/
#define RETRO_BEGIN_DECLS
#define RETRO_END_DECLS
#ifdef __cplusplus
#ifdef CXX_BUILD
/* build wants everything to be built as c++, so no extern "C" */
#else
#undef RETRO_BEGIN_DECLS
#undef RETRO_END_DECLS
#define RETRO_BEGIN_DECLS extern "C" {
#define RETRO_END_DECLS }
#endif
#else
/* header is included by a C source file, so no extern "C" */
#endif
/*
IMO, this non-standard ssize_t should not be used.
However, it's a good example of how to handle something like this.
*/
#ifdef _MSC_VER
#ifndef HAVE_SSIZE_T
#define HAVE_SSIZE_T
#if defined(_WIN64)
typedef __int64 ssize_t;
#elif defined(_WIN32)
typedef int ssize_t;
#endif
#endif
#elif defined(__MACH__)
#include <sys/types.h>
#endif
#ifdef _MSC_VER
#if _MSC_VER >= 1800
#include <inttypes.h>
#else
#ifndef PRId64
#define PRId64 "I64d"
#define PRIu64 "I64u"
#define PRIuPTR "Iu"
#endif
#endif
#else
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
/* https://github.com/libretro/RetroArch/issues/6009 */
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
#ifndef PRId64
#error "inttypes.h is being screwy"
#endif
#define STRING_REP_INT64 "%" PRId64
#define STRING_REP_UINT64 "%" PRIu64
#define STRING_REP_USIZE "%" PRIuPTR
/*
I would like to see retro_inline.h moved in here; possibly boolean too.
rationale: these are used in public APIs, and it is easier to find problems
and write code that works the first time portably when theyre included uniformly
than to do the analysis from scratch each time you think you need it, for each feature.
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
then you should pay the price everywhere, so you can see how much grief it will cause.
Of course, another school of thought is that you should do as little damage as possible
in as few places as possible...
*/
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
#endif

View File

@@ -0,0 +1,39 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_inline.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_INLINE_H
#define __LIBRETRO_SDK_INLINE_H
#ifndef INLINE
#if defined(_WIN32) || defined(__INTEL_COMPILER)
#define INLINE __inline
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
#define INLINE inline
#elif defined(__GNUC__)
#define INLINE __inline__
#else
#define INLINE
#endif
#endif
#endif

View File

@@ -0,0 +1,94 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_math.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _LIBRETRO_COMMON_MATH_H
#define _LIBRETRO_COMMON_MATH_H
#include <stdint.h>
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#include <limits.h>
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>
#ifndef M_PI
#if !defined(USE_MATH_DEFINES)
#define M_PI 3.14159265358979323846264338327
#endif
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/**
* next_pow2:
* @v : initial value
*
* Get next power of 2 value based on initial value.
*
* Returns: next power of 2 value (derived from @v).
**/
static INLINE uint32_t next_pow2(uint32_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
/**
* prev_pow2:
* @v : initial value
*
* Get previous power of 2 value based on initial value.
*
* Returns: previous power of 2 value (derived from @v).
**/
static INLINE uint32_t prev_pow2(uint32_t v)
{
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v - (v >> 1);
}
#endif

View File

@@ -0,0 +1,182 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_miscellaneous.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __RARCH_MISCELLANEOUS_H
#define __RARCH_MISCELLANEOUS_H
#define RARCH_MAX_SUBSYSTEMS 10
#define RARCH_MAX_SUBSYSTEM_ROMS 10
#include <stdint.h>
#include <boolean.h>
#include <retro_inline.h>
#if defined(_WIN32) && !defined(_XBOX)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#if defined(__CELLOS_LV2__)
#include <sys/fs_external.h>
#endif
#include <limits.h>
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
uint32_t i;
for (i = 0; i < count;i++)
a[i] |= b[i];
}
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
{
uint32_t i;
for (i = 0; i < count;i++)
a[i] &= ~b[i];
}
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
{
uint32_t i;
for (i = 0; i < count; i++)
{
if (ptr[i] != 0)
return true;
}
return false;
}
#ifndef PATH_MAX_LENGTH
#if defined(__CELLOS_LV2__)
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
#define PATH_MAX_LENGTH 512
#else
#define PATH_MAX_LENGTH 4096
#endif
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define BITS_GET_ELEM(a, i) ((a).data[i])
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
#define BIT16_CLEAR_ALL(a) ((a) = 0)
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
#define BIT32_CLEAR_ALL(a) ((a) = 0)
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
#define BIT64_CLEAR_ALL(a) ((a) = 0)
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
#define BITS_COPY16_PTR(a,bits) \
{ \
BIT128_CLEAR_ALL_PTR(a); \
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
}
#define BITS_COPY32_PTR(a,bits) \
{ \
BIT128_CLEAR_ALL_PTR(a); \
BITS_GET_ELEM_PTR(a, 0) = (bits); \
}
/* Helper macros and struct to keep track of many booleans. */
/* This struct has 256 bits. */
typedef struct
{
uint32_t data[8];
} retro_bits_t;
#ifdef _WIN32
# ifdef _WIN64
# define PRI_SIZET PRIu64
# else
# if _MSC_VER == 1800
# define PRI_SIZET PRIu32
# else
# define PRI_SIZET "u"
# endif
# endif
#elif PS2
# define PRI_SIZET "u"
#else
# if (SIZE_MAX == 0xFFFF)
# define PRI_SIZET "hu"
# elif (SIZE_MAX == 0xFFFFFFFF)
# define PRI_SIZET "u"
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
# define PRI_SIZET "lu"
# else
# error PRI_SIZET: unknown SIZE_MAX
# endif
#endif
#endif

View File

@@ -0,0 +1,116 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_timers.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_COMMON_TIMERS_H
#define __LIBRETRO_COMMON_TIMERS_H
#include <stdint.h>
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <sys/timer.h>
#elif defined(XENON)
#include <time/time.h>
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
#include <unistd.h>
#elif defined(WIIU)
#include <wiiu/os/thread.h>
#elif defined(PSP)
#include <pspthreadman.h>
#elif defined(VITA)
#include <psp2/kernel/threadmgr.h>
#elif defined(PS2)
#include <SDL/SDL_timer.h>
#elif defined(_3DS)
#include <3ds.h>
#else
#include <time.h>
#endif
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_WIN32) && defined(_XBOX)
#include <Xtl.h>
#endif
#include <limits.h>
#ifdef _MSC_VER
#include <compat/msvc.h>
#endif
#include <retro_inline.h>
#ifdef DJGPP
#define timespec timeval
#define tv_nsec tv_usec
#include <unistd.h>
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
{
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000);
if (rmtp)
rmtp->tv_sec = rmtp->tv_nsec=0;
return 0;
}
#define nanosleep nanosleepDOS
#endif
/**
* retro_sleep:
* @msec : amount in milliseconds to sleep
*
* Sleeps for a specified amount of milliseconds (@msec).
**/
static INLINE void retro_sleep(unsigned msec)
{
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
sys_timer_usleep(1000 * msec);
#elif defined(PSP) || defined(VITA)
sceKernelDelayThread(1000 * msec);
#elif defined(PS2)
SDL_Delay(msec);
#elif defined(_3DS)
svcSleepThread(1000000 * (s64)msec);
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
SleepEx(msec, FALSE);
#elif defined(_WIN32)
Sleep(msec);
#elif defined(XENON)
udelay(1000 * msec);
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
usleep(1000 * msec);
#elif defined(WIIU)
OSSleepTicks(ms_to_ticks(msec));
#else
struct timespec tv = {0};
tv.tv_sec = msec / 1000;
tv.tv_nsec = (msec % 1000) * 1000000;
nanosleep(&tv, NULL);
#endif
}
#endif

View File

@@ -0,0 +1,111 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_stream.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
#define __LIBRETRO_SDK_FILE_STREAM_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/types.h>
#include <libretro.h>
#include <retro_common_api.h>
#include <retro_inline.h>
#include <boolean.h>
#include <stdarg.h>
#define FILESTREAM_REQUIRED_VFS_VERSION 2
RETRO_BEGIN_DECLS
typedef struct RFILE RFILE;
#define FILESTREAM_REQUIRED_VFS_VERSION 2
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
int64_t filestream_get_size(RFILE *stream);
int64_t filestream_truncate(RFILE *stream, int64_t length);
/**
* filestream_open:
* @path : path to file
* @mode : file mode to use when opening (read/write)
* @bufsize : optional buffer size (-1 or 0 to use default)
*
* Opens a file for reading or writing, depending on the requested mode.
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
**/
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints);
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
int64_t filestream_read(RFILE *stream, void *data, int64_t len);
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
int64_t filestream_tell(RFILE *stream);
void filestream_rewind(RFILE *stream);
int filestream_close(RFILE *stream);
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
char *filestream_gets(RFILE *stream, char *s, size_t len);
int filestream_getc(RFILE *stream);
int filestream_scanf(RFILE *stream, const char* format, ...);
int filestream_eof(RFILE *stream);
bool filestream_write_file(const char *path, const void *data, int64_t size);
int filestream_putc(RFILE *stream, int c);
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
int filestream_printf(RFILE *stream, const char* format, ...);
int filestream_error(RFILE *stream);
int filestream_flush(RFILE *stream);
int filestream_delete(const char *path);
int filestream_rename(const char *old_path, const char *new_path);
const char *filestream_get_path(RFILE *stream);
bool filestream_exists(const char *path);
char *filestream_getline(RFILE *stream);
RETRO_END_DECLS
#endif

View File

@@ -0,0 +1,134 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (stdstring.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_STDSTRING_H
#define __LIBRETRO_SDK_STDSTRING_H
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <boolean.h>
#include <retro_common_api.h>
#include <retro_inline.h>
#include <compat/strl.h>
RETRO_BEGIN_DECLS
static INLINE bool string_is_empty(const char *data)
{
return !data || (*data == '\0');
}
static INLINE bool string_is_equal(const char *a, const char *b)
{
return (a && b) ? !strcmp(a, b) : false;
}
#define STRLEN_CONST(x) ((sizeof((x))-1))
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
#define string_add_pair_open(s, size) strlcat((s), " (", (size))
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
#define string_add_bracket_close(s, size) strlcat((s), "}", (size))
#define string_add_single_quote(s, size) strlcat((s), "'", (size))
#define string_add_quote(s, size) strlcat((s), "\"", (size))
#define string_add_colon(s, size) strlcat((s), ":", (size))
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
#define string_add_glob_close(s, size) strlcat((s), "*')", (size))
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
static INLINE void string_add_between_pairs(char *s, const char *str,
size_t size)
{
string_add_pair_open(s, size);
strlcat(s, str, size);
string_add_pair_close(s, size);
}
static INLINE bool string_is_equal_case_insensitive(const char *a,
const char *b)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)a;
const unsigned char *p2 = (const unsigned char*)b;
if (!a || !b)
return false;
if (p1 == p2)
return true;
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
if (*p1++ == '\0')
break;
return (result == 0);
}
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
{
int result = 0;
const unsigned char *p1 = (const unsigned char*)a;
const unsigned char *p2 = (const unsigned char*)b;
if (!a || !b)
return false;
if (p1 == p2)
return false;
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
if (*p1++ == '\0')
break;
return (result == 0);
}
char *string_to_upper(char *s);
char *string_to_lower(char *s);
char *string_ucwords(char *s);
char *string_replace_substring(const char *in, const char *pattern,
const char *by);
/* Remove leading whitespaces */
char *string_trim_whitespace_left(char *const s);
/* Remove trailing whitespaces */
char *string_trim_whitespace_right(char *const s);
/* Remove leading and trailing whitespaces */
char *string_trim_whitespace(char *const s);
/* max_lines == 0 means no limit */
char *word_wrap(char *buffer, const char *string,
int line_width, bool unicode, unsigned max_lines);
RETRO_END_DECLS
#endif

View File

@@ -0,0 +1,18 @@
Copyright (c) 2013 Mikko Mononen memon@inside.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,685 @@
//
// Copyright (c) 2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef NANOVG_H
#define NANOVG_H
#ifdef __cplusplus
extern "C" {
#endif
#define NVG_PI 3.14159265358979323846264338327f
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
#endif
typedef struct NVGcontext NVGcontext;
struct NVGcolor {
union {
float rgba[4];
struct {
float r,g,b,a;
};
};
};
typedef struct NVGcolor NVGcolor;
struct NVGpaint {
float xform[6];
float extent[2];
float radius;
float feather;
NVGcolor innerColor;
NVGcolor outerColor;
int image;
};
typedef struct NVGpaint NVGpaint;
enum NVGwinding {
NVG_CCW = 1, // Winding for solid shapes
NVG_CW = 2, // Winding for holes
};
enum NVGsolidity {
NVG_SOLID = 1, // CCW
NVG_HOLE = 2, // CW
};
enum NVGlineCap {
NVG_BUTT,
NVG_ROUND,
NVG_SQUARE,
NVG_BEVEL,
NVG_MITER,
};
enum NVGalign {
// Horizontal align
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left.
NVG_ALIGN_CENTER = 1<<1, // Align text horizontally to center.
NVG_ALIGN_RIGHT = 1<<2, // Align text horizontally to right.
// Vertical align
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top.
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle.
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom.
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline.
};
enum NVGblendFactor {
NVG_ZERO = 1<<0,
NVG_ONE = 1<<1,
NVG_SRC_COLOR = 1<<2,
NVG_ONE_MINUS_SRC_COLOR = 1<<3,
NVG_DST_COLOR = 1<<4,
NVG_ONE_MINUS_DST_COLOR = 1<<5,
NVG_SRC_ALPHA = 1<<6,
NVG_ONE_MINUS_SRC_ALPHA = 1<<7,
NVG_DST_ALPHA = 1<<8,
NVG_ONE_MINUS_DST_ALPHA = 1<<9,
NVG_SRC_ALPHA_SATURATE = 1<<10,
};
enum NVGcompositeOperation {
NVG_SOURCE_OVER,
NVG_SOURCE_IN,
NVG_SOURCE_OUT,
NVG_ATOP,
NVG_DESTINATION_OVER,
NVG_DESTINATION_IN,
NVG_DESTINATION_OUT,
NVG_DESTINATION_ATOP,
NVG_LIGHTER,
NVG_COPY,
NVG_XOR,
};
struct NVGcompositeOperationState {
int srcRGB;
int dstRGB;
int srcAlpha;
int dstAlpha;
};
typedef struct NVGcompositeOperationState NVGcompositeOperationState;
struct NVGglyphPosition {
const char* str; // Position of the glyph in the input string.
float x; // The x-coordinate of the logical glyph position.
float minx, maxx; // The bounds of the glyph shape.
};
typedef struct NVGglyphPosition NVGglyphPosition;
struct NVGtextRow {
const char* start; // Pointer to the input text where the row starts.
const char* end; // Pointer to the input text where the row ends (one past the last character).
const char* next; // Pointer to the beginning of the next row.
float width; // Logical width of the row.
float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending.
};
typedef struct NVGtextRow NVGtextRow;
enum NVGimageFlags {
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image.
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction.
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction.
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered.
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear
};
// Begin drawing a new frame
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame()
// nvgBeginFrame() defines the size of the window to render to in relation currently
// set viewport (i.e. glViewport on GL backends). Device pixel ration allows to
// control the rendering on Hi-DPI devices.
// For example, GLFW returns two dimension for an opened window: window size and
// frame buffer size. In that case you would set windowWidth/Height to the window size
// devicePixelRatio to: frameBufferWidth / windowWidth.
void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio);
// Cancels drawing the current frame.
void nvgCancelFrame(NVGcontext* ctx);
// Ends drawing flushing remaining render state.
void nvgEndFrame(NVGcontext* ctx);
//
// Composite operation
//
// The composite operations in NanoVG are modeled after HTML Canvas API, and
// the blend func is based on OpenGL (see corresponding manuals for more info).
// The colors in the blending state have premultiplied alpha.
// Sets the composite operation. The op parameter should be one of NVGcompositeOperation.
void nvgGlobalCompositeOperation(NVGcontext* ctx, int op);
// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor);
// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor.
void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
//
// Color utils
//
// Colors in NanoVG are stored as unsigned ints in ABGR format.
// Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f).
NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b);
// Returns a color value from red, green, blue values. Alpha will be set to 1.0f.
NVGcolor nvgRGBf(float r, float g, float b);
// Returns a color value from red, green, blue and alpha values.
NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
// Returns a color value from red, green, blue and alpha values.
NVGcolor nvgRGBAf(float r, float g, float b, float a);
// Linearly interpolates from color c0 to c1, and returns resulting color value.
NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u);
// Sets transparency of a color value.
NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a);
// Sets transparency of a color value.
NVGcolor nvgTransRGBAf(NVGcolor c0, float a);
// Returns color value specified by hue, saturation and lightness.
// HSL values are all in range [0..1], alpha will be set to 255.
NVGcolor nvgHSL(float h, float s, float l);
// Returns color value specified by hue, saturation and lightness and alpha.
// HSL values are all in range [0..1], alpha in range [0..255]
NVGcolor nvgHSLA(float h, float s, float l, unsigned char a);
//
// State Handling
//
// NanoVG contains state which represents how paths will be rendered.
// The state contains transform, fill and stroke styles, text and font styles,
// and scissor clipping.
// Pushes and saves the current render state into a state stack.
// A matching nvgRestore() must be used to restore the state.
void nvgSave(NVGcontext* ctx);
// Pops and restores current render state.
void nvgRestore(NVGcontext* ctx);
// Resets current render state to default values. Does not affect the render state stack.
void nvgReset(NVGcontext* ctx);
//
// Render styles
//
// Fill and stroke render style can be either a solid color or a paint which is a gradient or a pattern.
// Solid color is simply defined as a color value, different kinds of paints can be created
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern().
//
// Current render style can be saved and restored using nvgSave() and nvgRestore().
// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.
void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);
// Sets current stroke style to a solid color.
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color);
// Sets current stroke style to a paint, which can be a one of the gradients or a pattern.
void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint);
// Sets current fill style to a solid color.
void nvgFillColor(NVGcontext* ctx, NVGcolor color);
// Sets current fill style to a paint, which can be a one of the gradients or a pattern.
void nvgFillPaint(NVGcontext* ctx, NVGpaint paint);
// Sets the miter limit of the stroke style.
// Miter limit controls when a sharp corner is beveled.
void nvgMiterLimit(NVGcontext* ctx, float limit);
// Sets the stroke width of the stroke style.
void nvgStrokeWidth(NVGcontext* ctx, float size);
// Sets how the end of the line (cap) is drawn,
// Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE.
void nvgLineCap(NVGcontext* ctx, int cap);
// Sets how sharp path corners are drawn.
// Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL.
void nvgLineJoin(NVGcontext* ctx, int join);
// Sets the transparency applied to all rendered shapes.
// Already transparent paths will get proportionally more transparent as well.
void nvgGlobalAlpha(NVGcontext* ctx, float alpha);
//
// Transforms
//
// The paths, gradients, patterns and scissor region are transformed by an transformation
// matrix at the time when they are passed to the API.
// The current transformation matrix is a affine matrix:
// [sx kx tx]
// [ky sy ty]
// [ 0 0 1]
// Where: sx,sy define scaling, kx,ky skewing, and tx,ty translation.
// The last row is assumed to be 0,0,1 and is not stored.
//
// Apart from nvgResetTransform(), each transformation function first creates
// specific transformation matrix and pre-multiplies the current transformation by it.
//
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore().
// Resets current transform to a identity matrix.
void nvgResetTransform(NVGcontext* ctx);
// Premultiplies current coordinate system by specified matrix.
// The parameters are interpreted as matrix as follows:
// [a c e]
// [b d f]
// [0 0 1]
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f);
// Translates current coordinate system.
void nvgTranslate(NVGcontext* ctx, float x, float y);
// Rotates current coordinate system. Angle is specified in radians.
void nvgRotate(NVGcontext* ctx, float angle);
// Skews the current coordinate system along X axis. Angle is specified in radians.
void nvgSkewX(NVGcontext* ctx, float angle);
// Skews the current coordinate system along Y axis. Angle is specified in radians.
void nvgSkewY(NVGcontext* ctx, float angle);
// Scales the current coordinate system.
void nvgScale(NVGcontext* ctx, float x, float y);
// Stores the top part (a-f) of the current transformation matrix in to the specified buffer.
// [a c e]
// [b d f]
// [0 0 1]
// There should be space for 6 floats in the return buffer for the values a-f.
void nvgCurrentTransform(NVGcontext* ctx, float* xform);
// The following functions can be used to make calculations on 2x3 transformation matrices.
// A 2x3 matrix is represented as float[6].
// Sets the transform to identity matrix.
void nvgTransformIdentity(float* dst);
// Sets the transform to translation matrix matrix.
void nvgTransformTranslate(float* dst, float tx, float ty);
// Sets the transform to scale matrix.
void nvgTransformScale(float* dst, float sx, float sy);
// Sets the transform to rotate matrix. Angle is specified in radians.
void nvgTransformRotate(float* dst, float a);
// Sets the transform to skew-x matrix. Angle is specified in radians.
void nvgTransformSkewX(float* dst, float a);
// Sets the transform to skew-y matrix. Angle is specified in radians.
void nvgTransformSkewY(float* dst, float a);
// Sets the transform to the result of multiplication of two transforms, of A = A*B.
void nvgTransformMultiply(float* dst, const float* src);
// Sets the transform to the result of multiplication of two transforms, of A = B*A.
void nvgTransformPremultiply(float* dst, const float* src);
// Sets the destination to inverse of specified transform.
// Returns 1 if the inverse could be calculated, else 0.
int nvgTransformInverse(float* dst, const float* src);
// Transform a point by given transform.
void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy);
// Converts degrees to radians and vice versa.
float nvgDegToRad(float deg);
float nvgRadToDeg(float rad);
//
// Images
//
// NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering.
// In addition you can upload your own image. The image loading is provided by stb_image.
// The parameter imageFlags is combination of flags defined in NVGimageFlags.
// Creates image by loading it from the disk from specified file name.
// Returns handle to the image.
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags);
// Creates image by loading it from the specified chunk of memory.
// Returns handle to the image.
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata);
// Creates image from specified image data.
// Returns handle to the image.
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
// Updates image data specified by image handle.
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data);
// Returns the dimensions of a created image.
void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h);
// Deletes created image.
void nvgDeleteImage(NVGcontext* ctx, int image);
//
// Paints
//
// NanoVG supports four types of paints: linear gradient, box gradient, radial gradient and image pattern.
// These can be used as paints for strokes and fills.
// Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates
// of the linear gradient, icol specifies the start color and ocol the end color.
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
NVGcolor icol, NVGcolor ocol);
// Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering
// drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle,
// (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry
// the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient.
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h,
float r, float f, NVGcolor icol, NVGcolor ocol);
// Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify
// the inner and outer radius of the gradient, icol specifies the start color and ocol the end color.
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr,
NVGcolor icol, NVGcolor ocol);
// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern,
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render.
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint().
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey,
float angle, int image, float alpha);
//
// Scissoring
//
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various
// user interface cases like rendering a text edit or a timeline.
// Sets the current scissor rectangle.
// The scissor rectangle is transformed by the current transform.
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h);
// Intersects current scissor rectangle with the specified rectangle.
// The scissor rectangle is transformed by the current transform.
// Note: in case the rotation of previous scissor rect differs from
// the current one, the intersection will be done between the specified
// rectangle and the previous scissor rectangle transformed in the current
// transform space. The resulting shape is always rectangle.
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h);
// Reset and disables scissoring.
void nvgResetScissor(NVGcontext* ctx);
//
// Paths
//
// Drawing a new shape starts with nvgBeginPath(), it clears all the currently defined paths.
// Then you define one or more paths and sub-paths which describe the shape. The are functions
// to draw common shapes like rectangles and circles, and lower level step-by-step functions,
// which allow to define a path curve by curve.
//
// NanoVG uses even-odd fill rule to draw the shapes. Solid shapes should have counter clockwise
// winding and holes should have counter clockwise order. To specify winding of a path you can
// call nvgPathWinding(). This is useful especially for the common shapes, which are drawn CCW.
//
// Finally you can fill the path using current fill style by calling nvgFill(), and stroke it
// with current stroke style by calling nvgStroke().
//
// The curve segments and sub-paths are transformed by the current transform.
// Clears the current path and sub-paths.
void nvgBeginPath(NVGcontext* ctx);
// Starts new sub-path with specified point as first point.
void nvgMoveTo(NVGcontext* ctx, float x, float y);
// Adds line segment from the last point in the path to the specified point.
void nvgLineTo(NVGcontext* ctx, float x, float y);
// Adds cubic bezier segment from last point in the path via two control points to the specified point.
void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y);
// Adds quadratic bezier segment from last point in the path via a control point to the specified point.
void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y);
// Adds an arc segment at the corner defined by the last path point, and two specified points.
void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius);
// Closes current sub-path with a line segment.
void nvgClosePath(NVGcontext* ctx);
// Sets the current sub-path winding, see NVGwinding and NVGsolidity.
void nvgPathWinding(NVGcontext* ctx, int dir);
// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r,
// and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW).
// Angles are specified in radians.
void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir);
// Creates new rectangle shaped sub-path.
void nvgRect(NVGcontext* ctx, float x, float y, float w, float h);
// Creates new rounded rectangle shaped sub-path.
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r);
// Creates new rounded rectangle shaped sub-path with varying radii for each corner.
void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
// Creates new ellipse shaped sub-path.
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry);
// Creates new circle shaped sub-path.
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r);
// Fills the current path with current fill style.
void nvgFill(NVGcontext* ctx);
// Fills the current path with current stroke style.
void nvgStroke(NVGcontext* ctx);
//
// Text
//
// NanoVG allows you to load .ttf files and use the font to render text.
//
// The appearance of the text can be defined by setting the current text style
// and by specifying the fill color. Common text and font settings such as
// font size, letter spacing and text align are supported. Font blur allows you
// to create simple text effects such as drop shadows.
//
// At render time the font face can be set based on the font handles or name.
//
// Font measure functions return values in local space, the calculations are
// carried in the same resolution as the final rendering. This is done because
// the text glyph positions are snapped to the nearest pixels sharp rendering.
//
// The local space means that values are not rotated or scale as per the current
// transformation. For example if you set font size to 12, which would mean that
// line height is 16, then regardless of the current scaling and rotation, the
// returned line height is always 16. Some measures may vary because of the scaling
// since aforementioned pixel snapping.
//
// While this may sound a little odd, the setup allows you to always render the
// same way regardless of scaling. I.e. following works regardless of scaling:
//
// const char* txt = "Text me up.";
// nvgTextBounds(vg, x,y, txt, NULL, bounds);
// nvgBeginPath(vg);
// nvgRoundedRect(vg, bounds[0],bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]);
// nvgFill(vg);
//
// Note: currently only solid color fill is supported for text.
// Creates font by loading it from the disk from specified file name.
// Returns handle to the font.
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename);
// Creates font by loading it from the specified memory chunk.
// Returns handle to the font.
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData);
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found.
int nvgFindFont(NVGcontext* ctx, const char* name);
// Adds a fallback font by handle.
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont);
// Adds a fallback font by name.
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont);
// Sets the font size of current text style.
void nvgFontSize(NVGcontext* ctx, float size);
// Sets the blur of current text style.
void nvgFontBlur(NVGcontext* ctx, float blur);
// Sets the letter spacing of current text style.
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing);
// Sets the proportional line height of current text style. The line height is specified as multiple of font size.
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight);
// Sets the text align of current text style, see NVGalign for options.
void nvgTextAlign(NVGcontext* ctx, int align);
// Sets the font face based on specified id of current text style.
void nvgFontFaceId(NVGcontext* ctx, int font);
// Sets the font face based on specified name of current text style.
void nvgFontFace(NVGcontext* ctx, const char* font);
// Draws text string at specified location. If end is specified only the sub-string up to the end is drawn.
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end);
// Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn.
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end);
// Measures the specified text string. Parameter bounds should be a pointer to float[4],
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
// Returns the horizontal advance of the measured text (i.e. where the next character should drawn).
// Measured values are returned in local coordinate space.
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds);
// Measures the specified multi-text string. Parameter bounds should be a pointer to float[4],
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax]
// Measured values are returned in local coordinate space.
void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds);
// Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used.
// Measured values are returned in local coordinate space.
int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions);
// Returns the vertical metrics based on the current text style.
// Measured values are returned in local coordinate space.
void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh);
// Breaks the specified text into lines. If end is specified only the sub-string will be used.
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered.
// Words longer than the max width are slit at nearest character (i.e. no hyphenation).
int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows);
//
// Internal Render API
//
enum NVGtexture {
NVG_TEXTURE_ALPHA = 0x01,
NVG_TEXTURE_RGBA = 0x02,
};
struct NVGscissor {
float xform[6];
float extent[2];
};
typedef struct NVGscissor NVGscissor;
struct NVGvertex {
float x,y,u,v;
};
typedef struct NVGvertex NVGvertex;
struct NVGpath {
int first;
int count;
unsigned char closed;
int nbevel;
NVGvertex* fill;
int nfill;
NVGvertex* stroke;
int nstroke;
int winding;
int convex;
};
typedef struct NVGpath NVGpath;
struct NVGparams {
void* userPtr;
int edgeAntiAlias;
int (*renderCreate)(void* uptr);
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data);
int (*renderDeleteTexture)(void* uptr, int image);
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data);
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h);
void (*renderViewport)(void* uptr, float width, float height, float devicePixelRatio);
void (*renderCancel)(void* uptr);
void (*renderFlush)(void* uptr);
void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts);
void (*renderDelete)(void* uptr);
};
typedef struct NVGparams NVGparams;
// Constructor and destructor, called by the render back-end.
NVGcontext* nvgCreateInternal(NVGparams* params);
void nvgDeleteInternal(NVGcontext* ctx);
NVGparams* nvgInternalParams(NVGcontext* ctx);
// Debug function to dump cached path data.
void nvgDebugDumpPathCache(NVGcontext* ctx);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; }
#ifdef __cplusplus
}
#endif
#endif // NANOVG_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
//
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef NANOVG_GL_UTILS_H
#define NANOVG_GL_UTILS_H
struct NVGLUframebuffer {
NVGcontext* ctx;
GLuint fbo;
GLuint rbo;
GLuint texture;
int image;
};
typedef struct NVGLUframebuffer NVGLUframebuffer;
// Helper function to create GL frame buffer to render to.
void nvgluBindFramebuffer(NVGLUframebuffer* fb);
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags);
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb);
#endif // NANOVG_GL_UTILS_H
#ifdef NANOVG_GL_IMPLEMENTATION
#if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
// FBO is core in OpenGL 3>.
# define NANOVG_FBO_VALID 1
#elif defined(NANOVG_GL2)
// On OS X including glext defines FBO on GL2 too.
# ifdef __APPLE__
# include <OpenGL/glext.h>
# define NANOVG_FBO_VALID 1
# endif
#endif
static GLint defaultFBO = -1;
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags)
{
#ifdef NANOVG_FBO_VALID
GLint defaultFBO;
GLint defaultRBO;
NVGLUframebuffer* fb = NULL;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO);
fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer));
if (fb == NULL) goto error;
memset(fb, 0, sizeof(NVGLUframebuffer));
fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL);
#if defined NANOVG_GL2
fb->texture = nvglImageHandleGL2(ctx, fb->image);
#elif defined NANOVG_GL3
fb->texture = nvglImageHandleGL3(ctx, fb->image);
#elif defined NANOVG_GLES2
fb->texture = nvglImageHandleGLES2(ctx, fb->image);
#elif defined NANOVG_GLES3
fb->texture = nvglImageHandleGLES3(ctx, fb->image);
#endif
fb->ctx = ctx;
// frame buffer object
glGenFramebuffers(1, &fb->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo);
// render buffer object
glGenRenderbuffers(1, &fb->rbo);
glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h);
// combine all
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
#ifdef GL_DEPTH24_STENCIL8
// If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback.
// Some graphics cards require a depth buffer along with a stencil.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
#endif // GL_DEPTH24_STENCIL8
goto error;
}
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
return fb;
error:
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO);
nvgluDeleteFramebuffer(fb);
return NULL;
#else
NVG_NOTUSED(ctx);
NVG_NOTUSED(w);
NVG_NOTUSED(h);
NVG_NOTUSED(imageFlags);
return NULL;
#endif
}
void nvgluBindFramebuffer(NVGLUframebuffer* fb)
{
#ifdef NANOVG_FBO_VALID
if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO);
#else
NVG_NOTUSED(fb);
#endif
}
void nvgluDeleteFramebuffer(NVGLUframebuffer* fb)
{
#ifdef NANOVG_FBO_VALID
if (fb == NULL) return;
if (fb->fbo != 0)
glDeleteFramebuffers(1, &fb->fbo);
if (fb->rbo != 0)
glDeleteRenderbuffers(1, &fb->rbo);
if (fb->image >= 0)
nvgDeleteImage(fb->ctx, fb->image);
fb->ctx = NULL;
fb->fbo = 0;
fb->rbo = 0;
fb->texture = 0;
fb->image = -1;
free(fb);
#else
NVG_NOTUSED(fb);
#endif
}
#endif // NANOVG_GL_IMPLEMENTATION

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <nanovg.h>
#include <borealis/style.hpp>
#include <borealis/theme.hpp>
namespace brls
{
class FontStash
{
public:
int regular = 0;
int korean = 0;
int material = 0;
int sharedSymbols = 0;
};
class FrameContext
{
public:
NVGcontext* vg = nullptr;
float pixelRatio = 0.0;
FontStash* fontStash = nullptr;
ThemeValues* theme = nullptr;
};
} // namespace brls

View File

@@ -0,0 +1,42 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/view.hpp>
namespace brls
{
// A simple header with text, a rectangle on the left
// and a separator
class Header : public View
{
private:
std::string label;
std::string sublabel;
bool separator;
public:
Header(std::string label, bool separator = true, std::string sublabel = "");
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
};
} // namespace brls

View File

@@ -0,0 +1,63 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2020 WerWolv
Copyright (C) 2020 natinusala
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/box_layout.hpp>
#include <borealis/label.hpp>
#include <borealis/view.hpp>
namespace brls
{
// Displays button hints for the currently focused view
// Depending on the view's available actions
// there can only be one Hint visible at any time
class Hint : public BoxLayout
{
private:
bool animate;
GenericEvent::Subscription globalFocusEventSubscriptor;
VoidEvent::Subscription globalHintsUpdateEventSubscriptor;
static inline std::vector<Hint*> globalHintStack;
static void pushHint(Hint* hint);
static void popHint(Hint* hint);
static void animateHints();
static std::string getKeyIcon(Key key);
void rebuildHints();
public:
Hint(bool animate = true);
~Hint();
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
void setAnimate(bool animate)
{
this->animate = animate;
}
};
} // namespace brls

View File

@@ -0,0 +1,78 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 WerWolv
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/frame_context.hpp>
#include <borealis/view.hpp>
namespace brls
{
enum class ImageScaleType
{
NO_RESIZE = 0, // Nothing is resized
FIT, // The image is shrinked to fit the view boundaries
CROP, // The image is not resized but is cropped if bigger than the view
SCALE, // The image is stretched to match the view boundaries
VIEW_RESIZE // The view is resized to match the image
};
// An image
class Image : public View
{
public:
Image(std::string imagePath);
Image(unsigned char* buffer, size_t bufferSize);
~Image();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void setImage(unsigned char* buffer, size_t bufferSize);
void setImage(std::string imagePath);
void setScaleType(ImageScaleType imageScaleType);
void setOpacity(float opacity);
void setCornerRadius(float radius)
{
this->cornerRadius = radius;
}
private:
std::string imagePath;
unsigned char* imageBuffer = nullptr;
size_t imageBufferSize = 0;
int texture = -1;
NVGpaint imgPaint;
ImageScaleType imageScaleType = ImageScaleType::FIT;
float cornerRadius = 0;
int imageX = 0, imageY = 0;
int imageWidth = 0, imageHeight = 0;
int origViewWidth = 0, origViewHeight = 0;
void reloadTexture();
};
} // namespace brls

View File

@@ -0,0 +1,112 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/view.hpp>
namespace brls
{
enum class LabelStyle
{
REGULAR = 0,
MEDIUM,
SMALL,
DESCRIPTION,
CRASH,
BUTTON_PLAIN,
BUTTON_PLAIN_DISABLED,
BUTTON_BORDERLESS,
LIST_ITEM,
NOTIFICATION,
DIALOG,
BUTTON_DIALOG,
HINT
};
// A Label, multiline or with a ticker
class Label : public View
{
private:
std::string text;
bool multiline;
unsigned fontSize;
float lineHeight;
LabelStyle labelStyle;
NVGalign horizontalAlign = NVG_ALIGN_LEFT;
NVGalign verticalAlign = NVG_ALIGN_MIDDLE;
NVGcolor customColor;
bool useCustomColor = false;
int customFont;
bool useCustomFont = false;
public:
Label(LabelStyle labelStyle, std::string text, bool multiline = false);
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void setVerticalAlign(NVGalign align);
void setHorizontalAlign(NVGalign align);
void setText(std::string text);
void setStyle(LabelStyle style);
void setFontSize(unsigned size);
/**
* Sets the label color
*/
void setColor(NVGcolor color);
/**
* Unsets the label color - it
* will now use the default one
* for the label style
*/
void unsetColor();
/**
* Returns the effective label color
* = custom or the style default
*/
NVGcolor getColor(ThemeValues* theme);
/**
* Sets the font id
*/
void setFont(int fontId);
/**
* Unsets the font id - it
* will now use the regular one
*/
void unsetFont();
/**
* Returns the font used
* = custom or the regular font
*/
int getFont(FontStash* stash);
};
} // namespace brls

View File

@@ -0,0 +1,51 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 WerWolv
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/view.hpp>
#include <vector>
namespace brls
{
// A view containing multiple children views with the ability to freely switch between these layers
class LayerView : public View
{
public:
LayerView();
~LayerView();
void addLayer(View* view);
void changeLayer(int index, bool focus = false);
int getLayerIndex();
View* getDefaultFocus() override;
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
private:
std::vector<View*> layers;
int selectedIndex = 0;
};
}

View File

@@ -0,0 +1,217 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019-2020 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/box_layout.hpp>
#include <borealis/image.hpp>
#include <borealis/label.hpp>
#include <borealis/rectangle.hpp>
#include <borealis/scroll_view.hpp>
#include <string>
namespace brls
{
// A list item
// TODO: Use a Label with integrated ticker
class ListItem : public View
{
private:
std::string label;
std::string subLabel;
std::string value;
bool valueFaint;
std::string oldValue;
bool oldValueFaint;
float valueAnimation = 0.0f;
bool checked = false; // check mark on the right
unsigned textSize;
bool drawTopSeparator = true;
Label* descriptionView = nullptr;
Image* thumbnailView = nullptr;
bool reduceDescriptionSpacing = false;
GenericEvent clickEvent;
bool indented = false;
void resetValueAnimation();
public:
ListItem(std::string label, std::string description = "", std::string subLabel = "");
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void getHighlightInsets(unsigned* top, unsigned* right, unsigned* bottom, unsigned* left) override;
virtual bool onClick();
View* getDefaultFocus() override;
void setThumbnail(Image* image);
void setThumbnail(std::string imagePath);
void setThumbnail(unsigned char* buffer, size_t bufferSize);
bool hasDescription();
void setDrawTopSeparator(bool draw);
bool getReduceDescriptionSpacing();
void setReduceDescriptionSpacing(bool value);
void setIndented(bool indented);
void setTextSize(unsigned textSize);
void setChecked(bool checked);
std::string getLabel();
/**
* Sets the value of this list item
* (the text on the right)
* Set faint to true to have the new value
* use a darker color (typically "OFF" labels)
*/
void setValue(std::string value, bool faint = false, bool animate = true);
std::string getValue();
GenericEvent* getClickEvent();
~ListItem();
};
// Some spacing (to make groups of ListItems)
class ListItemGroupSpacing : public Rectangle
{
public:
ListItemGroupSpacing(bool separator = false);
};
// A list item with mutliple choices for its value
// (will open a Dropdown)
// Fired when the user has selected a value
//
// Parameter is either the selected value index
// or -1 if the user cancelled
typedef Event<int> ValueSelectedEvent;
class SelectListItem : public ListItem
{
public:
SelectListItem(std::string label, std::vector<std::string> values, unsigned selectedValue = 0);
void setSelectedValue(unsigned value);
ValueSelectedEvent* getValueSelectedEvent();
private:
std::vector<std::string> values;
unsigned selectedValue;
ValueSelectedEvent valueEvent;
};
// A list item with a ON/OFF value
// that can be toggled
// Use the click event to detect when the value
// changes
class ToggleListItem : public ListItem
{
private:
bool toggleState;
std::string onValue, offValue;
void updateValue();
public:
ToggleListItem(std::string label, bool initialValue, std::string description = "", std::string onValue = "On", std::string offValue = "Off");
virtual bool onClick() override;
bool getToggleState();
};
// A list item which spawns the swkbd
// to input its value (string)
class InputListItem : public ListItem
{
protected:
std::string helpText;
int maxInputLength;
public:
InputListItem(std::string label, std::string initialValue, std::string helpText, std::string description = "", int maxInputLength = 32);
virtual bool onClick() override;
};
// A list item which spawns the swkbd
// to input its value (integer)
class IntegerInputListItem : public InputListItem
{
public:
IntegerInputListItem(std::string label, int initialValue, std::string helpText, std::string description = "", int maxInputLength = 32);
virtual bool onClick() override;
};
class List; // forward declaration for ListContentView::list
// The content view of lists (used internally)
class ListContentView : public BoxLayout
{
public:
ListContentView(List* list, size_t defaultFocus = 0);
protected:
void customSpacing(View* current, View* next, int* spacing) override;
private:
List* list;
};
// A vertical list of various widgets, with proper margins and spacing
// and a scroll bar
// In practice it's a ScrollView which content view is
// a ListContentView (BoxLayout)
class List : public ScrollView
{
private:
ListContentView* layout;
public:
List(size_t defaultFocus = 0);
~List();
// Wrapped BoxLayout methods
void addView(View* view, bool fill = false);
void setMargins(unsigned top, unsigned right, unsigned bottom, unsigned left);
void setMarginBottom(unsigned bottom);
void setSpacing(unsigned spacing);
unsigned getSpacing();
virtual void customSpacing(View* current, View* next, int* spacing);
};
} // namespace brls

View File

@@ -0,0 +1,49 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdarg.h>
#include <string>
namespace brls
{
enum class LogLevel
{
ERROR = 0,
INFO,
DEBUG
};
class Logger
{
public:
static void setLogLevel(LogLevel logLevel);
static void error(const char* format, ...);
static void info(const char* format, ...);
static void debug(const char* format, ...);
protected:
static void log(LogLevel logLevel, const char* prefix, const char* color, const char* format, va_list ap);
};
} // namespace brls

View File

@@ -0,0 +1,40 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/view.hpp>
namespace brls
{
// A Material icon (from the Material font)
class MaterialIcon : public View
{
private:
std::string icon;
unsigned middleX, middleY;
public:
MaterialIcon(std::string icon);
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
};
} // namespace brls

View File

@@ -0,0 +1,64 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/animations.hpp>
#include <borealis/label.hpp>
#include <borealis/view.hpp>
#define BRLS_NOTIFICATIONS_MAX 8
// TODO: check in HOS that the animation duration + notification timeout are correct
namespace brls
{
class Notification : public View
{
public:
Notification(std::string text);
~Notification();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
menu_timer_t timeoutTimer;
private:
Label* label;
};
class NotificationManager : public View
{
private:
Notification* notifications[BRLS_NOTIFICATIONS_MAX];
void layoutNotification(size_t i);
public:
NotificationManager();
~NotificationManager();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
void notify(std::string text);
};
}; // namespace brls

View File

@@ -0,0 +1,63 @@
/*
Borealis, a Nintendo Switch UI Library
Copyright (C) 2019 natinusala
Copyright (C) 2019 WerWolv
Copyright (C) 2019 p-sam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <borealis/applet_frame.hpp>
#include <borealis/list.hpp>
#include <borealis/view.hpp>
#include <string>
namespace brls
{
class PopupFrame : public View
{
private:
PopupFrame(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
PopupFrame(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
PopupFrame(std::string title, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
AppletFrame* contentView = nullptr;
protected:
unsigned getShowAnimationDuration(ViewAnimation animation) override;
public:
~PopupFrame();
void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, Style* style, FrameContext* ctx) override;
void layout(NVGcontext* vg, Style* style, FontStash* stash) override;
View* getDefaultFocus() override;
virtual bool onCancel();
void willAppear(bool resetState = false) override;
void willDisappear(bool resetState = false) override;
static void open(std::string title, unsigned char* imageBuffer, size_t imageBufferSize, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
static void open(std::string title, std::string imagePath, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
static void open(std::string title, AppletFrame* contentView, std::string subTitleLeft = "", std::string subTitleRight = "");
bool isTranslucent() override
{
return true;
}
};
} // namespace brls

Some files were not shown because too many files have changed in this diff Show More