Skip to content

Conversation

@xbtu2
Copy link
Contributor

@xbtu2 xbtu2 commented Dec 21, 2025

tecan spark WIP. luminescence coming up soon. i had a hard time to get io.usb to work with this, so i'm directly using libusb for now

@hazlamshamin
Copy link
Contributor

CRAZY COOOOL! this is VERY complete

@BioCam BioCam requested a review from Copilot December 21, 2025 07:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for the Tecan Spark plate reader by implementing a comprehensive async backend with USB communication, packet parsing, and data processing capabilities. The implementation includes controls for various instrument subsystems and processors for absorbance and fluorescence measurements.

Key Changes

  • New async USB reader with packet parsing for Tecan Spark devices
  • Absorbance and fluorescence data processors with real-world test coverage
  • Comprehensive control modules for plate transport, optics, sensors, measurements, and system configuration
  • Utility function for calculating non-overlapping well rectangles

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pylabrobot/plate_reading/utils.py Adds helper to find non-overlapping rectangles covering plate wells
pylabrobot/plate_reading/tecan/spark20m/spark_reader_async.py Implements async USB communication layer for Spark devices
pylabrobot/plate_reading/tecan/spark20m/spark_packet_parser.py Parses binary measurement data packets from the device
pylabrobot/plate_reading/tecan/spark20m/spark_processor.py Processes raw measurement data into absorbance/fluorescence values
pylabrobot/plate_reading/tecan/spark20m/spark_backend.py Main backend integrating all components for plate reading operations
pylabrobot/plate_reading/tecan/spark20m/controls/*.py Control modules for device subsystems (optics, sensors, movement, etc.)
pylabrobot/plate_reading/tecan/spark20m/*_tests.py Unit tests for reader, processor, and backend components

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rickwierenga
Copy link
Member

is this ready for review?

rickwierenga and others added 2 commits January 31, 2026 10:18
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove AutoReaderProxy, integrate reading into send_command
- Remove reading context manager (no longer needed)
- Rename control classes to follow PEP8 (BaseControl, PlateControl, etc.)
- BaseControl now takes send_command directly instead of reader
- Make init_read and get_response private methods
- Add io.binary.Reader utility class

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@rickwierenga
Copy link
Member

Code review changes

Simplified the Spark control architecture:

  • Removed AutoReaderProxy - This was a magic proxy that wrapped every async method call with a reading context. Instead, the reading logic is now integrated directly into send_command(), making the flow more explicit and easier to follow.

  • Removed reading() context manager - No longer needed since send_command() handles read setup internally.

  • Renamed control classes to follow PEP8 - baseControlBaseControl, plateControlPlateControl, measurement_controlMeasurementControl, etc.

  • Simplified BaseControl - Now takes send_command function directly instead of the entire reader object, since that's all it uses.

  • Made internal methods private - init_read()_init_read(), get_response()_get_response() since they're only used internally by send_command().

  • Added io.binary.Reader - Utility class for binary parsing, used to replace the custom _read_u8, _read_u16, etc. helper functions in the packet parser.

# Conflicts:
#	pylabrobot/io/binary.py
#	pylabrobot/io/usb.py
rickwierenga and others added 7 commits January 31, 2026 11:27
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace custom byte parsing helpers (_read_bytes, _read_u8, _read_u16,
_read_u32, _read_string) with the Reader class from pylabrobot.io.binary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use pytest.approx() instead of exact equality for float comparisons
in test_process_real_data tests. Compare row by row since pytest.approx
does not support nested data structures.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add max_workers parameter to USB class constructor with default of 1
to maintain backward compatibility. SparkReaderAsync passes max_workers=16
for its specific needs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PR fixed the timeout conversion for the main write but missed
the zero-length packet write. PyUSB expects timeout in milliseconds,
so timeout must be multiplied by 1000.

Also add max_workers parameter to USBValidator for signature compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace manual calculation of well spacing with the new item_dx and
item_dy properties from ItemizedResource.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@rickwierenga
Copy link
Member

instead of returning False on error, can we raise the error in send command? this is a more pythonic way of dealing with errors

xbtu2 and others added 3 commits January 31, 2026 20:53
Extracts SparkDevice, SparkEndpoint, and VENDOR_ID from
spark_reader_async.py to a separate enums.py file for better
organization. These are USB protocol constants, not control logic.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

3 participants