finish refactor, add docs and CI
CI / Build NRO (push) Successful in 29s
CI / Format check (push) Successful in 11s
CI / Layering check (push) Successful in 1s

This commit is contained in:
2026-04-27 01:49:41 +03:00
parent dc65a4c8a9
commit 9339e7dbfe
48 changed files with 1979 additions and 1476 deletions
+25 -26
View File
@@ -24,16 +24,17 @@
* reasonable ways as different from the original version.
*/
#include <nxst/domain/account.hpp>
#include <sys/stat.h>
#include <cstdio>
#include <sys/stat.h>
#include <nxst/domain/account.hpp>
static std::map<AccountUid, User> mUsers;
Result Account::init(void)
{
Result Account::init(void) {
Result res = accountInitialize(AccountServiceType_Application);
if (R_FAILED(res)) return res;
if (R_FAILED(res))
return res;
AccountUid uids[8];
s32 count = 0;
@@ -44,13 +45,11 @@ Result Account::init(void)
return 0;
}
void Account::exit(void)
{
void Account::exit(void) {
accountExit();
}
std::vector<AccountUid> Account::ids(void)
{
std::vector<AccountUid> Account::ids(void) {
std::vector<AccountUid> v;
for (auto& value : mUsers) {
v.push_back(value.second.id);
@@ -58,8 +57,7 @@ std::vector<AccountUid> Account::ids(void)
return v;
}
static User getUser(AccountUid id)
{
static User getUser(AccountUid id) {
User user{id, ""};
AccountProfile profile;
AccountProfileBase profilebase;
@@ -74,8 +72,7 @@ static User getUser(AccountUid id)
return user;
}
std::string Account::username(AccountUid id)
{
std::string Account::username(AccountUid id) {
std::map<AccountUid, User>::const_iterator got = mUsers.find(id);
if (got == mUsers.end()) {
User user = getUser(id);
@@ -86,21 +83,21 @@ std::string Account::username(AccountUid id)
return got->second.name;
}
std::string Account::iconPath(AccountUid id)
{
std::string Account::iconPath(AccountUid id) {
char path[128];
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg",
id.uid[0], id.uid[1]);
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg", id.uid[0], id.uid[1]);
struct stat st;
if (stat(path, &st) == 0 && st.st_size > 0) return std::string(path);
if (stat(path, &st) == 0 && st.st_size > 0)
return std::string(path);
mkdir("sdmc:/switch", 0755);
mkdir("sdmc:/switch/NXST", 0755);
mkdir("sdmc:/switch/NXST/cache", 0755);
AccountProfile profile;
if (R_FAILED(accountGetProfile(&profile, id))) return "";
if (R_FAILED(accountGetProfile(&profile, id)))
return "";
u32 imgSize = 0;
if (R_FAILED(accountProfileGetImageSize(&profile, &imgSize)) || imgSize == 0) {
@@ -112,26 +109,28 @@ std::string Account::iconPath(AccountUid id)
u32 outSize = 0;
Result r = accountProfileLoadImage(&profile, buf.data(), imgSize, &outSize);
accountProfileClose(&profile);
if (R_FAILED(r) || outSize == 0) return "";
if (R_FAILED(r) || outSize == 0)
return "";
FILE* f = fopen(path, "wb");
if (!f) return "";
if (!f)
return "";
fwrite(buf.data(), 1, outSize, f);
fclose(f);
return std::string(path);
}
AccountUid Account::selectAccount(void)
{
AccountUid Account::selectAccount(void) {
LibAppletArgs args;
libappletArgsCreate(&args, 0x10000);
u8 st_in[0xA0] = {0};
u8 st_in[0xA0] = {0};
u8 st_out[0x18] = {0};
size_t repsz;
Result res = libappletLaunch(AppletId_LibraryAppletPlayerSelect, &args, st_in, 0xA0, st_out, 0x18, &repsz);
Result res =
libappletLaunch(AppletId_LibraryAppletPlayerSelect, &args, st_in, 0xA0, st_out, 0x18, &repsz);
if (R_SUCCEEDED(res)) {
u64 lres = *(u64*)st_out;
u64 lres = *(u64*)st_out;
AccountUid uid = *(AccountUid*)&st_out[8];
if (lres == 0)
return uid;
+25 -28
View File
@@ -26,8 +26,7 @@
#include <nxst/domain/common.hpp>
std::string DateTime::timeStr(void)
{
std::string DateTime::timeStr(void) {
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
@@ -35,35 +34,32 @@ std::string DateTime::timeStr(void)
return StringUtils::format("%02i:%02i:%02i", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
}
std::string DateTime::dateTimeStr(void)
{
std::string DateTime::dateTimeStr(void) {
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour,
timeStruct.tm_min, timeStruct.tm_sec);
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1,
timeStruct.tm_mday, timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
}
std::string DateTime::logDateTime(void)
{
std::string DateTime::logDateTime(void) {
time_t unixTime;
struct tm timeStruct;
time(&unixTime);
localtime_r(&unixTime, &timeStruct);
return StringUtils::format("%04i-%02i-%02i %02i:%02i:%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday,
timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
return StringUtils::format("%04i-%02i-%02i %02i:%02i:%02i", timeStruct.tm_year + 1900,
timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour,
timeStruct.tm_min, timeStruct.tm_sec);
}
std::string StringUtils::UTF16toUTF8(const std::u16string& src)
{
std::string StringUtils::UTF16toUTF8(const std::u16string& src) {
static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::string dst = convert.to_bytes(src);
return dst;
}
std::string StringUtils::removeForbiddenCharacters(std::string src)
{
std::string StringUtils::removeForbiddenCharacters(std::string src) {
static const std::string illegalChars = ".,!\\/:?*\"<>|";
for (size_t i = 0, sz = src.length(); i < sz; i++) {
if (illegalChars.find(src[i]) != std::string::npos) {
@@ -79,8 +75,7 @@ std::string StringUtils::removeForbiddenCharacters(std::string src)
return src;
}
std::string StringUtils::format(const std::string fmt_str, ...)
{
std::string StringUtils::format(const std::string fmt_str, ...) {
va_list ap;
char* fp = NULL;
va_start(ap, fmt_str);
@@ -90,8 +85,7 @@ std::string StringUtils::format(const std::string fmt_str, ...)
return std::string(formatted.get());
}
bool StringUtils::containsInvalidChar(const std::string& str)
{
bool StringUtils::containsInvalidChar(const std::string& str) {
for (size_t i = 0, sz = str.length(); i < sz; i++) {
if (!isascii(str[i])) {
return true;
@@ -100,24 +94,27 @@ bool StringUtils::containsInvalidChar(const std::string& str)
return false;
}
void StringUtils::ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
void StringUtils::ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
void StringUtils::rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
void StringUtils::rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
[](int ch) {
return !std::isspace(ch);
})
.base(),
s.end());
}
void StringUtils::trim(std::string& s)
{
void StringUtils::trim(std::string& s) {
ltrim(s);
rtrim(s);
}
char* getConsoleIP(void)
{
char* getConsoleIP(void) {
struct in_addr in;
in.s_addr = gethostid();
return inet_ntoa(in);
+89 -112
View File
@@ -24,40 +24,39 @@
* reasonable ways as different from the original version.
*/
#include <nxst/domain/title.hpp>
#include <nxst/app/main.hpp>
#include <nxst/domain/title.hpp>
static std::unordered_map<AccountUid, std::vector<Title>> titles;
static bool s_titlesLoaded = false;
bool areTitlesLoaded(void)
{
bool areTitlesLoaded(void) {
return s_titlesLoaded;
}
void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string& name, const std::string& author)
{
mId = id;
mUserId = userID;
void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string& name,
const std::string& author) {
mId = id;
mUserId = userID;
mSaveDataType = saveDataType;
mUserName = Account::username(userID);
mAuthor = author;
mName = name;
mSafeName = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", mId) : StringUtils::removeForbiddenCharacters(name);
mPath = "sdmc:/switch/NXST/saves/" + StringUtils::format("0x%016llX", mId) + " " + mSafeName;
mUserName = Account::username(userID);
mAuthor = author;
mName = name;
mSafeName = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", mId)
: StringUtils::removeForbiddenCharacters(name);
mPath = "sdmc:/switch/NXST/saves/" + StringUtils::format("0x%016llX", mId) + " " + mSafeName;
std::string aname = StringUtils::removeAccents(mName);
size_t pos = aname.rfind(":");
mDisplayName = std::make_pair(aname, "");
size_t pos = aname.rfind(":");
mDisplayName = std::make_pair(aname, "");
if (pos != std::string::npos) {
std::string name1 = aname.substr(0, pos);
std::string name2 = aname.substr(pos + 1);
StringUtils::trim(name1);
StringUtils::trim(name2);
mDisplayName.first = name1;
mDisplayName.first = name1;
mDisplayName.second = name2;
}
else {
} else {
// check for parenthesis
size_t pos1 = aname.rfind("(");
size_t pos2 = aname.rfind(")");
@@ -66,7 +65,7 @@ void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string&
std::string name2 = aname.substr(pos1 + 1, pos2 - 1 - pos1);
StringUtils::trim(name1);
StringUtils::trim(name2);
mDisplayName.first = name1;
mDisplayName.first = name1;
mDisplayName.second = name2;
}
}
@@ -74,94 +73,77 @@ void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string&
refreshDirectories();
}
u8 Title::saveDataType(void)
{
u8 Title::saveDataType(void) {
return mSaveDataType;
}
u64 Title::id(void)
{
u64 Title::id(void) {
return mId;
}
u64 Title::saveId(void)
{
u64 Title::saveId(void) {
return mSaveId;
}
void Title::saveId(u64 saveId)
{
void Title::saveId(u64 saveId) {
mSaveId = saveId;
}
AccountUid Title::userId(void)
{
AccountUid Title::userId(void) {
return mUserId;
}
std::string Title::userName(void)
{
std::string Title::userName(void) {
return mUserName;
}
std::string Title::author(void)
{
std::string Title::author(void) {
return mAuthor;
}
std::string Title::name(void)
{
std::string Title::name(void) {
return mName;
}
std::pair<std::string, std::string> Title::displayName(void)
{
std::pair<std::string, std::string> Title::displayName(void) {
return mDisplayName;
}
std::string Title::path(void)
{
std::string Title::path(void) {
return mPath;
}
std::string Title::fullPath(size_t index)
{
std::string Title::fullPath(size_t index) {
return mFullSavePaths.at(index);
}
std::vector<std::string> Title::saves()
{
std::vector<std::string> Title::saves() {
return mSaves;
}
u64 Title::playTimeNanoseconds(void)
{
u64 Title::playTimeNanoseconds(void) {
return mPlayTimeNanoseconds;
}
std::string Title::playTime(void)
{
std::string Title::playTime(void) {
const u64 playTimeMinutes = mPlayTimeNanoseconds / 60000000000;
return StringUtils::format("%d", playTimeMinutes / 60) + ":" + StringUtils::format("%02d", playTimeMinutes % 60) + " hours";
return StringUtils::format("%d", playTimeMinutes / 60) + ":" +
StringUtils::format("%02d", playTimeMinutes % 60) + " hours";
}
void Title::playTimeNanoseconds(u64 playTimeNanoseconds)
{
void Title::playTimeNanoseconds(u64 playTimeNanoseconds) {
mPlayTimeNanoseconds = playTimeNanoseconds;
}
u32 Title::lastPlayedTimestamp(void)
{
u32 Title::lastPlayedTimestamp(void) {
return mLastPlayedTimestamp;
}
void Title::lastPlayedTimestamp(u32 lastPlayedTimestamp)
{
void Title::lastPlayedTimestamp(u32 lastPlayedTimestamp) {
mLastPlayedTimestamp = lastPlayedTimestamp;
}
void Title::refreshDirectories(void)
{
void Title::refreshDirectories(void) {
mSaves.clear();
mFullSavePaths.clear();
@@ -178,15 +160,15 @@ void Title::refreshDirectories(void)
std::sort(mFullSavePaths.rbegin(), mFullSavePaths.rend());
mSaves.insert(mSaves.begin(), g_emptySave);
mFullSavePaths.insert(mFullSavePaths.begin(), g_emptySave);
}
else {
Logger::getInstance().log(Logger::ERROR, "Couldn't retrieve the extdata directory list for the title " + name());
} else {
Logger::getInstance().log(Logger::ERROR,
"Couldn't retrieve the extdata directory list for the title " + name());
}
}
void loadTitles(void)
{
if (s_titlesLoaded) return;
void loadTitles(void) {
if (s_titlesLoaded)
return;
s_titlesLoaded = true;
titles.clear();
@@ -194,9 +176,9 @@ void loadTitles(void)
FsSaveDataInfoReader reader;
FsSaveDataInfo info;
s64 total_entries = 0;
size_t outsize = 0;
size_t outsize = 0;
NacpLanguageEntry* nle = NULL;
NacpLanguageEntry* nle = NULL;
NsApplicationControlData* nsacd = (NsApplicationControlData*)malloc(sizeof(NsApplicationControlData));
if (nsacd == NULL) {
return;
@@ -216,43 +198,44 @@ void loadTitles(void)
}
if (info.save_data_type == FsSaveDataType_Account) {
u64 tid = info.application_id;
u64 sid = info.save_data_id;
u64 tid = info.application_id;
u64 sid = info.save_data_id;
AccountUid uid = info.uid;
// if (mFilterIds.find(tid) == mFilterIds.end()) {
res = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, nsacd, sizeof(NsApplicationControlData), &outsize);
if (R_SUCCEEDED(res) && !(outsize < sizeof(nsacd->nacp))) {
res = nacpGetLanguageEntry(&nsacd->nacp, &nle);
if (R_SUCCEEDED(res) && nle != NULL) {
Title title;
title.init(info.save_data_type, tid, uid, std::string(nle->name), std::string(nle->author));
title.saveId(sid);
res = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, nsacd,
sizeof(NsApplicationControlData), &outsize);
if (R_SUCCEEDED(res) && !(outsize < sizeof(nsacd->nacp))) {
res = nacpGetLanguageEntry(&nsacd->nacp, &nle);
if (R_SUCCEEDED(res) && nle != NULL) {
Title title;
title.init(info.save_data_type, tid, uid, std::string(nle->name),
std::string(nle->author));
title.saveId(sid);
// load play statistics
PdmPlayStatistics stats;
res = pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(tid, uid, false, &stats);
if (R_SUCCEEDED(res)) {
title.playTimeNanoseconds(stats.playtime);
title.lastPlayedTimestamp(stats.last_timestamp_user);
}
// load play statistics
PdmPlayStatistics stats;
res = pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(tid, uid, false, &stats);
if (R_SUCCEEDED(res)) {
title.playTimeNanoseconds(stats.playtime);
title.lastPlayedTimestamp(stats.last_timestamp_user);
}
// loadIcon(tid, nsacd, outsize - sizeof(nsacd->nacp));
// loadIcon(tid, nsacd, outsize - sizeof(nsacd->nacp));
// check if the vector is already created
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
if (it != titles.end()) {
// found
it->second.push_back(title);
}
else {
// not found, insert into map
std::vector<Title> v;
v.push_back(title);
titles.emplace(uid, v);
}
// check if the vector is already created
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
if (it != titles.end()) {
// found
it->second.push_back(title);
} else {
// not found, insert into map
std::vector<Title> v;
v.push_back(title);
titles.emplace(uid, v);
}
}
nle = NULL;
}
nle = NULL;
// }
}
}
@@ -263,45 +246,40 @@ void loadTitles(void)
sortTitles();
}
void sortTitles(void)
{
void sortTitles(void) {
for (auto& vect : titles) {
std::sort(vect.second.begin(), vect.second.end(), [](Title& l, Title& r) {
switch (g_sortMode) {
case SORT_LAST_PLAYED:
return l.lastPlayedTimestamp() > r.lastPlayedTimestamp();
case SORT_PLAY_TIME:
return l.playTimeNanoseconds() > r.playTimeNanoseconds();
case SORT_ALPHA:
default:
return l.name() < r.name();
case SORT_LAST_PLAYED:
return l.lastPlayedTimestamp() > r.lastPlayedTimestamp();
case SORT_PLAY_TIME:
return l.playTimeNanoseconds() > r.playTimeNanoseconds();
case SORT_ALPHA:
default:
return l.name() < r.name();
}
});
}
}
void rotateSortMode(void)
{
void rotateSortMode(void) {
g_sortMode = static_cast<sort_t>((g_sortMode + 1) % SORT_MODES_COUNT);
sortTitles();
}
void getTitle(Title& dst, AccountUid uid, size_t i)
{
void getTitle(Title& dst, AccountUid uid, size_t i) {
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
if (it != titles.end() && i < getTitleCount(uid)) {
dst = it->second.at(i);
}
}
size_t getTitleCount(AccountUid uid)
{
size_t getTitleCount(AccountUid uid) {
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
return it != titles.end() ? it->second.size() : 0;
}
void refreshDirectories(u64 id)
{
void refreshDirectories(u64 id) {
for (auto& pair : titles) {
for (size_t i = 0; i < pair.second.size(); i++) {
if (pair.second.at(i).id() == id) {
@@ -311,8 +289,7 @@ void refreshDirectories(u64 id)
}
}
std::unordered_map<std::string, std::string> getCompleteTitleList(void)
{
std::unordered_map<std::string, std::string> getCompleteTitleList(void) {
std::unordered_map<std::string, std::string> map;
for (const auto& pair : titles) {
for (auto value : pair.second) {
+30 -36
View File
@@ -24,21 +24,19 @@
* reasonable ways as different from the original version.
*/
#include <nxst/app/main.hpp>
#include <nxst/app/main_application.hpp>
#include <nxst/domain/util.hpp>
#include <nxst/infra/sys/logger.hpp>
#include <nxst/app/main_application.hpp>
#include <nxst/app/main.hpp>
void servicesExit(void)
{
void servicesExit(void) {
Logger::getInstance().flush();
Account::exit();
plExit();
romfsExit();
}
Result servicesInit(void)
{
Result servicesInit(void) {
io::createDirectory("sdmc:/switch");
io::createDirectory("sdmc:/switch/NXST");
io::createDirectory("sdmc:/switch/NXST/saves");
@@ -71,30 +69,28 @@ Result servicesInit(void)
if (R_SUCCEEDED(res = hidsysInitialize())) {
g_notificationLedAvailable = true;
}
else {
} else {
Logger::getInstance().log(Logger::INFO, "Notification led not available. Result code 0x{:08X}.", res);
}
Logger::getInstance().log(Logger::INFO, "NXST loading completed!");
return 0;
}
std::u16string StringUtils::UTF8toUTF16(const char* src)
{
std::u16string StringUtils::UTF8toUTF16(const char* src) {
char16_t tmp[256] = {0};
utf8_to_utf16((uint16_t*)tmp, (uint8_t*)src, 256);
return std::u16string(tmp);
}
// https://stackoverflow.com/questions/14094621/change-all-accented-letters-to-normal-letters-in-c
std::string StringUtils::removeAccents(std::string str)
{
std::string StringUtils::removeAccents(std::string str) {
std::u16string src = UTF8toUTF16(str.c_str());
const std::u16string illegal = UTF8toUTF16("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüūýþÿ");
const std::u16string fixed = UTF8toUTF16("AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuuypy");
const std::u16string illegal =
UTF8toUTF16("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüūýþÿ");
const std::u16string fixed =
UTF8toUTF16("AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuuypy");
for (size_t i = 0, sz = src.length(); i < sz; i++) {
size_t index = illegal.find(src[i]);
@@ -106,8 +102,7 @@ std::string StringUtils::removeAccents(std::string str)
return UTF16toUTF8(src);
}
std::string StringUtils::removeNotAscii(std::string str)
{
std::string StringUtils::removeNotAscii(std::string str) {
for (size_t i = 0, sz = str.length(); i < sz; i++) {
if (!isascii(str[i])) {
str[i] = ' ';
@@ -116,9 +111,9 @@ std::string StringUtils::removeNotAscii(std::string str)
return str;
}
std::string StringUtils::elide(const std::string& s, size_t maxChars)
{
if (s.size() <= maxChars || maxChars < 6) return s;
std::string StringUtils::elide(const std::string& s, size_t maxChars) {
if (s.size() <= maxChars || maxChars < 6)
return s;
constexpr const char* dots = "...";
size_t budget = maxChars - 3;
size_t head = (budget + 1) / 2;
@@ -126,36 +121,35 @@ std::string StringUtils::elide(const std::string& s, size_t maxChars)
return s.substr(0, head) + dots + s.substr(s.size() - tail);
}
HidsysNotificationLedPattern blinkLedPattern(u8 times)
{
HidsysNotificationLedPattern blinkLedPattern(u8 times) {
HidsysNotificationLedPattern pattern;
memset(&pattern, 0, sizeof(pattern));
pattern.baseMiniCycleDuration = 0x1; // 12.5ms.
pattern.totalMiniCycles = 0x2; // 2 mini cycles.
pattern.totalFullCycles = times; // Repeat n times.
pattern.startIntensity = 0x0; // 0%.
pattern.baseMiniCycleDuration = 0x1; // 12.5ms.
pattern.totalMiniCycles = 0x2; // 2 mini cycles.
pattern.totalFullCycles = times; // Repeat n times.
pattern.startIntensity = 0x0; // 0%.
pattern.miniCycles[0].ledIntensity = 0xF; // 100%.
pattern.miniCycles[0].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
pattern.miniCycles[0].finalStepDuration = 0x0; // Forced 12.5ms.
pattern.miniCycles[1].ledIntensity = 0x0; // 0%.
pattern.miniCycles[1].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
pattern.miniCycles[1].finalStepDuration = 0x0; // Forced 12.5ms.
pattern.miniCycles[0].ledIntensity = 0xF; // 100%.
pattern.miniCycles[0].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
pattern.miniCycles[0].finalStepDuration = 0x0; // Forced 12.5ms.
pattern.miniCycles[1].ledIntensity = 0x0; // 0%.
pattern.miniCycles[1].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
pattern.miniCycles[1].finalStepDuration = 0x0; // Forced 12.5ms.
return pattern;
}
void blinkLed(u8 times)
{
void blinkLed(u8 times) {
if (g_notificationLedAvailable) {
PadState pad;
padInitializeDefault(&pad);
s32 n;
HidsysUniquePadId uniquePadIds[2] = {0};
HidsysUniquePadId uniquePadIds[2] = {0};
HidsysNotificationLedPattern pattern = blinkLedPattern(times);
memset(uniquePadIds, 0, sizeof(uniquePadIds));
Result res = hidsysGetUniquePadsFromNpad(padIsHandheld(&pad) ? HidNpadIdType_Handheld : HidNpadIdType_No1, uniquePadIds, 2, &n);
Result res = hidsysGetUniquePadsFromNpad(
padIsHandheld(&pad) ? HidNpadIdType_Handheld : HidNpadIdType_No1, uniquePadIds, 2, &n);
if (R_SUCCEEDED(res)) {
for (s32 i = 0; i < n; i++) {
hidsysSetNotificationLedPattern(&pattern, uniquePadIds[i]);