Skip to content

psyqo Multi-tap driver and example update #1815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Feb 27, 2025

Conversation

johnbaumann
Copy link
Collaborator

@johnbaumann johnbaumann commented Dec 13, 2024

Add getters for adc+pad type, update multitap example

@johnbaumann
Copy link
Collaborator Author

I really didn't know what sort of access methods would make sense for the analog data fields here. I can scrap this and try again if this one's too painful to look at, otherwise, open to suggestions.

@nicolasnoble
Copy link
Member

Yeah no I was just trying to avoid doing too much during the holidays :P

@johnbaumann
Copy link
Collaborator Author

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented Jan 5, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

coderabbitai bot commented Jan 5, 2025

Walkthrough

The changes enhance the AdvancedPad class in the PsyQo library by updating the copyright year and modifying the class structure and functionality. This includes changing the Pad enum to a scoped enum class, moving the Command enum to the private section, and adding several methods for handling analog input states. The multitap.cpp example file is also updated to utilize these new methods, improving the display of connected pad information, including types and statuses.

Changes

File Changes
src/mips/psyqo/advancedpad.hh - Updated copyright year
- Changed Pad enum to scoped enum class
- Moved Command enum to private section
- Added methods: getAdc(), getHalfword(), getPadType()
- Updated isPadConnected() and isButtonPressed() methods for type safety
- Modified m_padData structure to a union
src/mips/psyqo/examples/multitap/multitap.cpp - Added printPadType() method
- Removed printPadConnectionStatus(), replaced with printPadList()
- Updated printPadStatus() to remove name parameter
- Refactored print() method for flexible formatting
- Adjusted printed output layout
src/mips/psyqo/src/advancedpad.cpp - Updated pad identifier references to namespaced format
- Changed handling of m_connected and m_buttons arrays for type safety
- Added configurePort() method
- Updated copyright year
src/mips/psyqo/utility-polyfill.h - Added concept Enum
- Added function toUnderlying() for enum type conversion

Sequence Diagram

sequenceDiagram
    participant Pad as Pad Device
    participant AdvancedPad as AdvancedPad Class
    participant MultitapScene as Multitap Scene

    Pad ->> AdvancedPad: Provide Pad Data
    AdvancedPad ->> AdvancedPad: Process Pad Type
    AdvancedPad ->> AdvancedPad: Extract Analog Inputs
    AdvancedPad ->> MultitapScene: Return Pad Information
    MultitapScene ->> MultitapScene: Display Pad Details
Loading

Poem

🎮 Analog Whiskers Twitch

Pads dance with digital glee,
Inputs flowing, secrets free,
Bytes and signals, rabbit's delight,
Multitap magic shining bright!

🐰✨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b1141a and 588f68d.

📒 Files selected for processing (1)
  • src/mips/psyqo/utility-polyfill.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mips/psyqo/utility-polyfill.h
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: coverage
  • GitHub Check: asan
  • GitHub Check: build
  • GitHub Check: cross-arm64
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: toolchain
  • GitHub Check: aur-build

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/mips/psyqo/examples/multitap/multitap.cpp (2)

112-112: Maintain consistent usage for printing pad connection info.
While this change properly calls print, consider also matching the style in other calls (e.g., x offsets). This keeps layout consistent across various calls.


136-153: Potential buffer overflow risk in printPadStatus.
Using sprintf can risk overflowing m_textBuffer. Although the current usage appears safe due to the small size (32 bytes) and short output strings, consider replacing sprintf with snprintf to ensure safety if future modifications expand the printed text.

-            sprintf(m_textBuffer, "%02X ", input.getAdc(pad, i));
+            snprintf(m_textBuffer, sizeof(m_textBuffer), "%02X ", input.getAdc(pad, i));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c477c3 and 0631089.

📒 Files selected for processing (2)
  • src/mips/psyqo/advancedpad.hh (1 hunks)
  • src/mips/psyqo/examples/multitap/multitap.cpp (6 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/examples/multitap/multitap.cpp

[warning] 156-200: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

🔇 Additional comments (9)
src/mips/psyqo/examples/multitap/multitap.cpp (4)

35-35: Include statement seems fine.
No issues here regarding functionality or maintainability.


64-64: Method signature addition is appropriate.
The new method signature extends the class's functionality and reads coherently with the rest of the code.


215-215: Pointer notation for active pad is straightforward.
No concerns here, as it cleanly indicates which pad is selected.


227-228: Check for cohesive printing sequence.
These calls to printPadStatus and printPadType work well together. Confirm that skipping either call when the pad isn't connected remains consistent with your UI flow; you may want to conditionally print the type only if connected.

src/mips/psyqo/advancedpad.hh (5)

145-184: Convenient specialized getters for analog inputs.
These four methods (getAdc0, getAdc1, getAdc2, getAdc3) improve code readability. Validate thorough test coverage, especially for edge cases when no analog data is present.


185-207: Unified analog getter is well-designed.
The getAdc method elegantly delegates to the specialized getters and prevents boilerplate in the calling code.


209-221: getHalfword is straightforward.
The method reduces code duplication. Make sure the modulo operation is the intended approach for indexing the 2D array, as out-of-range values might silently wrap.


223-232: getPadType matches usage in multitap example.
It cleanly extracts the higher byte for the pad type. Confirm correctness of shifting logic (e.g., >> 8) for all supported devices.


234-247: Moving Command to private is good encapsulation.
Hiding the enum is beneficial unless external code requires direct access. If future external usage is anticipated, consider making it protected or adding proper accessor methods.

Comment on lines 156 to 200
void MultitapTestScene::printPadType(psyqo::AdvancedPad::Pad pad, int column, const char *name) {
auto &input = multitapTest.m_input;
char m_textBuffer[16] = {'\0'};
const auto padType = input.getPadType(pad);

print(column + 0, 11, true, name);
switch (padType) {
case psyqo::AdvancedPad::PadType::Mouse:
sprintf(m_textBuffer, "Mouse");
break;
case psyqo::AdvancedPad::PadType::NegCon:
sprintf(m_textBuffer, "NegCon");
break;
case psyqo::AdvancedPad::PadType::KonamiLightgun:
sprintf(m_textBuffer, "KonamiLightgun");
break;
case psyqo::AdvancedPad::PadType::DigitalPad:
sprintf(m_textBuffer, "DigitalPad");
break;
case psyqo::AdvancedPad::PadType::AnalogStick:
sprintf(m_textBuffer, "AnalogStick");
break;
case psyqo::AdvancedPad::PadType::NamcoLightgun:
sprintf(m_textBuffer, "NamcoLightgun");
break;
case psyqo::AdvancedPad::PadType::AnalogPad:
sprintf(m_textBuffer, "AnalogPad");
break;
case psyqo::AdvancedPad::PadType::Multitap:
sprintf(m_textBuffer, "Multitap");
break;
case psyqo::AdvancedPad::PadType::Jogcon:
sprintf(m_textBuffer, "Jogcon");
break;
case psyqo::AdvancedPad::PadType::ConfigMode:
sprintf(m_textBuffer, "ConfigMode");
break;
case psyqo::AdvancedPad::PadType::None:
sprintf(m_textBuffer, "None");
break;
default:
sprintf(m_textBuffer, "Unknown");
break;
}
print(column + 10, 11, true, m_textBuffer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor to reduce cyclomatic complexity in printPadType.
This method’s complexity triggers a warning. As more pad types or logic are added, it can become unwieldy. A lookup table or map-based approach could drastically simplify this switch statement.

-switch (padType) {
  // ...
-    case psyqo::AdvancedPad::PadType::NegCon:
-        sprintf(m_textBuffer, "NegCon");
-        break;
  ...
-default:
-    sprintf(m_textBuffer, "Unknown");
-    break;
+static const struct {
+    psyqo::AdvancedPad::PadType type;
+    const char* name;
+} padTypeMap[] = {
+    { psyqo::AdvancedPad::PadType::Mouse, "Mouse" },
+    { psyqo::AdvancedPad::PadType::NegCon, "NegCon" },
+    // ...
+    { psyqo::AdvancedPad::PadType::None, "None" },
+};
+
+const auto it = std::find_if(
+    std::begin(padTypeMap), std::end(padTypeMap),
+    [padType](auto &entry) { return entry.type == padType; }
+);
+sprintf(m_textBuffer, "%s", (it != std::end(padTypeMap)) ? it->name : "Unknown");

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 156-200: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/mips/psyqo/advancedpad.hh (3)

145-184: Enhance documentation for ADC getter methods.

The documentation for the ADC getter methods could be more helpful by including:

  • Value ranges (e.g., 0-255)
  • Typical use cases (e.g., analog stick position, pressure sensitivity)
  • Mapping of values to physical controls for different pad types

185-207: Consider adding bounds checking for the index parameter.

The method silently returns 0 for invalid indices, which could mask errors. Consider:

  1. Adding a precondition check for the index parameter
  2. Throwing an exception or returning an optional/error code for invalid indices

209-221: Add safety notes to getHalfword documentation.

Since this method provides raw access to pad data, the documentation should:

  • Warn about the low-level nature of the method
  • Explain the data format for each index
  • Recommend using the higher-level methods when possible
src/mips/psyqo/examples/multitap/multitap.cpp (2)

101-111: Consider moving color constants to class scope.

The WHITE and GRAY color constants are defined as static within the method. Consider moving them to class scope to:

  • Avoid recreation on each call
  • Allow reuse in other methods
  • Make them configurable if needed

113-122: LGTM! Consider moving pad names to class scope.

The implementation is clean and efficient. Consider moving the padNames array to class scope to:

  • Make it configurable
  • Avoid recreation on each call
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0631089 and 929e76f.

📒 Files selected for processing (2)
  • src/mips/psyqo/advancedpad.hh (2 hunks)
  • src/mips/psyqo/examples/multitap/multitap.cpp (6 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/examples/multitap/multitap.cpp

[warning] 163-206: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: asan
  • GitHub Check: aur-build
  • GitHub Check: build
  • GitHub Check: coverage
  • GitHub Check: toolchain
  • GitHub Check: cross-arm64
🔇 Additional comments (3)
src/mips/psyqo/advancedpad.hh (1)

234-247: LGTM! Good encapsulation of implementation details.

Moving the Command enum to private section is a good practice as these are internal implementation details.

src/mips/psyqo/examples/multitap/multitap.cpp (2)

163-206: Refactor suggestion from previous review still applies.

The method's cyclomatic complexity is high. The previous review's suggestion to use a lookup table would improve maintainability.

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 163-206: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


220-222: LGTM! Clean and well-organized implementation.

The frame method effectively uses the new helper methods, providing a clear separation of concerns.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 929e76f and e73f7fd.

📒 Files selected for processing (2)
  • src/mips/psyqo/advancedpad.hh (2 hunks)
  • src/mips/psyqo/examples/multitap/multitap.cpp (6 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/examples/multitap/multitap.cpp

[warning] 163-206: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: toolchain
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: build
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: aur-build
  • GitHub Check: asan
🔇 Additional comments (6)
src/mips/psyqo/advancedpad.hh (2)

145-185: Well-documented and efficiently implemented analog input getters!

The implementation provides clear documentation about the meaning of values (e.g., "00h=Left, 80h=Center, FFh=Right") and uses efficient bit manipulation to extract the values.


242-255: Good encapsulation of low-level commands!

Moving the Command enum to private section improves encapsulation by hiding implementation details.

src/mips/psyqo/examples/multitap/multitap.cpp (4)

105-112: Clean implementation of variadic print method!

The implementation correctly handles variable arguments with proper va_start/va_end usage.


219-222: Clean and focused frame implementation!

The method has a clear separation of concerns, delegating to specific print methods.


163-206: 🛠️ Refactor suggestion

Refactor to reduce complexity and prevent potential issues.

The method has high cyclomatic complexity and potential safety issues:

  1. Large switch statement increases complexity
  2. padTypeStr could theoretically be used uninitialized if switch falls through

Consider using a static lookup table:

+    static const struct {
+        PadType type;
+        const char* name;
+    } padTypeMap[] = {
+        { PadType::Mouse, "Mouse" },
+        { PadType::NegCon, "NegCon" },
+        { PadType::KonamiLightgun, "KonamiLightgun" },
+        { PadType::DigitalPad, "DigitalPad" },
+        { PadType::AnalogStick, "AnalogStick" },
+        { PadType::NamcoLightgun, "NamcoLightgun" },
+        { PadType::AnalogPad, "AnalogPad" },
+        { PadType::Multitap, "Multitap" },
+        { PadType::Jogcon, "Jogcon" },
+        { PadType::ConfigMode, "ConfigMode" },
+        { PadType::None, "None" },
+    };
+
+    const auto it = std::find_if(std::begin(padTypeMap), std::end(padTypeMap),
+        [padType](const auto& entry) { return entry.type == padType; });
+    
+    const char* padTypeStr = (it != std::end(padTypeMap)) ? it->name : "Unknown";

Likely invalid or redundant comment.

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 163-206: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


125-161: Add bounds checking for adcBytes calculation.

The calculation of adcBytes from halfWords lacks bounds checking. While unlikely, corrupted pad data could lead to buffer overflow.

Consider adding explicit bounds check:

-    const auto adcBytes = (halfWords - 1) * 2;
+    const auto adcBytes = std::min((halfWords - 1) * 2, 8u);  // Limit to maximum possible ADC bytes

Comment on lines 187 to 210
/**
* @brief Returns the state of an Analog Input.
*
* @details See the specific Analog Input functions for details.
* The index is modulo 4, so it will wrap around if it is greater than 3.
*
* @param pad The pad to query.
* @param index The index of the Analog Input.
* @return The state of the Analog Input as an unsigned 8-bit value(0-255).
*/
uint8_t getAdc(Pad pad, unsigned int index) const {
switch (index) {
case 0:
return getAdc0(pad);
case 1:
return getAdc1(pad);
case 2:
return getAdc2(pad);
case 3:
return getAdc3(pad);
default:
return 0;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix documentation or implementation mismatch for index wrapping.

The documentation states "The index is modulo 4, so it will wrap around if it is greater than 3", but the implementation returns 0 for indices > 3 instead of wrapping.

Consider one of these fixes:

-    switch (index) {
+    switch (index % 4) {

or update the documentation to reflect the current behavior:

-     * The index is modulo 4, so it will wrap around if it is greater than 3.
+     * Indices greater than 3 will return 0.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @brief Returns the state of an Analog Input.
*
* @details See the specific Analog Input functions for details.
* The index is modulo 4, so it will wrap around if it is greater than 3.
*
* @param pad The pad to query.
* @param index The index of the Analog Input.
* @return The state of the Analog Input as an unsigned 8-bit value(0-255).
*/
uint8_t getAdc(Pad pad, unsigned int index) const {
switch (index) {
case 0:
return getAdc0(pad);
case 1:
return getAdc1(pad);
case 2:
return getAdc2(pad);
case 3:
return getAdc3(pad);
default:
return 0;
}
}
/**
* @brief Returns the state of an Analog Input.
*
* @details See the specific Analog Input functions for details.
* The index is modulo 4, so it will wrap around if it is greater than 3.
*
* @param pad The pad to query.
* @param index The index of the Analog Input.
* @return The state of the Analog Input as an unsigned 8-bit value(0-255).
*/
uint8_t getAdc(Pad pad, unsigned int index) const {
switch (index % 4) {
case 0:
return getAdc0(pad);
case 1:
return getAdc1(pad);
case 2:
return getAdc2(pad);
case 3:
return getAdc3(pad);
default:
return 0;
}
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/mips/psyqo/advancedpad.hh (1)

212-229: ⚠️ Potential issue

Fix documentation or implementation mismatch for index wrapping.

The documentation states "The index is modulo 4, so it will wrap around if it is greater than 3", but the implementation returns undefined behavior for indices > 3 due to direct array access.

Consider adding bounds checking:

-    uint16_t getHalfword(Pad pad, unsigned int index) const { return m_padData[pad][index % 4]; }
+    uint16_t getHalfword(Pad pad, unsigned int index) const {
+        const auto safeIndex = index % 4;
+        return m_padData[pad][safeIndex];
+    }
🧹 Nitpick comments (2)
src/mips/psyqo/advancedpad.hh (2)

197-210: Consider using array indexing for better maintainability.

The switch case could be simplified using array indexing, which would be more maintainable and potentially more efficient.

-    uint8_t getAdc(Pad pad, unsigned int index) const {
-        switch (index) {
-            case 0:
-                return getAdc0(pad);
-            case 1:
-                return getAdc1(pad);
-            case 2:
-                return getAdc2(pad);
-            case 3:
-                return getAdc3(pad);
-            default:
-                return 0;
-        }
-    }
+    uint8_t getAdc(Pad pad, unsigned int index) const {
+        static constexpr auto getters[] = {
+            &AdvancedPad::getAdc0,
+            &AdvancedPad::getAdc1,
+            &AdvancedPad::getAdc2,
+            &AdvancedPad::getAdc3
+        };
+        return index < 4 ? (this->*getters[index])(pad) : 0;
+    }

231-239: Enhance documentation for getPadType method.

The documentation could be more helpful by:

  1. Referencing the PadType enum values that could be returned
  2. Explaining how this relates to isPadConnected
  3. Noting any special cases or invalid states
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e73f7fd and af630c4.

📒 Files selected for processing (1)
  • src/mips/psyqo/advancedpad.hh (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: toolchain
  • GitHub Check: cross-arm64
  • GitHub Check: coverage
🔇 Additional comments (2)
src/mips/psyqo/advancedpad.hh (2)

5-5: LGTM!

Copyright year correctly updated to 2025.


242-255: LGTM! Good encapsulation of implementation details.

Moving the Command enum to private scope is a good practice as these are internal implementation details that shouldn't be exposed to users of the class.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/mips/psyqo/advancedpad.hh (1)

147-187: Consider optimizing the ADC access methods.

The implementation is correct and well-documented. However, consider these potential optimizations:

  1. The switch statement could be replaced with array indexing for better performance
  2. The individual getAdc0-3 methods could be implemented in terms of getAdc for better maintainability
-    uint8_t getAdc(Pad pad, unsigned int index) const {
-        switch (index) {
-            case 0:
-                return getAdc0(pad);
-            case 1:
-                return getAdc1(pad);
-            case 2:
-                return getAdc2(pad);
-            case 3:
-                return getAdc3(pad);
-            default:
-                return 0;
-        }
-    }
+    uint8_t getAdc(Pad pad, unsigned int index) const {
+        static const auto getters[] = {
+            &AdvancedPad::getAdc0,
+            &AdvancedPad::getAdc1,
+            &AdvancedPad::getAdc2,
+            &AdvancedPad::getAdc3
+        };
+        return index < 4 ? (this->*getters[index])(pad) : 0;
+    }

Also applies to: 189-212

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af630c4 and f3ee66e.

📒 Files selected for processing (2)
  • src/mips/psyqo/advancedpad.hh (4 hunks)
  • src/mips/psyqo/src/advancedpad.cpp (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: build-openbios
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: aur-build
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: asan
  • GitHub Check: build
  • GitHub Check: toolchain
🔇 Additional comments (7)
src/mips/psyqo/src/advancedpad.cpp (2)

117-117: LGTM! Consistent enum class handling.

All array accesses properly use static_cast<unsigned> for the enum class values.

Also applies to: 123-123, 127-128, 138-138


51-58: LGTM! Proper use of scoped enum.

The pad processing correctly uses the new Pad:: scope for enum values.

src/mips/psyqo/advancedpad.hh (5)

5-5: LGTM!

Copyright year correctly updated to 2025.


45-45: Great improvements to type safety and encapsulation!

  • Converting Pad to a scoped enum class with explicit unsigned type improves type safety
  • Moving Command enum to private section properly encapsulates implementation details

Also applies to: 246-259


131-131: LGTM!

Methods correctly updated to handle the new enum class type using static_cast.

Also applies to: 143-145


233-243: LGTM!

The getPadType method correctly extracts and returns the pad type from the raw data.


214-231: Verify the index wrapping behavior.

The implementation now correctly matches the documentation using the modulo operator. However, let's verify that this change doesn't break any existing code.

✅ Verification successful

Index wrapping implementation verified as safe and correct

The modulo operator implementation matches the documented behavior exactly, and no existing code in the codebase uses this method, making this change completely safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for calls to getHalfword with index parameter
rg -p "getHalfword.*\([^,]+,\s*(\d+|[^)]+)\)" --type cpp

Length of output: 213


Script:

#!/bin/bash
# Search for any derived classes
ast-grep --pattern 'class $_ : $$$AdvancedPad$$$'

# Search for test files
fd -e cpp -e cc test
fd -e cpp -e cc -e hh -e h mock

# Search for any indirect usage patterns
rg -p "getHalfword" --type cpp -A 2 -B 2

Length of output: 3634


Script:

#!/bin/bash
# Check the padtest example
cat src/mips/psyqo/examples/padtest/padtest.cpp

Length of output: 6689

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/mips/psyqo/advancedpad.hh (1)

205-205: Return Enum Type for getPadType

To enhance type safety and clarity, consider returning PadType instead of uint8_t in getPadType.

Apply this diff to update the return type:

-        uint8_t getPadType(Pad pad) const { return m_padData[static_cast<unsigned>(pad)][0] >> 8; }
+        PadType getPadType(Pad pad) const { return static_cast<PadType>(m_padData[static_cast<unsigned>(pad)][0] >> 8); }

Ensure that all callers handle the PadType enum appropriately.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3ee66e and 131796e.

📒 Files selected for processing (1)
  • src/mips/psyqo/advancedpad.hh (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: build
  • GitHub Check: asan
  • GitHub Check: toolchain
  • GitHub Check: aur-build
  • GitHub Check: cross-arm64
  • GitHub Check: coverage
  • GitHub Check: macos-build-and-test-toolchain
🔇 Additional comments (6)
src/mips/psyqo/advancedpad.hh (6)

45-45: Improved Type Safety with Scoped Enum

Changing Pad to a scoped enum class enhances type safety by preventing implicit conversions. This is a good practice.


131-131: Ensure Consistent Use of static_cast

Updating isPadConnected to use static_cast<unsigned>(pad) ensures compatibility with the new Pad enum class. Good job maintaining consistency.


185-186: Clarify Documentation Regarding Index Wrapping

The comment states, "The index is modulo 4, so it will wrap around if it is greater than 3." However, in getAdc, indices greater than 3 return 0 instead of wrapping.

Ensure the documentation accurately reflects the implementation in both methods for consistency.


208-221: Visibility Change of Command Enum

Moving the Command enum to the private section restricts its access, which is appropriate if it's not intended for public use.


161-174: 🛠️ Refactor suggestion

Consistency in Handling Invalid Indices in getAdc

The getAdc method returns 0 for indices greater than 3, while getHalfword wraps the index using modulo 4. This inconsistency might confuse users.

Consider aligning the behavior by applying the modulo operation to the index in getAdc:

-        switch (index) {
+        switch (index % 4) {

Alternatively, update the documentation to reflect that indices greater than 3 will return 0.

Likely invalid or redundant comment.


143-145: Verify Button Indexing Logic

Ensure that the button indexing in isButtonPressed correctly maps to the Button enum values. Verify that each button corresponds to the intended bit position.

Run the following script to check the correctness of button bit positions:

✅ Verification successful

Button Indexing Implementation is Correct

The button indexing logic in isButtonPressed correctly maps to the Button enum values. Each button value (0-15) corresponds to its intended bit position in the 16-bit pad data, with proper active-low signal handling.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that Button enum values correspond to correct bit positions.
# Expected: Button values should range from 0 to 15 and map to the appropriate bits.

# Extract Button enum values
ast-grep --pattern $'enum Button {\n  $$$\n};' \
   | grep -oP '\w+\s*=\s*\d+' \
   | awk -F'=' '{print $1, $2}' \
   | while read -r button value; do
       bit=$((1 << value))
       printf "%s (value: %s) should correspond to bit: 0x%X\n" "$button" "$value" "$bit"
     done

Length of output: 122


Script:

#!/bin/bash
# Let's first get the Button enum declaration with context
echo "=== Button enum declaration ==="
rg -U "enum\s+(?:class\s+)?Button" src/mips/psyqo/advancedpad.hh -A 20

echo -e "\n=== Pad data structure and related definitions ==="
rg "m_padData" src/mips/psyqo/advancedpad.hh -B 2 -A 2

echo -e "\n=== Any documentation about button mapping ==="
rg -B 2 -A 2 "Button" src/mips/psyqo/advancedpad.hh

Length of output: 2950

@johnbaumann
Copy link
Collaborator Author

Actionable comments posted: 0

🧹 Nitpick comments (1)

src/mips/psyqo/advancedpad.hh (1)> 205-205: Return Enum Type for getPadType

To enhance type safety and clarity, consider returning PadType instead of uint8_t in getPadType.
Apply this diff to update the return type:

-        uint8_t getPadType(Pad pad) const { return m_padData[static_cast<unsigned>(pad)][0] >> 8; }
+        PadType getPadType(Pad pad) const { return static_cast<PadType>(m_padData[static_cast<unsigned>(pad)][0] >> 8); }

Ensure that all callers handle the PadType enum appropriately.

📜 Review details

uint8_t makes more sense here, because the function could return unknown and undocumented PadType values. Silly wabbit!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/mips/psyqo/advancedpad.hh (1)

161-176: Consider simplifying the index selection logic.

The switch statement could be simplified using array indexing for better maintainability.

-        switch (index) {
-            case 0:
-                return m_padData[padIndex].adc[0];
-            case 1:
-                return m_padData[padIndex].adc[1];
-            case 2:
-                return m_padData[padIndex].adc[2];
-            case 3:
-                return m_padData[padIndex].adc[3];
-            default:
-                return 0;
-        }
+        return index <= 3 ? m_padData[padIndex].adc[index] : 0;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 131796e and 2e21c2f.

📒 Files selected for processing (2)
  • src/mips/psyqo/advancedpad.hh (5 hunks)
  • src/mips/psyqo/src/advancedpad.cpp (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mips/psyqo/src/advancedpad.cpp
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: coverage
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: asan
  • GitHub Check: aur-build
  • GitHub Check: build
  • GitHub Check: cross-arm64
  • GitHub Check: toolchain
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
src/mips/psyqo/advancedpad.hh (4)

5-5: LGTM: Copyright year update is appropriate.


45-45: Well-structured enum improvements!

Good changes:

  • Converting Pad to a scoped enum class improves type safety
  • Explicit unsigned type prevents potential sign issues
  • Moving Command to private section properly encapsulates implementation details

Also applies to: 212-225


209-209: Appropriate use of uint8_t for getPadType.

Good decision to use uint8_t instead of PadType enum as the return type, as it allows handling unknown pad types that might not be documented in the enum.


240-248: Well-designed data structure!

The PadData union effectively combines:

  • Structured access through named fields
  • Raw access through packed array
  • Efficient memory layout

Also applies to: 250-250

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/mips/psyqo/advancedpad.hh (2)

188-198: Consider using PadType enum with unknown value handling.

While returning uint8_t allows for handling unknown pad types, consider using the PadType enum with an additional Unknown value to maintain type safety while supporting undocumented values:

-    uint8_t getPadType(Pad pad) const { return m_padData[static_cast<unsigned>(pad)].padType; }
+    PadType getPadType(Pad pad) const {
+        uint8_t type = m_padData[static_cast<unsigned>(pad)].padType;
+        switch (type) {
+            case Mouse: return PadType::Mouse;
+            case NegCon: return PadType::NegCon;
+            // ... other known types ...
+            default: return PadType::Unknown;
+        }
+    }

Line range hint 251-274: Consider adding a named constant for clarity.

The bitwise AND with 7 ensures the pad index stays within range, but consider adding a named constant to make the code more self-documenting:

+    static constexpr unsigned PAD_INDEX_MASK = 0x7;  // 8 possible pad values (0-7)

     // operators implementation
-    return pad = static_cast<psyqo::AdvancedPad::Pad>((static_cast<unsigned>(pad) + 1) & 7);
+    return pad = static_cast<psyqo::AdvancedPad::Pad>((static_cast<unsigned>(pad) + 1) & PAD_INDEX_MASK);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e21c2f and 3215462.

📒 Files selected for processing (1)
  • src/mips/psyqo/advancedpad.hh (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: build
  • GitHub Check: toolchain
  • GitHub Check: aur-build
  • GitHub Check: asan
  • GitHub Check: macos-build-and-test-toolchain
🔇 Additional comments (6)
src/mips/psyqo/advancedpad.hh (6)

5-5: LGTM: Copyright year is up to date.


45-45: Great improvement: Enhanced type safety with enum class.

The conversion to enum class with explicit unsigned type prevents accidental implicit conversions and makes the code more type-safe. The explicit static_cast usage throughout the code properly handles this change.


147-165: LGTM: Well-implemented analog input retrieval.

The getAdc method is well-documented and includes proper bounds checking for the index parameter.


167-186: Fix documentation or implementation mismatch for index wrapping.

The documentation states "The index is modulo 4, so it will wrap around if it is greater than 3", which matches the implementation using index % 4. However, this is inconsistent with the behavior of getAdc which returns 0 for indices > 3.


201-214: LGTM: Improved encapsulation of command constants.

Moving the Command enum to private scope is a good practice as these are implementation details not needed by clients of the class.


229-237: LGTM: Well-designed data structure.

The PadData union elegantly provides both structured access to individual fields and raw access to packed data, which is useful for different access patterns while maintaining memory efficiency.

Copy link

codecov bot commented Jan 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 9.25%. Comparing base (e6f816d) to head (ceea701).
Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1815      +/-   ##
==========================================
- Coverage    9.26%    9.25%   -0.01%     
==========================================
  Files         468      468              
  Lines      144113   144115       +2     
==========================================
  Hits        13345    13345              
- Misses     130768   130770       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/mips/psyqo/examples/multitap/multitap.cpp (1)

163-209: 🛠️ Refactor suggestion

Reduce cyclomatic complexity in printPadType.

This method's complexity has been flagged by static analysis. As noted in a previous review, consider using a lookup table approach to simplify the switch statement.

Here's a simplified implementation using a lookup table:

-void MultitapTestScene::printPadType(psyqo::AdvancedPad::Pad pad, int column, const char *name) {
-    const auto padType = multitapTest.m_input.getPadType(pad);
-    const char *padTypeStr;
-
-    switch (padType) {
-        case psyqo::AdvancedPad::PadType::Mouse:
-            padTypeStr = "Mouse";
-            break;
-        // ... other cases ...
-        default:
-            padTypeStr = "Unknown";
-            break;
-    }
-    print(column + 0, 13, true, name);
-    print(column + 10, 13, true, "%s %02x", padTypeStr, padType);
+namespace {
+    struct PadTypeInfo {
+        psyqo::AdvancedPad::PadType type;
+        const char* name;
+    };
+
+    constexpr PadTypeInfo padTypeMap[] = {
+        {psyqo::AdvancedPad::PadType::Mouse, "Mouse"},
+        {psyqo::AdvancedPad::PadType::NegCon, "NegCon"},
+        {psyqo::AdvancedPad::PadType::KonamiLightgun, "KonamiLightgun"},
+        {psyqo::AdvancedPad::PadType::DigitalPad, "DigitalPad"},
+        {psyqo::AdvancedPad::PadType::AnalogStick, "AnalogStick"},
+        {psyqo::AdvancedPad::PadType::NamcoLightgun, "NamcoLightgun"},
+        {psyqo::AdvancedPad::PadType::AnalogPad, "AnalogPad"},
+        {psyqo::AdvancedPad::PadType::Multitap, "Multitap"},
+        {psyqo::AdvancedPad::PadType::Jogcon, "Jogcon"},
+        {psyqo::AdvancedPad::PadType::Fishingcon, "Fishingcon"},
+        {psyqo::AdvancedPad::PadType::ConfigMode, "ConfigMode"},
+        {psyqo::AdvancedPad::PadType::None, "None"},
+    };
+}
+
+void MultitapTestScene::printPadType(psyqo::AdvancedPad::Pad pad, int column, const char *name) {
+    const auto padType = multitapTest.m_input.getPadType(pad);
+    const char* padTypeStr = "Unknown";
+
+    for (const auto& info : padTypeMap) {
+        if (info.type == padType) {
+            padTypeStr = info.name;
+            break;
+        }
+    }
+
+    print(column + 0, 13, true, name);
+    print(column + 10, 13, true, "%s %02x", padTypeStr, padType);
}
🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 163-209: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 14, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

🧹 Nitpick comments (1)
src/mips/psyqo/examples/multitap/multitap.cpp (1)

115-122: Enhance type safety with const correctness.

Consider making the loop variable const since it's not modified within the loop.

-    for (int i = 0; i < 8; i++) {
+    for (const int i = 0; i < 8; i++) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3215462 and a1a2ae7.

📒 Files selected for processing (3)
  • src/mips/psyqo/advancedpad.hh (6 hunks)
  • src/mips/psyqo/examples/multitap/multitap.cpp (6 hunks)
  • src/mips/psyqo/src/advancedpad.cpp (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/mips/psyqo/src/advancedpad.cpp
  • src/mips/psyqo/advancedpad.hh
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/examples/multitap/multitap.cpp

[warning] 163-209: ❌ New issue: Complex Method
MultitapTestScene::printPadType has a cyclomatic complexity of 14, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: aur-build
  • GitHub Check: toolchain
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: asan
  • GitHub Check: build
  • GitHub Check: macos-build-and-test-toolchain
🔇 Additional comments (4)
src/mips/psyqo/examples/multitap/multitap.cpp (4)

5-5: LGTM: Copyright year updated correctly.

The copyright year has been updated to reflect the current year (2025).


61-68: LGTM: Well-structured helper methods and constants.

The new helper methods provide clear functionality for printing pad information, and the constants are well-organized with descriptive names.


125-161: LGTM: Well-structured pad status printing with ADC support.

The method effectively organizes button status printing and handles ADC data with clear comments explaining the bit manipulation.


48-48: Verify font rendering behavior with default template parameter.

The change from Font<1> to Font<> removes the explicit size parameter. Please verify that this doesn't affect the font rendering in the application.

@johnbaumann
Copy link
Collaborator Author

The interact fishing controller doesn't seem to get along with the multitap. Probably because of the number of halfwords, but also perhaps the controller isn't able to communicate at 1mhz.

Additionally, I may need to look back at the pointer math in the pad driver and put some better bounds checking on the array, or revise the approach completely.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/mips/psyqo/src/advancedpad.cpp (3)

5-5: Update copyright year to match current date.

The copyright year is set to 2025, which is ahead of the current date. Consider updating it to 2024 to avoid potential confusion.

-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2024 PCSX-Redux authors

152-283: Consider refactoring the readPad method to reduce complexity.

The readPad method has high cyclomatic complexity (29, threshold is 9) which makes it harder to maintain and test. Consider breaking it down into smaller, focused methods:

  1. Split multitap and default pad handling into separate methods
  2. Extract the pad data processing logic
  3. Create a dedicated method for error handling

Would you like me to propose a detailed refactoring plan to reduce the complexity?

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 156-208: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


190-195: Make the TODO comment more actionable.

While the comment explains the LED behavior issue well, it would be more helpful to:

  1. Create a tracking issue for implementing config mode
  2. Document the specific conditions that trigger this behavior
  3. Add acceptance criteria for the implementation

Would you like me to help create a tracking issue for implementing the config mode feature?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1a2ae7 and 3b85d77.

📒 Files selected for processing (1)
  • src/mips/psyqo/src/advancedpad.cpp (8 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/src/advancedpad.cpp

[warning] 156-208: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


[warning] 156-208: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: build
  • GitHub Check: aur-build
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: toolchain
  • GitHub Check: asan
  • GitHub Check: macos-build-and-test-toolchain
🔇 Additional comments (2)
src/mips/psyqo/src/advancedpad.cpp (2)

51-58: LGTM! Improved type safety and correctness.

The changes enhance type safety through:

  1. Using scoped enums for pad identifiers
  2. Proper casting from enum to array index
  3. More appropriate use of uint16_t for button states

Also applies to: 116-130


156-156: LGTM! Good use of constexpr.

Using constexpr for padDataWidth improves maintainability and compile-time safety.

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 156-208: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

@johnbaumann
Copy link
Collaborator Author

Actionable comments posted: 0

🧹 Nitpick comments (3)

src/mips/psyqo/src/advancedpad.cpp (3)> 5-5: Update copyright year to match current date.

The copyright year is set to 2025, which is ahead of the current date. Consider updating it to 2024 to avoid potential confusion.

-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2024 PCSX-Redux authors

152-283: Consider refactoring the readPad method to reduce complexity.
The readPad method has high cyclomatic complexity (29, threshold is 9) which makes it harder to maintain and test. Consider breaking it down into smaller, focused methods:

  1. Split multitap and default pad handling into separate methods
  2. Extract the pad data processing logic
  3. Create a dedicated method for error handling

Would you like me to propose a detailed refactoring plan to reduce the complexity?

🧰 Tools

🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
[warning] 156-208: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

190-195: Make the TODO comment more actionable.
While the comment explains the LED behavior issue well, it would be more helpful to:

  1. Create a tracking issue for implementing config mode
  2. Document the specific conditions that trigger this behavior
  3. Add acceptance criteria for the implementation

Would you like me to help create a tracking issue for implementing the config mode feature?

📜 Review details

You're mistaken, the current year is 2025.

Could you please propose a detailed refactoring plan to reduce the complexity?

@johnbaumann
Copy link
Collaborator Author

@coderabbitai

You're mistaken, the current year is 2025.

Could you please propose a detailed refactoring plan to reduce the complexity?

Copy link
Contributor

coderabbitai bot commented Feb 16, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@johnbaumann Here's a detailed refactoring plan for the readPad method to reduce its complexity:

// 1. Split pad type detection into a separate method
private:
    enum class PadMode {
        Default,
        Multitap
    };
    
    PadMode detectPadMode(uint16_t* const padData) const {
        // Extract pad mode detection logic
        return (padData[0] == 0x5a53) ? PadMode::Multitap : PadMode::Default;
    }

// 2. Extract pad data processing for default mode
    bool processDefaultPad(uint16_t* const padData) {
        // Move default pad processing logic here
        // Return success/failure status
    }

// 3. Extract multitap processing
    bool processMultitapPad(uint16_t* const padData) {
        // Move multitap processing logic here
        // Return success/failure status
    }

// 4. Create a dedicated error handler
    void handlePadError(uint16_t* const padData) {
        // Move error handling logic here
        m_error = true;
        // ... rest of error handling
    }

// 5. Extract pad data validation
    bool validatePadData(const uint16_t* const padData) const {
        // Move validation logic here
        return /* validation result */;
    }

// 6. Main method becomes a high-level orchestrator
public:
    void readPad() {
        uint16_t padData[32];
        if (!initializePadRead(padData)) {
            handlePadError(padData);
            return;
        }

        const auto mode = detectPadMode(padData);
        bool success = false;

        switch (mode) {
            case PadMode::Default:
                success = processDefaultPad(padData);
                break;
            case PadMode::Multitap:
                success = processMultitapPad(padData);
                break;
        }

        if (!success) {
            handlePadError(padData);
        }
    }

Key benefits of this refactoring:

  1. Each method has a single responsibility
  2. Easier to test individual components
  3. Improved readability and maintainability
  4. Reduced cyclomatic complexity in each method
  5. Better error handling isolation

Would you like me to elaborate on any specific part of this refactoring plan?


🏁 Script executed:

#!/bin/bash
# Get the content of the advancedpad.cpp file
cat src/mips/psyqo/src/advancedpad.cpp

Length of output: 9748


@johnbaumann Here's a detailed refactoring plan that respects the hardware-specific nature of the code:

class AdvancedPad {
private:
    // 1. Extract port configuration into a dedicated method
    void configurePort(uint8_t port) {
        SIO::Ctrl = (port * SIO::Control::CTRL_PORTSEL) | SIO::Control::CTRL_DTR;
        SIO::Baud = 0x88;  // 250kHz
        flushRxBuffer();
        SIO::Ctrl |= (SIO::Control::CTRL_TXEN | SIO::Control::CTRL_ACKIRQEN);
        busyLoop(100);  // Required delay for pad stability
    }

    // 2. Extract pad type detection
    PadType detectPadType(uint8_t dataIn, uint8_t port) {
        if (dataIn == PadType::Multitap) {
            return PadType::Multitap;
        }
        return static_cast<PadType>(dataIn);
    }

    // 3. Extract multitap data processing
    void processMultitapData(uint8_t dataIn, unsigned ticks, uint8_t* padData) {
        unsigned pad_index = ticks >= 11 ? (ticks - 3) / 8 : 0;
        
        switch (ticks) {
            case 4: case 12: case 20: case 28:  // Connection status
                padData[(padDataWidth * pad_index) + 0] = dataIn != 0x5a;
                break;
            case 3: case 11: case 19: case 27:  // ID low byte
                padData[(padDataWidth * pad_index) + 1] = dataIn;
                break;
            default:
                if (ticks > 4) {  // Data bytes
                    padData[(padDataWidth * pad_index) + ((ticks - 3) % 8)] = dataIn;
                }
        }
    }

    // 4. Extract default pad data processing
    void processDefaultPadData(uint8_t dataIn, unsigned ticks, uint8_t* padData) {
        switch (ticks) {
            case 2:  // Connection status
                padData[0] = dataIn != 0x5a;
                break;
            default:
                if (ticks > 2) {  // Data bytes
                    padData[ticks - 1] = dataIn;
                }
        }
    }

    // 5. Extract communication cycle
    bool performCommunicationCycle(uint8_t& dataIn, uint8_t dataOut) {
        SIO::Ctrl |= SIO::Control::CTRL_ERRRES;
        CPU::IReg.clear(CPU::IRQ::Controller);
        
        dataIn = transceive(dataOut);
        
        return waitForAck();
    }

    // 6. Main method becomes more structured
    void readPad() {
        uint8_t portDevType[2] = {PadType::None, PadType::None};
        uint8_t port = m_portToProbe;

        for (unsigned i = 0; i < m_portsToProbeByVSync; i++) {
            configurePort(port);
            
            uint8_t* padData = reinterpret_cast<uint8_t*>(&m_padData[port * 4].packed[0]);
            __builtin_memset(padData, 0xff, sizeof(m_padData[0]));

            if (!readPortData(port, portDevType[port], padData)) {
                handlePortError(port, padData);
            }

            SIO::Ctrl = 0;  // End transmission
            port ^= 1;
        }
        m_portToProbe = port;
    }

    // 7. Extract port reading logic
    bool readPortData(uint8_t port, PadType& portType, uint8_t* padData) {
        uint8_t dataIn;
        unsigned max_ticks = 5;

        for (unsigned ticks = 0; ticks < max_ticks; ticks++) {
            uint8_t dataOut = (portType == PadType::Multitap) 
                ? outputMultitap(ticks) 
                : outputDefault(ticks);

            if (!performCommunicationCycle(dataIn, dataOut)) {
                return false;
            }

            if (ticks == 1) {
                portType = detectPadType(dataIn, port);
            } else if (ticks == 2) {
                if (!handleIdentificationPhase(dataIn, max_ticks, padData)) {
                    return false;
                }
            } else {
                if (portType == PadType::Multitap) {
                    processMultitapData(dataIn, ticks, padData);
                } else {
                    processDefaultPadData(dataIn, ticks, padData);
                }
            }
        }
        return true;
    }
};

Key benefits of this refactoring:

  1. Each method has a clear, single responsibility
  2. Hardware-specific operations are grouped together
  3. Protocol-specific logic is separated from data processing
  4. Error handling is more localized
  5. The state machine-like structure is preserved
  6. Timing-sensitive operations remain close to each other
  7. Better testability of individual components

The refactoring maintains the original functionality while making the code more maintainable and easier to understand. Would you like me to elaborate on any specific part of this refactoring plan?


✏️ Learnings added
Learnt from: johnbaumann
URL: https://github.com/grumpycoders/pcsx-redux/pull/1815

Timestamp: 2025-02-16T17:32:25.769Z
Learning: The current year for the PCSX-Redux project is 2025, and copyright notices should reflect this year.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

nicolasnoble
nicolasnoble previously approved these changes Feb 26, 2025
Copy link
Member

@nicolasnoble nicolasnoble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of very minor nits, but otherwise good to go from my end.

@@ -143,7 +129,7 @@ class AdvancedPad {
* @param pad The pad to query.
* @return A boolean value indicating whether the pad is connected.
*/
bool isPadConnected(Pad pad) const { return (m_padData[pad][0] & 0xff) == 0; }
bool isPadConnected(Pad pad) const { return m_padData[static_cast<unsigned>(pad)].connected == 0; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be prettier to use std::to_underlying(pad) instead of the static_cast throughout this file. It comes from <utility>, and it's been added in C++23.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit shorter, but looks like we'd need to bump the whole SDK version for that change(currently on C++ 20). I'm ok with working around this with the casts for now if changing the minimum version is undesirable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah.

We could theoretically polyfill it somewhere in the codebase: https://godbolt.org/z/7r4T6nq3e

As you wish, really.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave this a shot in the latest commit

uint32_t mask = 1;
uint32_t padData = m_padData[pad][1];
uint32_t buttons = m_buttons[pad];
uint16_t mask = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Downgrading these to uint16_t will make for a worse codegen in the end. Was there a reason to do this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I probably thought I was catching a past mistake on the data type.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/mips/psyqo/src/advancedpad.cpp (1)

185-194: Consider implementing the TODOs in this PR or creating separate issues.

There are several TODOs in the code:

  1. Line 185: Check SIO status for errors
  2. Line 190: Implement config mode
  3. Lines 191-193: Handle the case when pad returns 0x00 for idhi

Consider implementing these TODOs as part of this PR or create separate issues to track them.

Would you like me to help create issues for these TODOs or suggest implementations for any of them?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7ecace and 6ee8271.

📒 Files selected for processing (1)
  • src/mips/psyqo/src/advancedpad.cpp (8 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/src/advancedpad.cpp

[warning] 168-269: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


[warning] 168-269: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: toolchain
  • GitHub Check: cross-arm64
  • GitHub Check: build
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: coverage
  • GitHub Check: aur-build
  • GitHub Check: asan
🔇 Additional comments (11)
src/mips/psyqo/src/advancedpad.cpp (11)

5-5: Copyright year updated to 2025.

The copyright year has been updated from 2024 to 2025, which is appropriate for new contributions.


51-58: Properly using scoped enum class for pad identifiers.

The code now uses the scoped enum Pad::Pad1a instead of raw integers, which improves type safety and code clarity.


62-68: Good extraction of common port configuration logic.

The new configurePort method effectively centralizes the SIO port configuration logic that was previously duplicated, improving maintainability and reducing the chance of inconsistencies.


77-77: Consistent variable naming with camelCase.

Variable naming has been standardized from data_out to dataOut, improving consistency with the codebase's naming conventions.

Also applies to: 81-81, 84-84, 88-88


92-92: Consistent variable naming in outputMultitap.

The variable naming changes to camelCase have been applied consistently across methods.

Also applies to: 97-97, 105-105, 120-120


124-125: Improved type safety with static_cast for enum class.

The change to use static_cast<unsigned>(pad) as an index is necessary when working with enum classes and ensures type safety.

Also applies to: 136-138, 148-148


151-156: Good refactoring of transceive method.

The extraction of the transceive functionality into a dedicated inline method improves code organization and reusability.


169-169: Consistent variable naming for maxTicks.

Renamed max_ticks to maxTicks for consistency with camelCase naming convention used throughout the codebase.

Also applies to: 178-178


211-241: Clearer organization of multitap data processing.

The multitap data processing logic has been improved, with better index calculation and clearer condition for when to apply multitap processing.


264-270: Improved error handling in wait for ACK.

The error handling when waiting for ACK has been improved, with better initialization of pad data on error.


287-291: Better timeout handling with constexpr.

Good use of static constexpr for the timeout value and improved condition check.

Comment on lines +168 to 206
static constexpr unsigned padDataWidth = sizeof(PadData);
const unsigned portsToProbeByVSync = m_portsToProbeByVSync;
uint8_t port = m_portToProbe;

for (unsigned i = 0; i < portsToProbeByVSync; i++) {
// Select enable on current port
SIO::Ctrl = (static_cast<uint16_t>(port) << 13) | SIO::Control::CTRL_DTR;

// Set baud 250kHz
SIO::Baud = 0x88;

flushRxBuffer();
configurePort(port);

// Enable transmit and IRQ on ACK
SIO::Ctrl |= (SIO::Control::CTRL_TXEN | SIO::Control::CTRL_ACKIRQEN);

// Pads get finicky if we don't wait a bit here
busyLoop(100);

uint8_t *padData = reinterpret_cast<uint8_t *>(&m_padData[port * 4][0]);
uint8_t *padData = reinterpret_cast<uint8_t *>(&m_padData[port * 4].packed[0]);
__builtin_memset(padData, 0xff, sizeof(m_padData[0]));

for (unsigned ticks = 0, max_ticks = 5; ticks < max_ticks; ticks++) {
SIO::Ctrl |= SIO::Control::CTRL_ERRRES; // Clear error
CPU::IReg.clear(CPU::IRQ::Controller); // Clear IRQ

for (unsigned ticks = 0, maxTicks = 5; ticks < maxTicks; ticks++) {
if (portDevType[port] == PadType::Multitap) {
dataOut = outputMultitap(ticks);
} else {
dataOut = outputDefault(ticks);
}
dataIn = transceive(dataOut);
// To-do: Check SIO status for errors, abort if necessary

// Set port type and total number of half-words to read
if (ticks == 2) {
if (dataIn == 0x5a) {
if (dataIn == 0x5a || dataIn == 0x00) { // Verify idhi byte
// To-do: Implement config mode
// If the LED was previously forced off, as is the case with xloader, the pad will return 0x00 for
// idhi. The pad will reset after a few seconds of no activity, but we can't wait that long. For
// now, we can just ignore this and treat it as a normal pad

// Set number of half-words to read
max_ticks = portDevType[port] & 0x0f;
if (!max_ticks) {
max_ticks = 0x10;
maxTicks = portDevType[port] & 0x0f;
if (!maxTicks) {
maxTicks = 0x10;
}
max_ticks = (max_ticks * 2) + ticks + 1;
maxTicks = (maxTicks * 2) + ticks + 1;

padData[0] = 0;
} else {
// Derp? Unknown device type or bad data, stop reading
max_ticks = ticks;
maxTicks = ticks;
padData[0] = 0xff;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor complex readPad method to reduce cyclomatic complexity.

The readPad method is flagged by static analysis for high cyclomatic complexity (29, threshold is 9) and it's getting worse. This makes the code harder to maintain and test.

Consider breaking this method into smaller, more focused methods:

  1. Create separate methods for multitap and default pad handling
  2. Extract pad data processing logic
  3. Extract error handling

This would make the code more maintainable and easier to understand.

// Example refactoring approach (partial):
-void psyqo::AdvancedPad::readPad() {
+void psyqo::AdvancedPad::readPad() {
+    uint8_t portDevType[2] = {PadType::None, PadType::None};
+    const unsigned portsToProbeByVSync = m_portsToProbeByVSync;
+    uint8_t port = m_portToProbe;
+
+    for (unsigned i = 0; i < portsToProbeByVSync; i++) {
+        readSinglePort(port, portDevType);
+        port ^= 1;
+    }
+    m_portToProbe = port;
+}
+
+void psyqo::AdvancedPad::readSinglePort(uint8_t port, uint8_t* portDevType) {
+    configurePort(port);
+    uint8_t* padData = reinterpret_cast<uint8_t*>(&m_padData[port * 4].packed[0]);
+    __builtin_memset(padData, 0xff, sizeof(m_padData[0]));
+    
+    unsigned maxTicks = 5;
+    for (unsigned ticks = 0; ticks < maxTicks; ticks++) {
+        bool shouldContinue = processPortTick(port, ticks, maxTicks, padData, portDevType);
+        if (!shouldContinue) break;
+    }
+    
+    // End transmission
+    SIO::Ctrl = 0;
+}

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 168-269: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
src/mips/psyqo/utility-polyfill.h (1)

5-5: Update copyright year to match current date.

The copyright year is set to 2025, but the current date is February 2025. This is a minor issue and might be intentional to cover future modifications in the current year.

-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2023-2025 PCSX-Redux authors
src/mips/psyqo/src/advancedpad.cpp (2)

5-5: Update copyright year to match current date.

The copyright year is set to 2025, but the current date is February 2025. This is a minor issue and might be intentional to cover future modifications in the current year.

-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2023-2025 PCSX-Redux authors

179-207: Consider improving variable names for better clarity.

The variable maxTicks is used in a confusing way - it's initially set to 5 but then potentially updated multiple times. This makes the code harder to follow.

Consider renaming variables for clarity:

-for (unsigned ticks = 0, maxTicks = 5; ticks < maxTicks; ticks++) {
+for (unsigned ticks = 0, initialMaxTicks = 5, maxTicks = initialMaxTicks; ticks < maxTicks; ticks++) {

Or better yet, structuring the loop differently to make the flow more clear:

-for (unsigned ticks = 0, maxTicks = 5; ticks < maxTicks; ticks++) {
+unsigned maxTicks = 5;
+for (unsigned ticks = 0; ticks < maxTicks; ticks++) {
src/mips/psyqo/advancedpad.hh (3)

5-5: Update copyright year to match current date.

The copyright year is set to 2025, but the current date is February 2025. This is a minor issue and might be intentional to cover future modifications in the current year.

-Copyright (c) 2025 PCSX-Redux authors
+Copyright (c) 2023-2025 PCSX-Redux authors

164-168: Consider returning PadType enum instead of uint8_t.

The getAdc method implementation is correct, but for better clarity, consider adding bounds checking with a more explicit error message.

uint8_t getAdc(Pad pad, unsigned int index) const {
    const unsigned padIndex = toUnderlying(pad);
-
-    return index <= 7 ? m_padData[padIndex].adc[index] : 0;
+    
+    if (index > 7) {
+        return 0; // Invalid index
+    }
+    
+    return m_padData[padIndex].adc[index];
}

199-199: Consider returning PadType enum instead of uint8_t.

For better type safety and clarity, consider returning the PadType enum instead of uint8_t. This would make the API more self-documenting and reduce the chance of errors.

-uint8_t getPadType(Pad pad) const { return m_padData[toUnderlying(pad)].padType; }
+PadType getPadType(Pad pad) const { return static_cast<PadType>(m_padData[toUnderlying(pad)].padType); }

However, if this function needs to return unknown/undocumented PadType values, then using uint8_t might be more appropriate.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ee8271 and 0b1141a.

📒 Files selected for processing (3)
  • src/mips/psyqo/advancedpad.hh (7 hunks)
  • src/mips/psyqo/src/advancedpad.cpp (9 hunks)
  • src/mips/psyqo/utility-polyfill.h (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)
src/mips/psyqo/src/advancedpad.cpp

[warning] 169-270: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.


[warning] 169-270: ❌ Getting worse: Complex Method
psyqo::AdvancedPad::readPad increases in cyclomatic complexity from 28 to 29, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

⏰ Context from checks skipped due to timeout of 90000ms (11)
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: toolchain
  • GitHub Check: aur-build
  • GitHub Check: asan
  • GitHub Check: build-openbios
  • GitHub Check: coverage
  • GitHub Check: cross-arm64
  • GitHub Check: build
🔇 Additional comments (13)
src/mips/psyqo/utility-polyfill.h (1)

32-38: Good implementation of toUnderlying utility function.

This is a clean implementation of a utility function that safely converts enum values to their underlying types. The use of the Enum concept ensures type safety by restricting the template to enum types only.

src/mips/psyqo/src/advancedpad.cpp (6)

52-59: Good conversion to scoped enum references.

The code correctly updates the references to use the new scoped enum format, which improves type safety and code clarity.


63-69: Excellent extraction of port configuration logic.

The common port configuration logic has been extracted into a dedicated method, which improves code organization and maintainability by reducing duplication.


77-89: Consistent variable naming with dataOut.

The variable naming has been updated from data_out to dataOut for better consistency throughout the codebase.


92-121: Consistent variable naming in outputMultitap.

Similar to the previous method, the variable naming has been standardized to use camelCase.


124-150: Good use of toUnderlying for type safety.

The code now properly uses the toUnderlying function when accessing array elements indexed by enum values, which improves type safety.


165-207: 🛠️ Refactor suggestion

Consider refactoring the complex readPad method.

The readPad method continues to have high cyclomatic complexity (29, threshold is 9) as flagged by static analysis. This makes the code harder to maintain and test.

Consider breaking this method into smaller, more focused methods:

  1. Create separate methods for multitap and default pad handling
  2. Extract pad data processing logic
  3. Extract error handling

This would make the code more maintainable and easier to understand.

// Example refactoring approach (partial):
-void psyqo::AdvancedPad::readPad() {
+void psyqo::AdvancedPad::readPad() {
+    uint8_t portDevType[2] = {PadType::None, PadType::None};
+    const unsigned portsToProbeByVSync = m_portsToProbeByVSync;
+    uint8_t port = m_portToProbe;
+
+    for (unsigned i = 0; i < portsToProbeByVSync; i++) {
+        readSinglePort(port, portDevType);
+        port ^= 1;
+    }
+    m_portToProbe = port;
+}
+
+void psyqo::AdvancedPad::readSinglePort(uint8_t port, uint8_t* portDevType) {
+    configurePort(port);
+    uint8_t* padData = reinterpret_cast<uint8_t *>(&m_padData[port * 4].packed[0]);
+    __builtin_memset(padData, 0xff, sizeof(m_padData[0]));
+    
+    unsigned maxTicks = 5;
+    for (unsigned ticks = 0; ticks < maxTicks; ticks++) {
+        bool shouldContinue = processPortTick(port, ticks, maxTicks, padData, portDevType);
+        if (!shouldContinue) break;
+    }
+    
+    // End transmission
+    SIO::Ctrl = 0;
+}
src/mips/psyqo/advancedpad.hh (6)

47-47: Good conversion to scoped enum class.

Changing Pad from a regular enum to a scoped enum class improves type safety and reduces potential for naming conflicts.


134-134: Good use of toUnderlying in isPadConnected.

The method has been updated to use toUnderlying when accessing the m_padData array, which ensures type safety.


146-148: Good use of toUnderlying in isButtonPressed.

The method has been updated to use toUnderlying when accessing the m_padData array, which ensures type safety.


187-187: Fix documentation or implementation mismatch for index wrapping.

The documentation states "The index is modulo 4, so it will wrap around if it is greater than 3", and the implementation correctly uses modulo operator for wrapping.


232-241: Good use of union for structured data access.

The change from a 2D array to a union with a structured view improves code clarity by providing named fields for the different components of pad data.


254-255: Good use of toUnderlying in operator overloads.

The increment/decrement operators have been updated to use toUnderlying, which ensures type safety and compatibility with the new enum class.

nicolasnoble
nicolasnoble previously approved these changes Feb 27, 2025
@johnbaumann johnbaumann merged commit be5274a into grumpycoders:main Feb 27, 2025
21 of 22 checks passed
@johnbaumann johnbaumann deleted the psyqo_multitap_additions branch February 27, 2025 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants