sysmodule: remove manager

This commit is contained in:
souldbminersmwc
2025-12-03 19:15:10 -05:00
parent 21d315d0a4
commit a7d7945a4b
212 changed files with 34620 additions and 50263 deletions

View File

@@ -0,0 +1,202 @@
/********************************************************************************
* File: haptics.cpp
* Author: ppkantorski
* Description:
* This source file provides implementations for the functions declared in
* haptics.hpp. These functions manage haptic feedback for the Ultrahand Overlay
* using libnxs vibration interfaces. It includes routines for initializing
* rumble devices, sending vibration patterns, and handling single or double
* click feedback with timing control. Thread safety is maintained through
* atomic operations and synchronization mechanisms.
*
* For the latest updates and contributions, visit the project's GitHub repository.
* (GitHub Repository: https://github.com/ppkantorski/Ultrahand-Overlay)
*
* Note: Please be aware that this notice cannot be altered or removed. It is a part
* of the project's documentation and must remain intact.
*
* Licensed under both GPLv2 and CC-BY-4.0
* Copyright (c) 2025 ppkantorski
********************************************************************************/
#include "haptics.hpp"
namespace ult {
// ===== Internal state (private to this file) =====
//bool rumbleInitialized = false;
static HidVibrationDeviceHandle vibHandheld;
static HidVibrationDeviceHandle vibPlayer1Left;
static HidVibrationDeviceHandle vibPlayer1Right;
static u64 rumbleStartTick = 0;
static u64 doubleClickTick = 0;
static u8 doubleClickPulse = 0;
// ===== Shared flags (accessible globally) =====
std::atomic<bool> rumbleActive{false};
std::atomic<bool> doubleClickActive{false};
// ===== Constants =====
static constexpr u64 RUMBLE_DURATION_NS = 30'000'000ULL;
static constexpr u64 DOUBLE_CLICK_PULSE_DURATION_NS = 30'000'000ULL;
static constexpr u64 DOUBLE_CLICK_GAP_NS = 100'000'000ULL;
static constexpr HidVibrationValue clickDocked = {
.amp_low = 0.20f,
.freq_low = 100.0f,
.amp_high = 0.80f,
.freq_high = 300.0f
};
static constexpr HidVibrationValue clickHandheld = {
.amp_low = 0.25f,
.freq_low = 100.0f,
.amp_high = 1.0f,
.freq_high = 300.0f
};
static constexpr HidVibrationValue vibrationStop{0};
// ===== Internal helpers =====
static void initController(HidNpadIdType npad, HidVibrationDeviceHandle* handles, int count) {
const u32 styleMask = hidGetNpadStyleSet(npad);
if (styleMask)
hidInitializeVibrationDevices(handles, count, npad, static_cast<HidNpadStyleTag>(styleMask));
}
static void sendVibration(const HidVibrationValue* value) {
if (hidGetNpadStyleSet(HidNpadIdType_Handheld))
hidSendVibrationValue(vibHandheld, value);
if (hidGetNpadStyleSet(HidNpadIdType_No1)) {
hidSendVibrationValue(vibPlayer1Left, value);
hidSendVibrationValue(vibPlayer1Right, value);
}
}
// ===== Public API =====
void initRumble() {
//if (rumbleInitialized) return;
// Try to initialize whatever is available
// Don't check if controllers exist - let initController handle it
initController(HidNpadIdType_Handheld, &vibHandheld, 1);
HidVibrationDeviceHandle handles[2];
initController(HidNpadIdType_No1, handles, 2);
vibPlayer1Left = handles[0];
vibPlayer1Right = handles[1];
// Only mark as initialized if at least one controller was found
hidGetNpadStyleSet(HidNpadIdType_Handheld);
hidGetNpadStyleSet(HidNpadIdType_No1);
//rumbleInitialized = (handheldStyle || player1Style);
// If neither exist, stay uninitialized so we retry later
}
//void deinitRumble() {
// rumbleInitialized = false;
//}
void checkAndReinitRumble() {
static u32 lastHandheldStyle = 0;
static u32 lastPlayer1Style = 0;
const u32 currentHandheldStyle = hidGetNpadStyleSet(HidNpadIdType_Handheld);
const u32 currentPlayer1Style = hidGetNpadStyleSet(HidNpadIdType_No1);
// If not initialized but controllers exist, try to init
// This handles the boot race condition where HID reports controllers
// but vibration subsystem isn't ready yet
//if (!rumbleInitialized && (currentHandheldStyle || currentPlayer1Style)) {
// initRumble();
//}
// Reinit if controller configuration changed
if (currentHandheldStyle != lastHandheldStyle || currentPlayer1Style != lastPlayer1Style) {
//rumbleInitialized = false;
initRumble();
}
// Update last style tracking regardless
lastHandheldStyle = currentHandheldStyle;
lastPlayer1Style = currentPlayer1Style;
}
void rumbleClick() {
//if (!rumbleInitialized) {
// initRumble();
// if (!rumbleInitialized) return;
//}
sendVibration(hidGetNpadStyleSet(HidNpadIdType_Handheld) ? &clickHandheld : &clickDocked);
rumbleActive.store(true, std::memory_order_release);
rumbleStartTick = armGetSystemTick();
}
void rumbleDoubleClick() {
//if (!rumbleInitialized) {
// initRumble();
// if (!rumbleInitialized) return;
//}
sendVibration(hidGetNpadStyleSet(HidNpadIdType_Handheld) ? &clickHandheld : &clickDocked);
doubleClickActive.store(true, std::memory_order_release);
doubleClickPulse = 1;
doubleClickTick = armGetSystemTick();
}
void processRumbleStop(u64 nowNs) {
if (rumbleActive.load(std::memory_order_acquire) &&
nowNs - armTicksToNs(rumbleStartTick) >= RUMBLE_DURATION_NS) {
sendVibration(&vibrationStop);
rumbleActive.store(false, std::memory_order_release);
}
}
void processRumbleDoubleClick(u64 nowNs) {
if (!doubleClickActive.load(std::memory_order_acquire)) return;
const u64 elapsed = nowNs - armTicksToNs(doubleClickTick);
switch (doubleClickPulse) {
case 1:
if (elapsed >= DOUBLE_CLICK_PULSE_DURATION_NS) {
sendVibration(&vibrationStop);
doubleClickPulse = 2;
doubleClickTick = armGetSystemTick();
}
break;
case 2:
if (elapsed >= DOUBLE_CLICK_GAP_NS) {
sendVibration(hidGetNpadStyleSet(HidNpadIdType_Handheld) ? &clickHandheld : &clickDocked);
doubleClickPulse = 3;
doubleClickTick = armGetSystemTick();
}
break;
case 3:
if (elapsed >= DOUBLE_CLICK_PULSE_DURATION_NS) {
sendVibration(&vibrationStop);
doubleClickActive.store(false, std::memory_order_release);
doubleClickPulse = 0;
}
break;
}
}
void rumbleDoubleClickStandalone() {
sendVibration(hidGetNpadStyleSet(HidNpadIdType_Handheld) ? &clickHandheld : &clickDocked);
svcSleepThread(DOUBLE_CLICK_PULSE_DURATION_NS);
sendVibration(&vibrationStop);
svcSleepThread(DOUBLE_CLICK_GAP_NS);
sendVibration(hidGetNpadStyleSet(HidNpadIdType_Handheld) ? &clickHandheld : &clickDocked);
svcSleepThread(DOUBLE_CLICK_PULSE_DURATION_NS);
sendVibration(&vibrationStop);
}
}