-
-
Notifications
You must be signed in to change notification settings - Fork 8
using a unique low level semaphore to prevent simultaneous access to pixel data #82
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
base: main
Are you sure you want to change the base?
Conversation
|
Note
|
| Cohort / File(s) | Summary |
|---|---|
Semaphore Consolidation src/main.cpp |
Replaced effectSemaphore and driverSemaphore with a single binary semaphore lowLevelSemaphore (volatile xSemaphoreHandle lowLevelSemaphore = xSemaphoreCreateBinary();); updated effectTask to take/give lowLevelSemaphore and conditionally call layerP.loop20ms(); updated driverTask to take/give lowLevelSemaphore and call layerP.loopDrivers(); setup() now gives lowLevelSemaphore at startup; removed old semaphore declarations and all call sites referencing them. |
Estimated code review effort
🎯 2 (Simple) | ⏱️ ~10 minutes
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title directly and accurately describes the main change: replacing two separate semaphores with a single shared semaphore to prevent simultaneous access to pixel data, which is the core objective of the PR. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
📜 Recent review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main.cpp
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main.cpp (1)
117-158: Critical: Single semaphore doesn't guarantee alternation between effect and driver tasks.The current pattern uses one semaphore with both tasks following take → process → give. This provides mutual exclusion but doesn't ensure strict alternation. After
effectTaskgives the semaphore (line 142), the FreeRTOS scheduler may alloweffectTaskto acquire it again beforedriverTaskruns, causingeffectTaskto update pixel data beforedriverTaskfinishes pushing the previous frame—the exact problem this PR aims to solve.For strict producer-consumer synchronization (effects produce data, driver consumes), use two semaphores:
🔎 Proposed fix: Use two semaphores for guaranteed alternation
-volatile xSemaphoreHandle lowLevelSemaphore = xSemaphoreCreateBinary(); +volatile xSemaphoreHandle effectSemaphore = xSemaphoreCreateBinary(); +volatile xSemaphoreHandle driverSemaphore = xSemaphoreCreateBinary();In
setup()after task creation:); + + // Initialize: allow effectTask to run first + xSemaphoreGive(effectSemaphore); #endifIn
effectTask:- if (xSemaphoreTake(lowLevelSemaphore, pdMS_TO_TICKS(100)) == pdFALSE) { + if (xSemaphoreTake(effectSemaphore, pdMS_TO_TICKS(100)) == pdFALSE) { // EXT_LOGW(ML_TAG, "effectSemaphore wait too long"); } layerP.loop(); // ... loop20ms code ... - xSemaphoreGive(lowLevelSemaphore); + xSemaphoreGive(driverSemaphore); // Signal driver to consumeIn
driverTask:- xSemaphoreTake(lowLevelSemaphore, pdMS_TO_TICKS(100)); + xSemaphoreTake(driverSemaphore, pdMS_TO_TICKS(100)); layerP.loopDrivers(); - xSemaphoreGive(lowLevelSemaphore); + xSemaphoreGive(effectSemaphore); // Signal effect can produce next frameThis ensures: effectTask produces → driverTask consumes → effectTask produces → (repeat)
🧹 Nitpick comments (2)
src/main.cpp (2)
130-132: Update comment to reflect new semaphore name.The comment references the old
effectSemaphorebut the code now useslowLevelSemaphore.🔎 Proposed fix
if (xSemaphoreTake(lowLevelSemaphore, pdMS_TO_TICKS(100)) == pdFALSE) { - // EXT_LOGW(ML_TAG, "effectSemaphore wait too long"); //happens if no driver!, but let effects continue (for monitor) at 10 fps + // EXT_LOGW(ML_TAG, "lowLevelSemaphore wait too long"); //happens if no driver!, but let effects continue (for monitor) at 10 fps }
154-154: Consider checking semaphore timeout in driverTask.Unlike
effectTask(line 130),driverTaskdoesn't check the return value ofxSemaphoreTake. If the timeout occurs,driverTaskproceeds to callloopDrivers()without confirming it has exclusive access to pixel data, potentially violating the synchronization this PR aims to establish.🔎 Proposed improvement
- xSemaphoreTake(lowLevelSemaphore, pdMS_TO_TICKS(100)); + if (xSemaphoreTake(lowLevelSemaphore, pdMS_TO_TICKS(100)) == pdFALSE) { + // Timeout occurred - skip this iteration to maintain synchronization + continue; + } layerP.loopDrivers();Or if it's safe to proceed on timeout, add a comment explaining why.
|
@coderabbitai : are we good? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 118 🏁 Script executed: Length of output: 16090 @limpkin The implementation looks solid for preventing simultaneous access to pixel data! Here's my assessment: ✅ What's working well:
💡 Minor consideration:
That said, at the same priority level, the binary semaphore approach should work fine in practice. Questions:
If your testing shows it's working as expected, this looks good to merge! 🎉 |
|
no timeouts, all tested, good to go @ewowi ! |
for large LED strips, with the current code it is possible for the effects to update the pixel data to be sent out before the driver has actually finished pushing it out.
As a consequence I'm using only a single semaphore. In the future it would be best to use double buffering techniques .
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.