Skip to content
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

Synchronise end-of-line sounds between app and firmware #731

Merged
merged 4 commits into from
Dec 13, 2024

Conversation

jonathanperret
Copy link
Contributor

@jonathanperret jonathanperret commented Dec 3, 2024

🤔 Problem

The end-of-line sounds are not synchronized between the firmware and the desktop app, fixes #617.

💡 Proposed solution

The main source of discrepancy is the fact that the desktop app closes the connection to the firmware as soon as it has sent the final pattern row. But this actually happens two full carriage passes (or one, with the garter carriage) before knitting is really complete.

The firmware itself continues to emit end-of-row sounds until the end of the last selecting row, i.e. one pass further than the desktop app.

This PR slightly changes the final row transmission logic: instead of marking the last patterning row as "final" and closing the connection, it sends that last row normally (not telling the firmware that it is the last), so that it gets the usual request for a next row from the firmware at the end of that pass, which the app now answers with a blank row.

This which lets the app emit a "work finished" sound at the same point that previous AYAB versions emitted an "end of work" beep from the hardware.

This also makes the message "Please knit until you hear the double beep sound" notification more correct, as the final pass (knitting the final selection of needles while moving them all back to B) will trigger one last sound from the hardware.

Two other minor issues around sounds are also fixed by this PR:

  • the "work finished" sound from the desktop app, in addition to being one pass early as described above, was delayed by one to two seconds — it is now synchronous with the hardware beep, making the app feel more "snappy";
  • the "simulation" mode only emitted end-of-line sounds for the first row, it now more faithfully reproduces the experience of actual knitting.

🤔 Remarks

This change may also "fix" #662, or at least reduce its impact — if the firmware now fails to "move on" from the final blank row, the result will be very close to having properly finished the process.

Also, the hardware sounds themselves need a bit of work, as for example the final "double beep sound" does not actually sound like a double beep, at least on the AYAB shield's standard buzzer. I have changes to the firmware that should improve that situation, which I will submit in an upcoming PR to ayab-firmware.

🔬 How to test

I have prepared a test release at https://github.com/jonathanperret/ayab-desktop/releases/tag/1.0.0-endsounds-4 that can be installed as usual. It does not include a new firmware (compared to 1.0.0 beta 3) so no reflashing should be necessary.

Note that this PR (and the test release above) now includes PR #740 which is a proper fix for #662, so neither it nor #617 should be reproducible on the test release.

Summary by CodeRabbit

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new FINISHING state in the state machine to enhance the knitting operation's control flow.
    • Added audio feedback for knitting completion.
  • Improvements

    • Simplified signal handling by removing unnecessary parameters from various methods.
    • Enhanced the testing framework for better validation of communication functionality.
    • Improved the efficiency of the knitting operation's completion process.
    • Added a method to handle the sending of a blank line as the final line in the knitting process.
  • Bug Fixes

    • Streamlined the operation completion process by removing redundant audio notifications.

Copy link
Contributor

coderabbitai bot commented Dec 3, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

The pull request introduces multiple changes across several classes in the AYAB software. Key modifications include the simplification of method signatures by removing unnecessary parameters, such as the beep argument in the finish_operation method. New functionality is added, including a method to handle a blank final line in the knitting process and the introduction of a FINISHING state in the state machine. Additionally, the communication mock's internal logic is streamlined, and improvements are made to the feedback mechanisms upon operation completion.

Changes

File Path Change Summary
src/main/python/main/ayab/ayab.py Updated finish_operation method to remove beep parameter and associated logic.
src/main/python/main/ayab/engine/communication_mock.py Removed step parameter from CommunicationMock constructor, replaced deque with list for rx_msg_list, and modified update_API6 logic.
src/main/python/main/ayab/engine/control.py Added cnf_final_line_API6 method for sending a blank line and modified cnf_line_API6 to use an integer flags variable.
src/main/python/main/ayab/engine/engine.py Removed sleep delay in run method, simplified operation finisher signal emission, and clarified return type in validate method.
src/main/python/main/ayab/engine/engine_fsm.py Introduced FINISHING state and new _API6_finishing method for state management.
src/main/python/main/ayab/engine/output.py Updated _knitting_finished method to include audio feedback upon completion.
src/main/python/main/ayab/signal_receiver.py Simplified operation_finisher signal by removing the boolean parameter.
src/main/python/main/ayab/signal_sender.py Removed beep parameter from emit_operation_finisher method and reformatted emit_progress_bar_updater for clarity.
src/main/python/main/ayab/tests/test_communication_mock.py Enhanced test_req_line_API6 to validate both valid requests and absence of output.

Assessment against linked issues

Objective Addressed Explanation
Ensure sounds and display match at the end of a single repeat (#617) The changes do not address sound adjustments.

Possibly related PRs

  • Fix hardware test dialog #693: The changes in the main PR regarding the removal of the beep parameter from the finish_operation method are related to the modifications in the SignalReceiver class, which also altered the signal's signature to remove the boolean parameter. This indicates a direct connection in how operation completion is handled across both PRs.
  • Send dummy request before closing serial port #740: This PR introduces changes to the state management in the engine_fsm.py file, which may indirectly relate to the overall operation completion process that the main PR addresses, particularly in how operations are finalized and signals are emitted.

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f2b0f32 and 5f9e751.

📒 Files selected for processing (9)
  • src/main/python/main/ayab/ayab.py (2 hunks)
  • src/main/python/main/ayab/engine/communication_mock.py (3 hunks)
  • src/main/python/main/ayab/engine/control.py (2 hunks)
  • src/main/python/main/ayab/engine/engine.py (1 hunks)
  • src/main/python/main/ayab/engine/engine_fsm.py (3 hunks)
  • src/main/python/main/ayab/engine/output.py (1 hunks)
  • src/main/python/main/ayab/signal_receiver.py (1 hunks)
  • src/main/python/main/ayab/signal_sender.py (3 hunks)
  • src/main/python/main/ayab/tests/test_communication_mock.py (1 hunks)

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. (Experiment)
  • @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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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: 0

🧹 Outside diff range and nitpick comments (3)
src/main/python/main/ayab/engine/communication_mock.py (1)

46-48: Consider using a queue for thread-safe message handling

While changing from deque to list works, consider using Queue from the queue module if this mock will be used in multi-threaded scenarios. The Queue class provides thread-safe operations which might be beneficial for simulating real hardware communication.

- self.rx_msg_list = list()
+ from queue import Queue
+ self.rx_msg_list = Queue()
src/main/python/main/ayab/ayab.py (1)

Line range hint 159-169: Consider adding documentation for sound behavior

While the method implementation is correct, it would be helpful to add documentation explaining the new sound behavior, especially since it's a key part of the PR objectives.

 def finish_operation(self, operation: Operation) -> None:
-    """(Re-)enable UI elements after operation finishes."""
+    """(Re-)enable UI elements after operation finishes.
+    
+    Note: Sound notifications are now handled by the firmware timing
+    to ensure proper synchronization with the actual knitting process.
+    """
src/main/python/main/ayab/engine/control.py (1)

245-254: Add docstring to explain method's purpose.

The implementation is correct, but adding a docstring would help explain the method's role in synchronizing end-of-line sounds.

Consider adding:

 def cnf_final_line_API6(self, requested_line: int) -> None:
+    """Send a blank line as the final line to synchronize end-of-line sounds.
+    
+    This method is called during the FINISHING state to ensure the firmware
+    completes its final operations before the app signals completion.
+    
+    Args:
+        requested_line: The line number requested by the firmware
+    """
     self.logger.debug("sending blank line as final line=%d", requested_line)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5e781f1 and bbca6b7.

📒 Files selected for processing (9)
  • src/main/python/main/ayab/ayab.py (2 hunks)
  • src/main/python/main/ayab/engine/communication_mock.py (3 hunks)
  • src/main/python/main/ayab/engine/control.py (2 hunks)
  • src/main/python/main/ayab/engine/engine.py (1 hunks)
  • src/main/python/main/ayab/engine/engine_fsm.py (3 hunks)
  • src/main/python/main/ayab/engine/output.py (1 hunks)
  • src/main/python/main/ayab/signal_receiver.py (1 hunks)
  • src/main/python/main/ayab/signal_sender.py (3 hunks)
  • src/main/python/main/ayab/tests/test_communication_mock.py (1 hunks)
🔇 Additional comments (13)
src/main/python/main/ayab/signal_receiver.py (1)

61-61: LGTM! Signal signature simplified to support sound synchronization.

The removal of the boolean parameter from operation_finisher signal aligns with the PR's objective of improving sound synchronization between app and firmware.

Let's verify all usages of this signal to ensure the change is consistently applied:

✅ Verification successful

Let me verify the implementation of finish_operation to ensure it correctly handles the updated signal signature.


Let me try a different approach to find the finish_operation implementation using ripgrep.


Signal signature change is correctly implemented across the codebase

Based on the verification results:

  • The operation_finisher signal is defined with Signal(Operation) type
  • It's properly connected to finish_operation method which accepts an Operation parameter
  • The signal is emitted correctly in signal_sender.py and engine.py with an operation argument
  • The receiver method finish_operation in ayab.py correctly handles the operation parameter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for operation_finisher signal connections and emissions
rg "operation_finisher" -A 2 -B 2

Length of output: 1842


Script:

#!/bin/bash
# Search for finish_operation implementation
ast-grep --pattern 'def finish_operation($_) {
  $$$
}'

Length of output: 57


Script:

#!/bin/bash
# Search for finish_operation method definition
rg "def finish_operation" -A 5 -B 2

Length of output: 604

src/main/python/main/ayab/engine/output.py (1)

Line range hint 99-104: LGTM! Sound feedback enhanced for knitting completion.

The addition of the finish sound and updated notification message directly addresses the PR's objective of synchronizing end-of-line sounds between app and firmware.

src/main/python/main/ayab/tests/test_communication_mock.py (1)

110-115: Add documentation explaining the test's purpose.

While the test implementation is correct, it would benefit from documentation explaining how this alternating pattern relates to the sound synchronization feature.

Add a comment block explaining the test's purpose:

+        # Test the alternating behavior between line requests and idle states
+        # This pattern ensures proper timing for sound synchronization
+        # between the app and firmware
         for i in range(0, 256):

Let's check the test coverage:

✅ Verification successful

Based on the search results, I found evidence that the alternating pattern between line requests and no output is specifically designed to trigger end-of-line sound notifications in the UI. This is confirmed by the comment in communication_mock.py:

# Alternate between reqLine and no message
# (so that the UI makes the end-of-line sound for each row)

Additionally, I found that the application uses sound notifications for important events, including end-of-line beeps, as evidenced by the translation strings and audio player implementation.

Add documentation explaining the test's purpose and sound synchronization.

+        # Test the alternating behavior between line requests and idle states
+        # This pattern ensures proper timing for end-of-line sound notifications
+        # by alternating between reqLine messages and no output
         for i in range(0, 256):
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related test cases
rg "test.*API6" --type python

Length of output: 62


Script:

#!/bin/bash
# Search for related test cases using ripgrep without file type filter
rg "test.*API6"

Length of output: 1682


Script:

#!/bin/bash
# Find Python test files and examine their content
fd "test.*\.py" | xargs cat

Length of output: 37552


Script:

#!/bin/bash
# Search for API6-related code
rg "API6"

Length of output: 9320


Script:

#!/bin/bash
# Search for sound synchronization related code
rg -B 2 -A 2 "sound|sync|timing"

Length of output: 36463


Script:

#!/bin/bash
# Look for related test documentation
rg -B 2 -A 2 "Test.*alternating|alternating.*test" --type py

Length of output: 62

src/main/python/main/ayab/engine/communication_mock.py (2)

32-32: LGTM: Constructor simplified

The removal of the unused step parameter simplifies the interface without affecting functionality.


98-114: Verify the alternating message pattern matches hardware behavior

The implementation alternates between sending request lines and no messages to simulate end-of-line sounds. This change aligns with the PR objective of synchronizing sounds, but we should verify it matches the actual hardware behavior.

✅ Verification successful

Based on the search results, I can now generate a final response:

Alternating message pattern correctly simulates hardware behavior

The implementation in communication_mock.py correctly simulates the hardware behavior:

  • The mock alternates between reqLine and no message to trigger UI sounds, which aligns with the actual hardware communication pattern as evidenced by:
    • Hardware communication (communication.py) defines the same reqLine token (0x82)
    • Engine FSM (engine_fsm.py) processes these reqLine tokens to track knitting progress
    • Audio system (audio.py, output.py) plays corresponding sounds for line completion
    • Test cases (test_communication_mock.py) verify this alternating behavior: "Alternates between requesting a line and no output"
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the hardware communication follows similar pattern
# Look for similar alternating patterns in hardware communication code

# Search for reqLine token usage in actual hardware communication
rg -A 5 "reqLine" --type python

# Search for sound-related timing patterns
rg -A 5 "beep|sound|audio" --type python

Length of output: 136


Script:

#!/bin/bash
# Search for reqLine token usage in actual hardware communication without file type filter
rg -A 5 "reqLine"

# Search for sound-related timing patterns
rg -A 5 "beep|sound|audio"

# Find Python files that might contain communication logic
fd ".py$" | grep -i "comm\|serial"

Length of output: 22523

src/main/python/main/ayab/signal_sender.py (2)

52-53: LGTM: Method reformatting improves readability

The single-line format for emit_progress_bar_updater improves code consistency.


100-101: Verify all operation finish signal connections are updated

The removal of the beep parameter aligns with the PR's sound synchronization goals. However, we should verify all connections to this signal have been updated accordingly.

✅ Verification successful

All operation finish signal connections are properly updated

Based on the codebase analysis, all operation finish signal connections have been updated correctly. The search results show that:

  • The operation_finisher signal is defined without any beep parameter
  • All connections and emissions of the signal are using the updated signature with just the operation parameter
  • No legacy code using beep parameter was found in any signal connections
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to operation_finisher with beep parameter

# Search for operation_finisher calls
rg "operation_finisher.*beep" --type python

# Search for operation finish signal connections
rg "finished\.connect.*beep" --type python

Length of output: 152


Script:

#!/bin/bash
# Search for operation_finisher calls and connections without file type flag
rg "operation_finisher.*beep"

# Search for operation finish signal connections
rg "finished\.connect.*beep"

# Search for any operation_finisher related code
rg "operation_finisher"

# Search for signal connections related to operations
rg "finished\.connect"

Length of output: 865

src/main/python/main/ayab/ayab.py (1)

109-109: LGTM: Hardware test completion signal simplified

The lambda function simplification aligns with the new sound synchronization approach.

src/main/python/main/ayab/engine/engine_fsm.py (3)

54-54: LGTM: New state addition aligns with PR objectives.

The introduction of the FINISHING state provides a clear transition point for synchronizing end-of-line sounds between the app and firmware.


200-201: LGTM: Improved state transition logic.

The transition to FINISHING state instead of directly to FINISHED enables proper synchronization of end-of-line sounds by allowing the firmware to complete its final operations.


241-250: LGTM: Well-implemented finishing state handler.

The _API6_finishing method properly handles the final line request and ensures correct timing of the "work finished" sound by transitioning to FINISHED state only after the firmware confirms receipt of the final line.

src/main/python/main/ayab/engine/control.py (1)

213-214: LGTM: Improved end-of-pattern handling.

Setting flags = 0 ensures the firmware doesn't receive a premature end signal, allowing for proper synchronization of the final operations and associated sounds.

src/main/python/main/ayab/engine/engine.py (1)

197-197: LGTM: Simplified operation completion signaling.

The removal of the beep parameter from emit_operation_finisher aligns with the new approach of letting the firmware handle the end-of-line sounds naturally.

@dl1com
Copy link
Contributor

dl1com commented Dec 4, 2024

@Adrienne200 could you please try the test build of this branch to verify this achieves what it intends to do?
@jonathanperret do we require an update in the API description to reflect your changes?

@jonathanperret
Copy link
Contributor Author

@jonathanperret do we require an update in the API description to reflect your changes?

I don't think so, I am using the API exactly as it is documented — as demonstrated by the fact that the firmware doesn't need to be modified for this code to work.

@jonathanperret
Copy link
Contributor Author

I just triggered a new test release that now includes the newly merged fixes for #732 and #734 : https://github.com/jonathanperret/ayab-desktop/releases/tag/1.0.0-endsounds-3

@jpcornil-git
Copy link

Note that with this change, the FW doesn't move to init state anymore unless you effectively knit the blank row.

@jonathanperret
Copy link
Contributor Author

Note that with this change, the FW doesn't move to init state anymore unless you effectively knit the blank row.

Note that in general you do have to "knit" the "blank row", because while it will select every needle to B, it will knit the final row of the pattern, that was previously selected. The only exception is the garter carriage, whose work is indeed finished as soon as it reaches the end of the last pattern row.

In theory there can be a difference between the firmware being in init state and still executing a blank row, but in practice it is not easily observable. Remember that the desktop app always closes the serial port after knitting, and opening it back up resets the Arduino so the question of the final state is moot.

By the way, the current firmware would not work if that reset did not occur (you can easily see this with simavr), because even if you knit until it goes back to init state, it does not accept the initial reqInit message from the app (that message is only accepted in wait_for_machine state).

This is all to say that yes, the current firmware and API are a bit broken, and will have to be improved, but I am trying to make a small change here for now.

@jpcornil-git
Copy link

jpcornil-git commented Dec 4, 2024

That reset is specific to the current AVR board, if you take a uno R4 minima or Wifi for example, then opening the serial port doesn't reset the device, i.e. behavior is not generic but specific to a few platforms
=> why in ayabAsync, I do accept an init message while in operation mode to support R4, see
https://github.com/jpcornil-git/ayabAsync-firmware/blob/v1.0/lib/components/knitter/knitter.cpp#L128

It will be required as well moving forward with a webapp/wifi communication (no HW reset).

From an user experience, the HW/shield beep will also be missing (unless you knit the blank row again).

@jonathanperret
Copy link
Contributor Author

That reset is specific to the current AVR board, if you take a uno R4 minima or Wifi for example, then opening the serial port doesn't reset the device, i.e. behavior is not generic but specific to a few platforms => why in ayabAsync, I do accept an init message while in operation mode to support R4, see jpcornil-git/ayabAsync-firmware@v1.0/lib/components/knitter/knitter.cpp#L128

It will be required as well moving forward with a webapp/wifi communication (no HW reset).

Again, I'm 100% onboard with improving the firmware and API in the future.

From an user experience, the HW/shield beep will also be missing (unless you knit the blank row again).

The beep is here. Have you tried knitting with ayab-firmware?

@jpcornil-git
Copy link

No (remember that I've no machine/only coding for my daugther :-)) but I see that Knitter::stopKnitting() and therefore GlobalBeeper::endWork() won't be called until you finish the last line
https://github.com/AllYarnsAreBeautiful/ayab-firmware/blob/main/src/ayab/knitter.cpp#L454

void Knitter::stopKnitting() const {
  GlobalBeeper::endWork();
  GlobalFsm::setState(OpState::init);

@jonathanperret
Copy link
Contributor Author

No (remember that I've no machine/only coding for my daugther :-)) but I see that Knitter::stopKnitting() and therefore GlobalBeeper::endWork() won't be called until you finish the last line

Yes, but GlobalBeeper::finishedLine is called after every row is received. Also it may look like GlobalBeeper::endWork would be make a special sound but 1) the sounds are all borked up on the shield beeper due to switching too fast for the electromechanical device and 2) if you look closer you'll see that currently there's another GlobalBeeper::finishedLine call right after the GlobalBeeper::endWork, which resets the beep count and nullifies the GlobalBeeper::endWork.

Believe me, I know that so many things are suboptimal in the whole thing. I'm just trying to start somewhere and improve things bit by bit here. I believe the change in this PR makes things incrementally better. Let's remember the focus here is to get to a state where we can make the first release of AYAB in over 5 years.

@jpcornil-git
Copy link

I understand but I believe that adding the suggested indState is a step in the right direction while adding a fake new row is rather a workaround/a step in the wrong direction that you will have to undo moving forward.
I believe you got my points/won't insist anymore on this :-)

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

🧹 Outside diff range and nitpick comments (3)
src/main/python/main/ayab/engine/engine_fsm.py (1)

242-273: LGTM! Well-implemented state handlers with good error mitigation.

The implementation properly handles:

  1. Sending the blank final line
  2. Preventing serial port closure issues
  3. Maintaining proper state transitions

Consider adding debug logging in _API6_disconnect similar to other state transitions.

 @staticmethod
 def _API6_disconnect(control: Control, operation: Operation) -> Output:
     token, _ = control.check_serial_API6()
     if token == Token.cnfInfo:
+        control.logger.debug("State FINISHED")
         # We received a response to our final `reqInfo` request,
         # it is now safe to close the port.
         control.state = State.FINISHED
         return Output.KNITTING_FINISHED
src/main/python/main/ayab/engine/control.py (1)

248-258: LGTM! Clean implementation of final line handling.

The method properly implements the blank final line sending with appropriate debug logging. Consider defining a constant for the flags to improve code maintainability.

 class Control(SignalSender):
+    FINAL_LINE_FLAG = 1
+    REGULAR_LINE_FLAG = 0
     
     def cnf_final_line_API6(self, requested_line: int) -> None:
         self.logger.debug("sending blank line as final line=%d", requested_line)
 
         # prepare a blank line as the final line
         bits = bitarray(self.machine.width, endian="little")
 
         # send line to machine
         color = 0  # doesn't matter
-        flags = 1  # this is the last line
+        flags = self.FINAL_LINE_FLAG  # this is the last line
         self.com.cnf_line_API6(requested_line, color, flags, bits.tobytes())
src/main/python/main/ayab/engine/communication_mock.py (1)

109-109: Document return type change in docstring.

The return type annotation now includes None, but this isn't reflected in the docstring.

-    """Read and parse data packet."""
+    """Read and parse data packet.
+    
+    Returns:
+        tuple[bytes | None, Token, int]: A tuple containing the parsed message,
+            token, and message length. Returns None as the first element when
+            no message is available.
+    """
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a9097c1 and f2b0f32.

📒 Files selected for processing (9)
  • src/main/python/main/ayab/ayab.py (2 hunks)
  • src/main/python/main/ayab/engine/communication_mock.py (3 hunks)
  • src/main/python/main/ayab/engine/control.py (2 hunks)
  • src/main/python/main/ayab/engine/engine.py (1 hunks)
  • src/main/python/main/ayab/engine/engine_fsm.py (3 hunks)
  • src/main/python/main/ayab/engine/output.py (3 hunks)
  • src/main/python/main/ayab/signal_receiver.py (1 hunks)
  • src/main/python/main/ayab/signal_sender.py (3 hunks)
  • src/main/python/main/ayab/tests/test_communication_mock.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/main/python/main/ayab/tests/test_communication_mock.py
  • src/main/python/main/ayab/signal_receiver.py
  • src/main/python/main/ayab/engine/output.py
  • src/main/python/main/ayab/signal_sender.py
  • src/main/python/main/ayab/engine/engine.py
  • src/main/python/main/ayab/ayab.py
🔇 Additional comments (6)
src/main/python/main/ayab/engine/engine_fsm.py (2)

54-55: LGTM! New states align with PR objectives.

The addition of DISCONNECT and FINISHING states provides a clean separation of concerns for handling the final knitting phase and proper port closure.


201-202: LGTM! Clean transition to new FINISHING state.

The change correctly implements the first part of the synchronization fix by transitioning to the FINISHING state instead of immediately finishing.

src/main/python/main/ayab/engine/control.py (1)

212-217: LGTM! Clear implementation of the new line handling approach.

The change correctly implements the core fix by never marking regular pattern lines as final, with good documentation explaining the rationale.

src/main/python/main/ayab/engine/communication_mock.py (3)

32-32: LGTM! Constructor signature simplified.

The removal of the unused step parameter streamlines the interface while maintaining the core functionality.


112-123: LGTM! Sound synchronization logic implemented correctly.

The alternating behavior between request lines and no messages effectively implements the sound synchronization requirements from the PR objectives. The implementation:

  • Properly simulates the knitting process timing
  • Ensures UI sounds are synchronized with the mock hardware
  • Maintains a consistent state through __started_row

46-48: Verify performance impact of using list.pop(0).

While changing from deque to list maintains FIFO behavior through pop(0), this operation has O(n) complexity compared to O(1) for deque.popleft(). Although this is a mock class used for testing, we should verify if this impacts performance with large message queues.

Consider keeping deque for better performance:

-        self.rx_msg_list = list()
+        from collections import deque
+        self.rx_msg_list = deque()

There were two sources for the delay: one deliberate delay of 1 second to
"finish printing to knit progress window", which does not seem required
anymore; and another caused by waiting for the serial port to be closed
before emitting the finished sound: this was fixed by coupling the audio
emission to printing the notification in the progress bar, rather than the
actual end of the complete operation.
In order to let the UI play the end-of-line sounds, we
need the communications mock to not emit reqLine messages
back-to-back.
This did not really work, due to running on a non-UI thread.
@dl1com dl1com merged commit 22335aa into AllYarnsAreBeautiful:main Dec 13, 2024
3 checks passed
@dl1com
Copy link
Contributor

dl1com commented Dec 13, 2024

Reported to be working by @Adrienne200 in Discord

@jonathanperret jonathanperret deleted the fix-end-sounds branch December 13, 2024 08:45
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.

[BUG] Incorrect sounds/display at the end of a single repeat
3 participants