diff --git a/src/comptition/comptition.cpp b/src/comptition/comptition.cpp index fb7c352..e9a6f9c 100644 --- a/src/comptition/comptition.cpp +++ b/src/comptition/comptition.cpp @@ -1,5 +1,58 @@ #include "vex.h" +// Test function to validate triple-down logic (for development testing) +void testTripleDownLogic() +{ + logHandler("testTripleDownLogic", "Testing triple-down detection logic", Log::Level::Info); + + // Test variables + int downPressCount = 0; + vex::timer downPressTimer; + const int TRIPLE_DOWN_WINDOW_MS = 1500; + + // Test case 1: Quick triple press (should work) + downPressCount = 0; + downPressTimer.clear(); + + // Simulate first press + downPressCount++; + if (downPressCount < 3) downPressTimer.clear(); + + // Simulate second press after 300ms + vex::this_thread::sleep_for(300); + if (downPressTimer.time() <= TRIPLE_DOWN_WINDOW_MS) { + downPressCount++; + if (downPressCount < 3) downPressTimer.clear(); + } + + // Simulate third press after another 300ms + vex::this_thread::sleep_for(300); + if (downPressTimer.time() <= TRIPLE_DOWN_WINDOW_MS) { + downPressCount++; + if (downPressCount >= 3) { + logHandler("testTripleDownLogic", "Test case 1 PASSED: Quick triple press detected", Log::Level::Info); + } + } + + // Test case 2: Slow triple press (should fail) + downPressCount = 0; + downPressTimer.clear(); + + downPressCount++; + vex::this_thread::sleep_for(800); // Wait longer + if (downPressTimer.time() <= TRIPLE_DOWN_WINDOW_MS) { + downPressCount++; + vex::this_thread::sleep_for(800); // Wait longer again + if (downPressTimer.time() <= TRIPLE_DOWN_WINDOW_MS) { + downPressCount++; + } else { + logHandler("testTripleDownLogic", "Test case 2 PASSED: Slow triple press correctly rejected", Log::Level::Info); + } + } + + logHandler("testTripleDownLogic", "Triple-down logic testing completed", Log::Level::Info); +} + void autonomous() { logHandler("autonomous", "Test message.", Log::Level::Warn, 2); @@ -104,6 +157,132 @@ void displayDriveModeMenu() primaryController.Screen.print("Drive Mode Selected"); } +// Function to display runtime settings menu +void displayRuntimeSettingsMenu() +{ + primaryController.Screen.clearScreen(); + primaryController.Screen.setCursor(1, 1); + primaryController.Screen.print("Runtime Settings"); + + // Simple menu with numbered options + primaryController.Screen.setCursor(2, 1); + primaryController.Screen.print("A: Drive Mode"); + primaryController.Screen.setCursor(3, 1); + primaryController.Screen.print("B: Traction Ctrl"); + primaryController.Screen.setCursor(4, 1); + primaryController.Screen.print("X: Stability Ctrl"); + primaryController.Screen.setCursor(5, 1); + primaryController.Screen.print("Y: ABS Control"); + + vex::timer menuTimer; + bool menuActive = true; + bool buttonWasPressed = false; // Debounce flag + + while (menuActive && Competition.isEnabled() && menuTimer.time() < 10000) // 10 second timeout + { + bool anyButtonPressed = primaryController.ButtonA.pressing() || + primaryController.ButtonB.pressing() || + primaryController.ButtonX.pressing() || + primaryController.ButtonY.pressing() || + primaryController.ButtonDown.pressing() || + primaryController.ButtonUp.pressing(); + + if (!anyButtonPressed) + { + buttonWasPressed = false; // Reset debounce when no button is pressed + } + + if (!buttonWasPressed && primaryController.ButtonA.pressing()) + { + buttonWasPressed = true; + // Cycle through drive modes + configManager::DriveMode currentMode = ConfigManager.getDriveMode(); + configManager::DriveMode newMode; + + switch (currentMode) + { + case configManager::DriveMode::LeftArcade: + newMode = configManager::DriveMode::RightArcade; + break; + case configManager::DriveMode::RightArcade: + newMode = configManager::DriveMode::SplitArcade; + break; + case configManager::DriveMode::SplitArcade: + newMode = configManager::DriveMode::Tank; + break; + case configManager::DriveMode::Tank: + newMode = configManager::DriveMode::LeftArcade; + break; + } + + ConfigManager.setDriveMode(newMode); + primaryController.Screen.clearScreen(); + primaryController.Screen.setCursor(1, 1); + + std::string modeText; + switch (newMode) + { + case configManager::DriveMode::LeftArcade: + modeText = "Left Arcade"; + break; + case configManager::DriveMode::RightArcade: + modeText = "Right Arcade"; + break; + case configManager::DriveMode::SplitArcade: + modeText = "Split Arcade"; + break; + case configManager::DriveMode::Tank: + modeText = "Tank Drive"; + break; + } + + primaryController.Screen.print(("Mode: " + modeText).c_str()); + vex::this_thread::sleep_for(1000); + menuActive = false; + } + else if (!buttonWasPressed && primaryController.ButtonB.pressing()) + { + buttonWasPressed = true; + tractionControlEnabled = !tractionControlEnabled; + primaryController.Screen.clearScreen(); + primaryController.Screen.setCursor(1, 1); + primaryController.Screen.print(tractionControlEnabled ? "Traction ON" : "Traction OFF"); + vex::this_thread::sleep_for(1000); + menuActive = false; + } + else if (!buttonWasPressed && primaryController.ButtonX.pressing()) + { + buttonWasPressed = true; + stabilityControlEnabled = !stabilityControlEnabled; + primaryController.Screen.clearScreen(); + primaryController.Screen.setCursor(1, 1); + primaryController.Screen.print(stabilityControlEnabled ? "Stability ON" : "Stability OFF"); + vex::this_thread::sleep_for(1000); + menuActive = false; + } + else if (!buttonWasPressed && primaryController.ButtonY.pressing()) + { + buttonWasPressed = true; + absEnabled = !absEnabled; + primaryController.Screen.clearScreen(); + primaryController.Screen.setCursor(1, 1); + primaryController.Screen.print(absEnabled ? "ABS ON" : "ABS OFF"); + vex::this_thread::sleep_for(1000); + menuActive = false; + } + else if (!buttonWasPressed && (primaryController.ButtonDown.pressing() || primaryController.ButtonUp.pressing())) + { + buttonWasPressed = true; + // Exit menu if Down or Up is pressed + menuActive = false; + } + + vex::this_thread::sleep_for(50); + } + + primaryController.Screen.clearScreen(); +} + // User control task void userControl() { @@ -118,6 +297,12 @@ void userControl() double turnVolts, forwardVolts; bool configMenuActive = false; // Tracks if options menu is active + + // Triple-down detection variables + int downPressCount = 0; + vex::timer downPressTimer; + bool lastDownState = false; + const int TRIPLE_DOWN_WINDOW_MS = 1500; // 1.5 second window // Load drive mode from config configManager::DriveMode currentDriveMode = ConfigManager.getDriveMode(); @@ -127,7 +312,47 @@ void userControl() while (Competition.isEnabled()) { - // Open configuration menu + // Triple-down detection for runtime settings + bool currentDownState = primaryController.ButtonDown.pressing(); + + if (currentDownState && !lastDownState) // Down button just pressed + { + if (downPressCount == 0 || downPressTimer.time() <= TRIPLE_DOWN_WINDOW_MS) + { + downPressCount++; + downPressTimer.clear(); + + if (downPressCount >= 3) + { + // Triple-down detected, open runtime settings + displayRuntimeSettingsMenu(); + currentDriveMode = ConfigManager.getDriveMode(); // Update current mode + leftDeadzone = ConfigManager.getLeftDeadzone(); // Update deadzones if changed + rightDeadzone = ConfigManager.getRightDeadzone(); + downPressCount = 0; // Reset counter + } + else if (downPressCount == 2) + { + // Give user feedback they're partway there + primaryController.rumble("-"); + } + } + else + { + // Window expired, reset counter + downPressCount = 1; + downPressTimer.clear(); + } + } + else if (downPressTimer.time() > TRIPLE_DOWN_WINDOW_MS && downPressCount > 0) + { + // Reset counter if window expires + downPressCount = 0; + } + + lastDownState = currentDownState; + + // Open configuration menu (existing UP button functionality) if (primaryController.ButtonUp.pressing()) { configMenuActive = !configMenuActive;