Skip to content
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

Is there a "reset instrument to defaults from yaml file" function or similar? #83

Open
dougthor42 opened this issue May 25, 2023 · 5 comments

Comments

@dougthor42
Copy link
Contributor

Is there a function/method that will reset a simulated instrument to the defaults defined in the yaml file?

What I'd like to be able to do is basically:

import pyvisa
rm = pyvisa.ResourceManager("myfile.yaml@sim")
instr = rm.OpenResource("ASRL1::INSTR")

instr.query("volt")  # 5, the default defined by myfile.yaml
instr.write("volt 10")
instr.query("volt")  # 10
instr.reset_to_defaults()  # magic function that I'm asking about
instr.query("volt")  # 5, the default defined by myfile.yaml

Does such a method exist? Closing the resource and/or the resource manager does not reset things (this might be related to #82).

Steps to Reproduce

Create this YAML file. I called it "doug_example.yaml":
---
spec: "1.1"

devices:

  MyDevice:
    eom:
      ASRL INSTR:
        q: "\r"
        r: "\r\n"
    error:
      response:
        command_error: "invalid command. Update the yaml file."
        query_error: "empty buffer"
    dialogues:
      - q: ";LC:DONE?"
        r: "done"
    properties:
      echo:
        default: "0"
        setter:
          q: "echo {}"
          r: "OK"
        getter:
          q: "echo?"
          r: "{}"

resources:
  "ASRL1::INSTR":
    device: "MyDevice"
Create this Python file. I called it "doug_example.py":
import pathlib

import pyvisa

VISA_ADDR = "ASRL1::INSTR"
SIM_BACKEND = str(pathlib.Path(__file__).parent / "doug_example.yaml@sim")


def create_instr() -> tuple[pyvisa.ResourceManager, pyvisa.Resource]:
    rm = pyvisa.ResourceManager(visa_library=SIM_BACKEND)

    instr = rm.open_resource(VISA_ADDR)
    instr.read_termination = "\r\n"
    instr.write_termination = "\r"

    print(f"ResourceManager session: {rm.session}")

    return rm, instr


rm, instr = create_instr()


want = "0"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")

want = "OK"
got = instr.query("echo 1")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")


want = "1"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")


# Magic reset command
print("Running reset")
rm.close()
print("Creating new resource manager and instrument")
rm, instr = create_instr()


want = "0"
got = instr.query("echo?")
correct = got == want
print(f"{got = }\t{want = }\t{correct = }")

Run python doug_example.py and get this output:

$ python doug_example.py 
ResourceManager session: 5282223
got = '0'       want = '0'      correct = True
got = 'OK'      want = 'OK'     correct = True
got = '1'       want = '1'      correct = True
Running reset
Creating new resource manager and instrument
ResourceManager session: 1299675
got = '1'       want = '0'      correct = False
@MatthieuDartiailh
Copy link
Member

Sorry for the delay but I think we have no such thing. You may be able to use CLS to achieve something similar but we could also envision adding a custom method.

@dougthor42
Copy link
Contributor Author

No worries! After all, I still haven't addressed pyvisa/pyvisa-py#374 lol

I assume that, at it's core, pyvisa-sim is a glorified dictionary where "queries" are the keys and "responses" are the values. It seems like we should just be able to empty that dictionary to reset things. Am I on the right track there?

Where is this dictionary-like data structure defined? I'd imagine that a custom method on the Resource Manager or perhaps the individual Resource is probably easy to implement.

@bilderbuchi
Copy link

Closing the [...] resource manager does not reset things (this might be related to #82).

Are you sure? I just tripped on this/#82 again, and closing the resource manager so far seems sufficient to clean up hidden state.

@jenshnielsen
Copy link

TLDR: calling resource_manager.visalib._init() will reset all devices loaded from the same yaml file.

I spent a bit of time debugging why this happens. As far as I can see the state is kept in the Device class The device class is in turn stored as a member of the Devices class which is
in turn kept in the SimVisaLibrary. SimVisaLibrary is a subclass of VisaLibraryBase which in turn implements a registry of
loaded libraries here Which means that if a SimVisaLibrary for a given yaml path exists, it will be reused next time you load SimVisaLibrary for that yaml path.

As the Device is loaded via
_init only when SimVisaLibrary is created this in turn means that the device state is kept as long as an instance of SimVisaLibrary is kept alive. One can force a reload from disk by calling the private method _init on the SimVisaLibrary class bound to a resource manager. Probably via resource_manager.visalib as resource_manager.visalib._init()

I did not trace all objects that keep a reference to the visa library but it could be that the resource_manager is the only object that does this so closing the resource manager would under some circumstances trigger the visalib to be garbage collected explaining the observations above (the mentioned registry in VisaLibraryBase is a WeakValueDict so it does it self add to the refcount)

@MatthieuDartiailh
Copy link
Member

Thanks for investigating this @jenshnielsen

Since it seems a needed feature, I would welcome a PR in that direction.

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

No branches or pull requests

4 participants