Saving tab entries in a BLACs Tab

37 views
Skip to first unread message

Michael D.

unread,
Jan 6, 2021, 2:09:16 PM1/6/21
to the labscript suite
Hello, I've been trying to understand labscript better and how it works underneath. Currently I'm trying to understand how widgets and the ui is added and created, as well as how this information is stored. I think I have an okay understanding of how to make UIs and widgets now, but I'm currently struggling with understanding how blacs saves information (other than the connection table and experiment shot results).

I'm currently modifying the NI blacs tab to have additional fields to save the windows device id that corresponds to the NI device, and a box to check whether or not to use a feature of windows to restart the USB bus it's attached to. The field for the device id is just a simple text box. I currently have these to set to a default state when the tab is created, but if a user enters in a value I would like blacs to save this text entry or whether or not the checkbox was checked. I've been looking at the other labscript device files to see how they save their tab states, but I can't seem to figure it out. How does blacs save the tab state when the application is exited? How can I restore these values when blacs is started again? Is it through the h5 file found in app_saved_configs?

Philip Starkey

unread,
Jan 6, 2021, 7:47:50 PM1/6/21
to labscri...@googlegroups.com
Hi Michael,

You might want to take a look at the Camera device here (the get_save_data and restore_save_data methods of the BLACS tab).
(Note for anyone coming across this post in the future after searching for cameras: The camera device is for communicating with cameras via BIAS. BIAS is an unmaintained/deprecated component of the labscript suite. You probably want to use the IMAQdxCamera or other similarly named devices instead which are controlled directly from BLACS.)
Basically, get_save_data() is called by BLACS at appropriate points in time and should return a dictionary of data you want to save. restore_save_data() is the called when the tab is created/restarted and gives you a dictionary of the saved data, which you can use to restore however you like (but please don't assume that the data will always be there - there are several cases where restore_save_data will be called before get_save_data, like adding a new device or deleting the BLACS setting file, so you code needs to be able to handle the dictionary being empty!).

If you want to go deeper, these methods are ultimately called by the front panel settings code in BLACS. I would probably advise not to go deeper into it because the front panel settings code was written very early on in the development, as it a bit of a disaster zone (it was bad enough that I didn't want to attempt to rewrite it when we rewrote BLACS when moving from GTK to Qt).

Hope that helps!

Cheers,
Phil

On Thu, 7 Jan 2021 at 06:09, Michael D. <mjd...@umd.edu> wrote:
Hello, I've been trying to understand labscript better and how it works underneath. Currently I'm trying to understand how widgets and the ui is added and created, as well as how this information is stored. I think I have an okay understanding of how to make UIs and widgets now, but I'm currently struggling with understanding how blacs saves information (other than the connection table and experiment shot results).

I'm currently modifying the NI blacs tab to have additional fields to save the windows device id that corresponds to the NI device, and a box to check whether or not to use a feature of windows to restart the USB bus it's attached to. The field for the device id is just a simple text box. I currently have these to set to a default state when the tab is created, but if a user enters in a value I would like blacs to save this text entry or whether or not the checkbox was checked. I've been looking at the other labscript device files to see how they save their tab states, but I can't seem to figure it out. How does blacs save the tab state when the application is exited? How can I restore these values when blacs is started again? Is it through the h5 file found in app_saved_configs?

--
You received this message because you are subscribed to the Google Groups "the labscript suite" group.
To unsubscribe from this group and stop receiving emails from it, send an email to labscriptsuit...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/labscriptsuite/deb67d36-f174-4525-b2e8-b4f60237a4b2n%40googlegroups.com.


--
Dr Philip Starkey
Senior Technician (Lightboard developer)

School of Physics & Astronomy
Monash University
10 College Walk, Clayton Campus
Victoria 3800, Australia
Message has been deleted

Michael D.

unread,
Jan 8, 2021, 3:54:49 PM1/8/21
to the labscript suite
Thank you!! This did the trick perfectly and pointed me right where I needed to go.

Philip Starkey

unread,
Jan 9, 2021, 7:50:47 PM1/9/21
to labscri...@googlegroups.com
Hi Michael,

In a slightly unrelated topic, how can one change an attribute value in a worker process from the main thread? I can see how workers are created, and how functions are called and returned between a worker and its parent, but what if I wanted to change an aspect of the worker after it has been created? Say a worker has some flag set to true when it was created by the tab, but at a later point id like to toggle that flag during idle. How can I communicate the UI change to the worker?  

Methods (decorated with @define_state(...)) of the BLACS tab can interact with a BLACS worker using the yield keyword. This can only be used to call a method of the BLACS worker, not directly update a variable in the worker directly. However, you can just write a method in the worker to update the variable. Note that @define_state decorator ensures the BLACS tab method is executed by the BLACS tab statemachine at the appropriate time (and not necessarily immediately) 

Using your suggested example, you would place a checkbox (that you can toggle) in the BLACS tab GUI, and connect the Qt clicked signal to your new BLACS tab method. This method should be decorated with @define_state(...), meaning clicks of the checkbox will queue up an event, not execute your method. There are 3 arguments to @define_state (one of which is optional). The first indicates what "modes" your method can run in. This will likely just be MODE_MANUAL (importable from blacs.tab_base_classes) as I suspect you don't want things to change on GUI click during buffered execution of shots or the transitions to/from that mode. The second argument is called queue_state_indefinitely, and indicates whether you would like the queued event (to execute your method) to stay in the queue even if it can't run yet (like for example if you were in buffered mode). True means it sticks around until it can run, False means it's deleted if it can't run. Typically you want True for this value, otherwise you get an inconsistent state between the actual Qt checkbox state and whatever it feeds into. The third argument is called delete_stale_states, and defaults to False (so is optional). In this case, you should set it to True - what it does is compress N sequential method events into only the last one. So if someone toggles the checkbox faster than the worker can process, it doesn't back up and execute each one, it throws the early ones away and takes the most up-to-date event.

So you want something like (in your BLACS tab):
@define_state(MODE_MANUAL, True, True)
def on_checkbox_clicked(self, checkbox_state):
    # checkbox_state is provided by the Qt clicked signal
    pass

I've left off the Qt signal connection in the tab initialisation code for brevity

Then you'll want to queue up some work. This can be done using:
    return_data = yield(self.queue_work(self.primary_worker, 'worker_method_name', checkbox_state))

And then you'll want a worker method like:
class MyWorker(Worker)

    ...

    def worker_method_name(self, checkbox_state):
        # update worker attribute, program device, whatever

And that is pretty much it! Let me know if anything doesn't make sense.

Cheers,
Phil

On Sat, 9 Jan 2021 at 07:05, Michael D. <mjd...@umd.edu> wrote:
Thank you very much, that did the trick and now I see how it's all saved.

In a slightly unrelated topic, how can one change an attribute value in a worker process from the main thread? I can see how workers are created, and how functions are called and returned between a worker and its parent, but what if I wanted to change an aspect of the worker after it has been created? Say a worker has some flag set to true when it was created by the tab, but at a later point id like to toggle that flag during idle. How can I communicate the UI change to the worker?

If I understand it right it looks like when a tab tells a worker to do something it calls put() with the allowed states, the function to call, and its arguments (triggered by a yield command). But I can't seem to figure out how to change an attribute of the worker itself. 

On Wednesday, January 6, 2021 at 7:47:50 PM UTC-5 Philip Starkey wrote:
Reply all
Reply to author
Forward
0 new messages