Wasatch.PY
Python application driver for Wasatch Photonics spectrometers
Loading...
Searching...
No Matches
wasatch.DeviceID.DeviceID Class Reference

Represents a persistent unique identifier for a spectrometer device (USB or otherwise) which should remain valid for connected devices in spite of hotplug events around them. More...

Public Member Functions

 __eq__ (self, other)
 
 __hash__ (self)
 
 __init__ (self, device=None, label=None, directory=None, device_type=None, overrides=None, spectra_options=None)
 Instantiates a DeviceID object from either a usb.device or an existing device_id string representation.
 
 __lt__ (self, other)
 
 __ne__ (self, other)
 
 __repr__ (self)
 
 __str__ (self)
 Whether a given device is USB, FILE or otherwise, render the DeviceID as a string containing all the relevant bits neccessary to reconstruct the object into a parsed structure while providing a concise, readable and hashable unique key.
 
 determine_bus_and_address (self, device)
 
 get_pid_hex (self)
 
 get_vid_hex (self)
 
 is_andor (self)
 
 is_ble (self)
 
 is_file (self)
 
 is_mock (self)
 
 is_usb (self)
 
 to_dict (self)
 So that dict() can return a clean dict without any "private" attributes (which we should probably __prefix or something)
 

Public Attributes

 address
 
 bus
 
 device_type
 
 directory
 
 name
 
 overrides
 
 pid
 
 product
 
 serial
 
 spectra_options
 
 type
 
 vid
 

Detailed Description

Represents a persistent unique identifier for a spectrometer device (USB or otherwise) which should remain valid for connected devices in spite of hotplug events around them.

Class Justification

That is to say, this DeviceID is a solution to the following problem. Assume we have four WP-785 spectrometers: A, B, C and D. We connect A, B and C, then launch ENLIGHTEN. A is the first on the USB chain, so in a positional listing A would be #1, B is #2, C is #3.

Now we unplug B. That leaves us with A (1) and C (3). Except that, positionally C is really now 2. Now we plug in D. Is D now 4th on the list, or did it slip into the unoccupied 2 slot? Or was C internally moved back to 2, and now D is 3, but C also thinks it's 3?

One solution would be to UPDATE the positional order in a master list on unplug events (detecting B's removal, and changing C from 3 to 2). ENLIGHTEN could do that, but note that it would therefore be a client- side operation, not within the driver itself. Or we could move the multi-process "Controller" ownership of the several WasatchDeviceWrapper processes into Wasatch.PY, such that Wasatch.PY provided a single-object Facade. We could possibly achieve that by maintaining a list of all WasatchDeviceWrapper instances in a static WasatchDeviceWrapper attribute (or WasatchDeviceWrappers or WasatchDeviceWrapperFactory as it were). But either would require some additional refactoring that I'm not diving into right now, although it seems an improved and reasonable architecture.

Or maybe we don't need a DeviceID at all, and just track "the WasatchDeviceWrapper associated with this serial number", and simply assume that all spectrometers will have a unique spectrometer (or be assigned one at connection). So maybe my attempt to generate a UNIQUE and PERSISTENT DeviceID from the usb.device object is quixotic and unnecessary. That's probably the case.

Part of what drove this is that historically ENLIGHTEN supported a bus_order command-line argument which explicitly referenced spectrometers by their position on the USB bus. However, we're now trying to support hotplug use-cases, meaning that position is no longer reliable. But since we had a legacy expectation of being able to explicitly identify devices at the bus level, I'm trying to retain that capability by habit. It probably is no longer needed, and we can probably replace the old –bus-order option with –serial-number instead.

More to the point, the current architecture is such that ENLIGHTEN calls WasatchBus to detect hotplug events, and then ENLIGHTEN instantiates a new WasatchDeviceWrapper to support the new bus device. That means there really ought to be a way to pass the "id" of the device, which was detected by WasatchBus, down into WasatchDeviceWrapper (and hence WasatchDevice and FeatureIdentificationDevice) to be re-instantiated. I don't trust position, I'm not sure how to confirm "claim state" (ASSUMING we wanted the "first eligible unclaimed") , "serial number" seems heavy-handed (and would still require a way to deliberately "skip" already-connected devices, again requiring some sort of key).

ALSO we want to eventually support BLE (which has unique UUID), and perhaps TCP/IP (which has IP addresses)...basically I think objects on a "bus" should be uniquely identifiable and addressable from their bus address, WITHOUT making guesses based on position or ordering or claim-state or anything like that.

So yeah, I think this is useful and a good design.

Note
USB VID and PID are stored as ints

Constructor & Destructor Documentation

◆ __init__()

wasatch.DeviceID.DeviceID.__init__ ( self,
device = None,
label = None,
directory = None,
device_type = None,
overrides = None,
spectra_options = None )

Instantiates a DeviceID object from either a usb.device or an existing device_id string representation.

Member Function Documentation

◆ __eq__()

wasatch.DeviceID.DeviceID.__eq__ ( self,
other )

◆ __hash__()

wasatch.DeviceID.DeviceID.__hash__ ( self)

◆ __lt__()

wasatch.DeviceID.DeviceID.__lt__ ( self,
other )

◆ __ne__()

wasatch.DeviceID.DeviceID.__ne__ ( self,
other )

◆ __repr__()

wasatch.DeviceID.DeviceID.__repr__ ( self)

◆ __str__()

wasatch.DeviceID.DeviceID.__str__ ( self)

Whether a given device is USB, FILE or otherwise, render the DeviceID as a string containing all the relevant bits neccessary to reconstruct the object into a parsed structure while providing a concise, readable and hashable unique key.

◆ determine_bus_and_address()

wasatch.DeviceID.DeviceID.determine_bus_and_address ( self,
device )

◆ get_pid_hex()

wasatch.DeviceID.DeviceID.get_pid_hex ( self)

◆ get_vid_hex()

wasatch.DeviceID.DeviceID.get_vid_hex ( self)

◆ is_andor()

wasatch.DeviceID.DeviceID.is_andor ( self)

◆ is_ble()

wasatch.DeviceID.DeviceID.is_ble ( self)

◆ is_file()

wasatch.DeviceID.DeviceID.is_file ( self)

◆ is_mock()

wasatch.DeviceID.DeviceID.is_mock ( self)

◆ is_usb()

wasatch.DeviceID.DeviceID.is_usb ( self)

◆ to_dict()

wasatch.DeviceID.DeviceID.to_dict ( self)

So that dict() can return a clean dict without any "private" attributes (which we should probably __prefix or something)

Member Data Documentation

◆ address

wasatch.DeviceID.DeviceID.address

◆ bus

wasatch.DeviceID.DeviceID.bus

◆ device_type

wasatch.DeviceID.DeviceID.device_type

◆ directory

wasatch.DeviceID.DeviceID.directory

◆ name

wasatch.DeviceID.DeviceID.name

◆ overrides

wasatch.DeviceID.DeviceID.overrides

◆ pid

wasatch.DeviceID.DeviceID.pid

◆ product

wasatch.DeviceID.DeviceID.product

◆ serial

wasatch.DeviceID.DeviceID.serial

◆ spectra_options

wasatch.DeviceID.DeviceID.spectra_options

◆ type

wasatch.DeviceID.DeviceID.type

◆ vid

wasatch.DeviceID.DeviceID.vid

The documentation for this class was generated from the following file: