Qblox qmi driver - #215
Qblox qmi driver#215heevasti wants to merge 9 commits into
Conversation
…rted editing unit-tests.
| EXT_TRIGGERS_IN_CLUSTER = 15 | ||
| # Module configuration constants: | ||
| # AO_IN_MODULE: Analog output channels in modules with value range -1V...+1V. | ||
| # AI_IN_MODULE: Analog output channels in modules with value range -1V...+1V. |
There was a problem hiding this comment.
input channels presumeably
There was a problem hiding this comment.
Yes, will correct this, thanks!
| # Add type handles as callables | ||
| for type_handle, value in self.cluster._type_handle.__dict__.items(): | ||
| if type_handle.startswith("_is"): | ||
| # As 'value' gets overridden in memory for the lambda function, do like this: |
There was a problem hiding this comment.
Will correct this, thanks!
| idn = self.cluster._get_idn() | ||
| _, model, _, _ = idn.split(",") | ||
| self._modules = {"0": _QbloxModule(model, self.cluster_funcs)} | ||
| for k, v in self.cluster._mod_handles.items(): |
There was a problem hiding this comment.
code would be a bit more readable if these keys and values have a bit more descriptive names
There was a problem hiding this comment.
I guess the v's are modules?
There was a problem hiding this comment.
Yes, I will change 'k' to refer to the slot numbers and 'v' to module handles.
| if str(module) == module_type: | ||
| # Just double check module type before returning | ||
| if ( | ||
| module_type == "QCM" |
There was a problem hiding this comment.
if these two are on the same line it looks much better
There was a problem hiding this comment.
I'm not sure if Ruff formatter will agree on that. I'll see what it thinks.
There was a problem hiding this comment.
Sorry, Ruff left it that way.
| self.cluster._slot_reset() | ||
|
|
||
| @rpc_method | ||
| def get_module(self, module_type: str, slot_no: int | None = None) -> NativeCluster | _QbloxModule: |
There was a problem hiding this comment.
I guess it might be fair enough, but if you have multiple of the same module and you specify the module name, it's not clear which one you're gonna get. Maybe ideally you warn the user (or refuse) when you know there are duplicate modules and they didn't specify the slot.
There was a problem hiding this comment.
The module you will get is the first match, i.e. with smallest slot number. I could add a message for the logger here to say the the first matching module will be 'get' when no slot number was provided. To 'know' if there are >1 modules of given type, I would have to change the loop to go to the end or do some pre-loop with the module names only. I think the call description (dosctring) in the base class and a logger info should be informative enough, without making extra checks here.
There was a problem hiding this comment.
Sure I guess that's fine!
| for sequencer in range(SEQUENCERS_IN_MODULE[module_type]): | ||
| try: | ||
| sequencer_config = module_func_refs["_get_sequencer_config"](sequencer) | ||
| if channel_type in [0, 1] and AI_IN_MODULE[module_type] > 0: |
There was a problem hiding this comment.
magical constants, ideally we replace
There was a problem hiding this comment.
Do you mean the channel_type? Those are explained in the base class docstring. But we could consider making enumerated integers class for them, which would make them more clear. Like
class ChannelTypes(Enum.Enum):
ALL_CHANNELS = 0 # all channels (default)
AI_CHANNELS = 1 # analog input channels (adc)
AO_CHANNELS = 2 # analog output channels (dac)
MRK_CHANNELS = 3 # marker channels
IO_CHANNELS = 4 # IO channels (QTM only)and replace
if channel_type in [ChannelTypes.ALL_CHANNELS, ChannelTypes.AI] ...Or perhaps with even shorter names as we use these only internally, really:
_ChannelTypes.ALL, _ChannelTypes.AI etc.
There was a problem hiding this comment.
Yeah sorry my comment was a bit short. Indeed It was not clear to me what channel type 0 and 1 would refer to. I think the second solution is good!
| for channel in sequencer_channel_map[1]: | ||
| channels[f"adc{channel}_acq_Q{sequencer}"] = sequencer_config["awg"] | ||
|
|
||
| if channel_type in [0, 2] and AO_IN_MODULE[module_type] > 0: |
There was a problem hiding this comment.
idem with previous
| for channel in sequencer_channel_map[1]: | ||
| channels[f"dac{channel}_Q{sequencer}"] = sequencer_config["awg"] # TODO: Is this always valid? | ||
|
|
||
| if channel_type in [0, 3] and DIGITAL_MARKERS_IN_MODULE[module_type] > 0: |
There was a problem hiding this comment.
idem with previous.
| invert: Any | ||
|
|
||
|
|
||
| class Qblox_QcodesCluster(Qblox_ClusterBase): |
There was a problem hiding this comment.
what is the difference between this class and Qblox_NativeCluster?
There was a problem hiding this comment.
The difference is that the 'NativeCluster' communicates directly with the cluster SCPI interface, while the 'QcodesCluster' communicates with the QCoDeS interface, which then communicates via SCPI interface (and a couple of special features). Both have their pros and cons, which I haven't managed to decide so far which one is overall better. The qblox_instruments API has changed a lot over the development of various versions, and 'QcodesCluster' option was a bit more stable towards the changes, whereas 'NativeCluster' usually needed more smaller changes. On the other hand, at times the 'QcodesCluster' option's dependency 'Cluster' class radically changed with much more complex changes in the 'QcodesCluster' as result.
The other thing is that communicating directly with the SCPI interface we actually do not need the QCoDeS dependency. This reduces also considerably dependency conflicts with other packages as we can override or ignore the QCoDeS version be something else than in the qblox_instruments requirements.
This is of course more maintenance work which is not desirable in the long term. But so far I couldn't weight one out against the other such that a decision could be made into which option we will focus on.
There was a problem hiding this comment.
Right, thanks for the explanation, that is very clear. Then let's keep both for now.
Maybe you could add a sentence or two in comments somewhere that documents this difference? It would be quite informative
Add a QMI driver for Qblox Cluster series device.
The driver contains only base functions to control the cluster, and trigger channels, and receive system info and module | function reference objects.