-
Notifications
You must be signed in to change notification settings - Fork 176
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
fix(api): update USB port & hub mapping logic for Flex #12775
Conversation
Codecov Report
@@ Coverage Diff @@
## edge #12775 +/- ##
==========================================
+ Coverage 73.28% 73.32% +0.03%
==========================================
Files 2317 2315 -2
Lines 63500 63117 -383
Branches 6973 6973
==========================================
- Hits 46537 46278 -259
+ Misses 15307 15183 -124
Partials 1656 1656
Flags with carried forward coverage won't be shown. Click here to find out more.
|
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.
I think the structure is good but we need some changes.
- We should test the new code.
- We should make sure we can still handle someone plugging an external hub into one of the USB ports on the OT3
- We should make the port group type an Enum
- We should make sure we understand how this new data is represented via HTTP
@@ -22,6 +24,7 @@ class USBPort: | |||
port_number: int | |||
device_path: str = "" | |||
hub: Optional[int] = None | |||
port_group: str = "" |
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.
I think we really want this to be an enumeration since it has a fixed number of possible values. We'll need to represent it as a string eventually in the HTTP layer, but we can cross that bridge when we come to it. We should make the enum handle the left, the right, and "main" (for OT-2) and probably even "front" (for OT-3 - just in case).
@@ -103,18 +112,27 @@ def get_unique_nodes(full_name: str) -> List[str]: | |||
@staticmethod | |||
def map_to_revision( | |||
board_revision: BoardRevision, port_info: Tuple[Optional[int], int] | |||
) -> Tuple[Optional[int], int]: | |||
) -> Tuple[Optional[int], str, int]: |
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.
this would be a good place for us to return the enum
else: | ||
return hub, "MAIN", REV_OG_USB_PORTS.get(str(port), port) | ||
elif board_revision == BoardRevision.B2: | ||
# what will hub look like?? |
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.
what does it look like?
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.
This is looking really good! I think we should make the revision name for the OT-3 variants include that it's an ot3 - honestly, this driver code should probably leave the rpi_drivers
section but we don't need to do that in this PR - and maybe add some comments noting in more depth what's going on with the usb string splitting in map_to_revision
.
Also, let's add some tests that explicitly check that strings captured from a running OT-3 prase properly, for left and right with no hubs and left and right with hubs
hub: Optional[int] = int(port_info[1]) | ||
port = int(port_info[2]) | ||
hub_port: Optional[int] = int(port_info[3]) |
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.
this would want to be port_info[-1]
maybe?
@@ -458,6 +458,7 @@ class BoardRevision(enum.Enum): | |||
A = enum.auto() | |||
B = enum.auto() | |||
C = enum.auto() | |||
B2 = enum.auto() |
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.
can we maybe make this FLEX_B2
or something?
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.
Looks good to me once we fix up the tests!
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.
Looks great to me if tests all pass, but let's make sure @sanni-t or another RSS person gets a glance - possibly an in-person demo?
@@ -103,6 +103,7 @@ stages: | |||
moduleModel: thermocyclerModuleV1 | |||
usbPort: | |||
port: !anyint | |||
hub: !anyint |
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.
@sfoster1 will this become an int? It is a bool in the api
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.
When sent via http, the type is expressed as determined in the response model which would also have to change. that would then be a breaking change, which would be rough.
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.
You can see there that the hub
field is optional in the model and setup by this data: https://github.com/Opentrons/opentrons/blob/4445d808e5401c9283c8af780bb7e1ddee65a162/robot-server/robot_server/service/legacy/routers/modules.py#LL36C51-L36C51
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.
Looks good pending seeing what this breaks in app interactions if anything
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.
This looks good mostly. Just some minor comments.
I tested this on a flex and it works great! Didn't test on ot2 but I'm assuming it'll have similar app-side change requirements due to the hub/port structure (& type) change? (and that'll be a slight breaking change/ introduce incompatibility with older app).
As for the app changes, this is how the app shows usb ports with your change-
![Screenshot 2023-06-07 at 4 03 33 PM](https://private-user-images.githubusercontent.com/8520173/244475249-453a7c62-a620-4195-b03e-9dc67a0288c3.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM1OTI3OTksIm5iZiI6MTcyMzU5MjQ5OSwicGF0aCI6Ii84NTIwMTczLzI0NDQ3NTI0OS00NTNhN2M2Mi1hNjIwLTQxOTUtYjAzZS05ZGM2N2EwMjg4YzMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTNUMjM0MTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OTFjN2IyYmVkMzY4ZWViZjU1MWJhODIzNWJlNjU1NDUzODA0YTcwYzA3ZmIzNGZhOTIzODM3Y2NlMDE1MjYwMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.lSALb57x0NbnE8G9ISsW96vtE16J12-gSyIZqo72AFM)
![Screenshot 2023-06-07 at 4 03 23 PM](https://private-user-images.githubusercontent.com/8520173/244475246-7cd25cc4-79b6-404e-9251-c07c810ae037.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjM1OTI3OTksIm5iZiI6MTcyMzU5MjQ5OSwicGF0aCI6Ii84NTIwMTczLzI0NDQ3NTI0Ni03Y2QyNWNjNC03OWI2LTQwNGUtOTI1MS1jMDdjODEwYWUwMzcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDgxMyUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA4MTNUMjM0MTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTM0ODI1ZWFhYmU4NzFjMjJlMzA5N2I5NDZjZDQ1Y2Q0YzVmYzUxYWNhZmJkOWQ0ZTVhM2ZlOWNmMGI2YTU1ZiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.oeWsDP2WDWEj5sOcdRLWUUDHGTl1l9AjCMh7lupIBQM)
"usbPort": { | ||
"hub": None, | ||
"port": None, | ||
"port_group": None, | ||
"hub_port": None, | ||
}, |
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.
We want to make sure the example structure is valid acc to the defined models-
"usbPort": { | |
"hub": None, | |
"port": None, | |
"port_group": None, | |
"hub_port": None, | |
}, | |
"usbPort": { | |
"hub": 1, | |
"port": 1, | |
"portGroup": 1, | |
"hubPort": None, | |
}, |
If we change port group to have string values, then will need to update that here too.
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.
Also, I think the "port" field above "usbPort" might have been added here by mistake. We should remove it since a real response can't contain both 'port' (virtual port) and a 'usbPort'.
Overview
Previously, we represented USB-connected modules with the data structure (hub, port). We will now represent USB-connected modules with the data structure
(hub, port_group, port, hub_port)
. On the OT-2_OG, we have 1 USB port bank with 2 ports for connecting modules. On the OT-2_R, we have 1 port bank with 2 ports for connecting modules. On the Flex, we have 3 port banks (left and right with 4 ports each, front with 1 port) for connecting modules.If a USB hub/extender is attached to a port, the port's hub data field will be True and the hub_port data field will be populated with the port on the USB hub. If a hub is not attached to a port, the port's hub data field will be False and the hub_port data field will be None.
On the Flex, the left port bank USB ports are numbered 1 to 4 from top to bottom and the right port bank USB ports are numbered 5 to 8 from top to bottom. The data structure ports match these. The front port bank port is always 1.
Test Plan
>>> api._backend.module_controls._usb.match_virtual_ports(new_mods)
[ModuleAtPort(port='/dev/ot_module_tempdeck2', name='tempdeck', usb_port=USBPort(name='1-1.3.1', port_number=8, port_group=<PortGroup.RIGHT: 3>, hub=False, hub_port=None, device_path='1.0/tty/ttyACM2/dev')), ModuleAtPort(port='/dev/ot_module_heatershaker1', name='heatershaker', usb_port=USBPort(name='1-1.4.1.4', port_number=4, port_group=<PortGroup.LEFT: 2>, hub=True, hub_port=4, device_path='1.0/tty/ttyACM1/dev'))]
>>> api._backend.module_controls._usb.match_virtual_ports(new_mods)
[ModuleAtPort(port='/dev/ot_module_tempdeck2', name='tempdeck', usb_port=USBPort(name='1-1.7.4', port_number=1, port_group=<PortGroup.FRONT: 4>, hub=True, hub_port=4, device_path='1.0/tty/ttyACM2/dev')), ModuleAtPort(port='/dev/ot_module_heatershaker1', name='heatershaker', usb_port=USBPort(name='1-1.4.4', port_number=1, port_group=<PortGroup.LEFT: 2>, hub=False, hub_port=None, device_path='1.0/tty/ttyACM1/dev'))]
Changelog
Review requests
Risk assessment