Skip to content

Optimize PA01's matrix keyboard scanning#7394

Closed
sneone wants to merge 1 commit into
EdgeTX:mainfrom
sneone:matrix_keyboard
Closed

Optimize PA01's matrix keyboard scanning#7394
sneone wants to merge 1 commit into
EdgeTX:mainfrom
sneone:matrix_keyboard

Conversation

@sneone
Copy link
Copy Markdown
Contributor

@sneone sneone commented May 26, 2026

1.Resubmit program #7315
2.Exit key scanning when no interrupt occurs or a concurrent task is invoked.However. But,I'm not sure if this function is intended to be called concurrently.

Summary by CodeRabbit

  • Refactor
    • Optimized key polling logic with early exit conditions to reduce unnecessary scanning operations during specific system states and concurrent read scenarios.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

The change adds two early return points to pollKeys(): one when reads are disabled and the nonReadCount threshold is not met, and another when concurrent reads are detected after restoring keyState, both preventing unnecessary matrix scanning for those invocations.

Changes

Early Exit Conditions in Key Polling

Layer / File(s) Summary
Early returns for nonReadCount and concurrency guard
radio/src/targets/pa01/key_driver.cpp
Two early returns are added to pollKeys(): one exits after incrementing nonReadCount when reads are disabled, and another exits after restoring keyState when the concurrency guard detects simultaneous reads, both skipping matrix scanning.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks the required template structure with 'Fixes #' and 'Summary of changes' sections, and contains unclear/grammatical issues that obscure the actual changes being made. Reformat using the repository template with proper sections. Clarify the concurrency concern and explain why this optimization is safe despite the author's uncertainty.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main optimization to PA01's keyboard matrix scanning logic with early exits.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
radio/src/targets/pa01/key_driver.cpp (2)

109-111: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pre-existing concurrency guard bug: missing early return.

When ui8ReadInProgress != 0, another thread is already scanning the matrix. The code sets keyState but continues to line 114 and increments the counter, allowing concurrent access to syncelem.ui8ReadInProgress. According to the cross-target pattern (pl18 in context snippet 3), this check should return immediately.

While the second check at line 117 (with the new return at line 119) mitigates this, the first check should also return to fully prevent concurrent access.

🔒 Proposed fix: add early return
 if (syncelem.ui8ReadInProgress != 0) {
   keyState = syncelem.oldResult;
+  return;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@radio/src/targets/pa01/key_driver.cpp` around lines 109 - 111, When
syncelem.ui8ReadInProgress != 0 the code currently sets keyState =
syncelem.oldResult but continues executing and increments the concurrency
counter; change this by making the branch return immediately after setting
keyState to syncelem.oldResult to avoid touching syncelem.ui8ReadInProgress
(i.e., add an early return in the same if that checks
syncelem.ui8ReadInProgress). Locate the check using syncelem.ui8ReadInProgress
and keyState in key_driver.cpp and ensure the function exits right after
assigning syncelem.oldResult so no further access (like the counter increment)
occurs.

86-87: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: OR operation causes sticky key state.

The |= operator sets the ENT bit when pressed but never clears it when released during early-return cycles. Since keyState is static (persists across calls), previously-pressed keys remain set even after release until the next full matrix scan. This causes keys to appear stuck.

When taking the early-return path, either properly update the ENT bit (set if pressed, clear if released) or leave keyState unmodified and rely on the cached state.

🔧 Proposed fix: properly update ENT bit
-  if (gpio_read(KEYS_GPIO_ENTER) == 0)
-    keyState |= 1<<ENT;
+  if (gpio_read(KEYS_GPIO_ENTER) == 0)
+    keyState |= 1<<ENT;
+  else
+    keyState &= ~(1<<ENT);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@radio/src/targets/pa01/key_driver.cpp` around lines 86 - 87, The early-return
branch currently uses "keyState |= 1<<ENT" which sets the ENT bit but never
clears it, causing sticky keys because keyState is static; change that logic so
the ENT bit is explicitly updated based on gpio_read(KEYS_GPIO_ENTER): if
gpio_read(KEYS_GPIO_ENTER) == 0 then set the bit (keyState |= 1<<ENT) else clear
the bit (keyState &= ~(1<<ENT)); alternatively, if the early-return should not
touch the cached value, leave keyState unchanged—locate the use of keyState,
KEYS_GPIO_ENTER, and ENT and replace the single |= update with the conditional
set/clear using the 1<<ENT mask.
🧹 Nitpick comments (1)
radio/src/targets/pa01/key_driver.cpp (1)

90-90: 💤 Low value

Fix comment spacing.

Missing space after comma.

✏️ Proposed fix
-  //If no interrupt occurs, it means no key is pressed, so no scanning is needed this time,exit.
+  //If no interrupt occurs, it means no key is pressed, so no scanning is needed this time, exit.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@radio/src/targets/pa01/key_driver.cpp` at line 90, Update the inline comment
that currently reads "//If no interrupt occurs, it means no key is pressed, so
no scanning is needed this time,exit." to fix spacing after the comma by adding
a space before "exit."—i.e., change ",exit." to ", exit."; locate this comment
in key_driver.cpp (the comment text itself) and apply the single-character
spacing fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@radio/src/targets/pa01/key_driver.cpp`:
- Around line 109-111: When syncelem.ui8ReadInProgress != 0 the code currently
sets keyState = syncelem.oldResult but continues executing and increments the
concurrency counter; change this by making the branch return immediately after
setting keyState to syncelem.oldResult to avoid touching
syncelem.ui8ReadInProgress (i.e., add an early return in the same if that checks
syncelem.ui8ReadInProgress). Locate the check using syncelem.ui8ReadInProgress
and keyState in key_driver.cpp and ensure the function exits right after
assigning syncelem.oldResult so no further access (like the counter increment)
occurs.
- Around line 86-87: The early-return branch currently uses "keyState |= 1<<ENT"
which sets the ENT bit but never clears it, causing sticky keys because keyState
is static; change that logic so the ENT bit is explicitly updated based on
gpio_read(KEYS_GPIO_ENTER): if gpio_read(KEYS_GPIO_ENTER) == 0 then set the bit
(keyState |= 1<<ENT) else clear the bit (keyState &= ~(1<<ENT)); alternatively,
if the early-return should not touch the cached value, leave keyState
unchanged—locate the use of keyState, KEYS_GPIO_ENTER, and ENT and replace the
single |= update with the conditional set/clear using the 1<<ENT mask.

---

Nitpick comments:
In `@radio/src/targets/pa01/key_driver.cpp`:
- Line 90: Update the inline comment that currently reads "//If no interrupt
occurs, it means no key is pressed, so no scanning is needed this time,exit." to
fix spacing after the comma by adding a space before "exit."—i.e., change
",exit." to ", exit."; locate this comment in key_driver.cpp (the comment text
itself) and apply the single-character spacing fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a33761a7-c827-42c9-95c9-f57755c7387e

📥 Commits

Reviewing files that changed from the base of the PR and between 00d7544 and 7cfa65f.

📒 Files selected for processing (1)
  • radio/src/targets/pa01/key_driver.cpp

@richardclli
Copy link
Copy Markdown
Member

Seems not correct, reverted many changes in #7315, let me rework this using AI coder

@richardclli
Copy link
Copy Markdown
Member

Replaced by #7405

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