Skip to content

Add WLAN support #242

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 6 commits into from
Feb 19, 2025
Merged

Add WLAN support #242

merged 6 commits into from
Feb 19, 2025

Conversation

bessman
Copy link
Collaborator

@bessman bessman commented Feb 19, 2025

Summary by Sourcery

This pull request introduces WLAN support for PSLab devices by refactoring the connection logic to support multiple connection types. It introduces a new ConnectionHandler abstract base class and implements SerialHandler and WLANHandler classes to handle serial and WLAN connections, respectively. The ScienceLab class is updated to use the ConnectionHandler interface, allowing it to work with different connection types.

Enhancements:

  • Refactor the connection logic to support multiple connection types, including serial and WLAN.
  • Introduce a new ConnectionHandler abstract base class to define the common interface for all connection types.
  • Implement SerialHandler and WLANHandler classes to handle serial and WLAN connections, respectively.
  • Update the ScienceLab class to use the ConnectionHandler interface, allowing it to work with different connection types.
  • Deprecate the old pslab.serial_handler module and redirect users to the new pslab.connection module.

Copy link

sourcery-ai bot commented Feb 19, 2025

Reviewer's Guide by Sourcery

This pull request introduces WLAN support by adding a new WLANHandler and deprecates the old SerialHandler in favor of the new connection architecture. It also refactors serial port access permission checks and removes the wait_for_data method.

Updated class diagram for ConnectionHandler and its subclasses

Loading
classDiagram
    class ConnectionHandler {
        <<abstract>>
        +connect()
        +disconnect()
        +read(numbytes: int): bytes
        +write(data: bytes): int
        +get_byte(): int
        +get_int(): int
        +get_long(): int
        +send_byte(data: int | bytes)
        +send_int(data: int | bytes)
        +send_long(data: int | bytes)
        +get_ack(): int
        +get_version(): str
        +get_firmware_version(): FirmwareVersion
    }
    class SerialHandler {
        -_port: str
        -_ser: serial.Serial
        +port: str
        +baudrate: int
        +timeout: float
        +connect()
        +disconnect()
        +read(number_of_bytes: int): bytes
        +write(data: bytes): int
    }
    class WLANHandler {
        -_host: str
        -_port: int
        -_timeout: float
        -_sock: socket.socket
        +host: int
        +port: int
        +timeout: float
        +connect()
        +disconnect()
        +read(numbytes: int): bytes
        +write(data: bytes): int
    }

    ConnectionHandler <|-- SerialHandler
    ConnectionHandler <|-- WLANHandler

    note for ConnectionHandler "Abstract base class for PSLab control interfaces"
    note for SerialHandler "Interface for controlling a PSLab over a serial port"
    note for WLANHandler "Interface for controlling a PSLab over WLAN"

File-Level Changes

Change Details Files
Deprecate pslab.serial_handler and replace it with pslab.connection.
  • Introduce pslab.connection module with ConnectionHandler ABC and SerialHandler implementation.
  • Deprecate pslab.serial_handler and redirect to pslab.connection with a warning.
  • Update imports throughout the codebase to use pslab.connection.SerialHandler instead of pslab.serial_handler.SerialHandler.
pslab/serial_handler.py
pslab/sciencelab.py
tests/test_serial_handler.py
pslab/bus/busio.py
pslab/bus/spi.py
pslab/bus/i2c.py
pslab/instrument/waveform_generator.py
pslab/instrument/logic_analyzer.py
pslab/bus/uart.py
pslab/instrument/oscilloscope.py
pslab/instrument/power_supply.py
tests/conftest.py
pslab/instrument/multimeter.py
tests/test_i2c.py
tests/test_motor.py
tests/test_multimeter.py
tests/test_spi.py
tests/test_uart.py
tests/test_waveform_generator.py
Introduce WLAN support via a new WLANHandler in pslab.connection.
  • Add WLANHandler to pslab.connection for wireless communication.
  • Modify ScienceLab to accept a generic ConnectionHandler instead of a SerialHandler.
  • Update detect() function in pslab.connection to detect WLAN devices.
  • Update ADCBufferMixin to avoid large data chunks.
pslab/sciencelab.py
pslab/connection/connection.py
pslab/connection/wlan.py
pslab/instrument/buffer.py
pslab/connection/__init__.py
Refactor serial port access permission checks.
  • Move check_serial_access_permission to pslab.connection._serial.
  • Rename check_serial_access_permission to _check_serial_access_permission to indicate that it is a private function.
pslab/connection/_serial.py
Remove wait_for_data method from SerialHandler.
  • Remove wait_for_data method from SerialHandler.
  • Replace wait_for_data with time.sleep in LogicAnalyzer.
tests/test_serial_handler.py
pslab/instrument/logic_analyzer.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @bessman - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a factory function or classmethod to ConnectionHandler to handle the connection logic instead of autoconnect().
  • The detect function could return a list of disconnected ConnectionHandler instances, allowing the user to choose which device to connect to.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Testing: 1 issue found
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -3,7 +3,7 @@
from serial.tools.list_ports_common import ListPortInfo

import pslab.protocol as CP
from pslab.serial_handler import detect, SerialHandler
from pslab.connection import detect, SerialHandler
Copy link

Choose a reason for hiding this comment

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

issue (testing): Missing test for autoconnect

It seems like autoconnect is a new function, but I don't see any tests for it in this PR. We should add tests to ensure it functions correctly, including cases where no devices are found and where multiple devices are found.

import pslab.protocol as CP


class ADCBufferMixin:
Copy link

Choose a reason for hiding this comment

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

issue (complexity): Consider creating a helper function to encapsulate the common device communication steps in fetch_buffer and fill_buffer to reduce code duplication.

You can reduce the duplication in the while loops by abstracting the common device communication steps into a helper function. For example, you can create an internal method (e.g. _buffer_transaction) that handles sending the common header and command, plus the extra parameters. Then call this helper in both fetch_buffer and fill_buffer. For instance:

def _buffer_transaction(self, command: int, idx: int, count: int, extra_send: callable = None):
    self._device.send_byte(CP.COMMON)
    self._device.send_byte(command)
    self._device.send_int(idx)
    self._device.send_int(count)
    if extra_send:
        extra_send()
    result = None
    if command == CP.RETRIEVE_BUFFER:
        # when fetching the buffer, gather the responses
        result = [self._device.get_int() for _ in range(count)]
    self._device.get_ack()
    return result

Then modify your methods as:

def fetch_buffer(self, samples: int, starting_position: int = 0):
    received = []
    buf_size = 128
    remaining = samples
    idx = starting_position
    while remaining > 0:
        samps = min(remaining, buf_size)
        chunk = self._buffer_transaction(
            CP.RETRIEVE_BUFFER,
            idx,
            samps
        )
        received += chunk
        remaining -= samps
        idx += samps
    return received

def fill_buffer(self, data: list[int], starting_position: int = 0):
    buf_size = 128
    idx = starting_position
    remaining = len(data)
    while remaining > 0:
        samps = min(remaining, buf_size)
        # supply a lambda to send the data chunk
        self._buffer_transaction(
            CP.FILL_BUFFER,
            idx,
            samps,
            extra_send=lambda: [self._device.send_int(value) for value in data[idx:idx+samps]]
        )
        idx += samps
        remaining -= samps

This refactoring abstracts away the common patterns in device communication while preserving functionality and reducing complexity.

@bessman bessman merged commit 10fd755 into fossasia:development Feb 19, 2025
2 checks passed
@bessman bessman deleted the feat/wlan branch February 20, 2025 09:38
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.

None yet

1 participant