Squidstat API User Manual
|
The basic building block of a custom experiment are the elements. An element is an elementary experiment such as Constant Voltage/Potential (CV) or Constant Current (CC). A custom experiment can have one or more elements. The elements inside could be run one or more times. A custom experiment can also contain another custom experiment as a sub-experiment. The sub-experiment can be run one or more times as well.
We will go through an example of building and running an experiment.
First, we will have some environment setup by creating our application:
To build a custom experiment, we need at least one element. In the example we will build below, we have two elements and a sub-experiment. The sub-experiment has the same two elements only with their parameters changed.
Let us go through it step by step:
We first create a constant voltage element and set its parameters as seen in the following code block. You can see a full list of the available elements in the classes section. For now, we are only setting the required parameters. You can get a complete list of settable parameters for any given element type by examining the corresponding element class.
We create another element of a different type.
We create a custom experiment and add the previously created elements to it.
Next, we create a second experiment as a sub-experiment i.e. we are going to then add it to the main experiment.
Again, the order adding/appending the elements and the sub-experiment here corresponds to the order at which they will run. The sub-experiment and the elements it contains will be run after the elements already added to the main experiment
We create an additional constant voltage element with a different voltage setpoint.
This concludes creating the experiment. Next is how to control the workflow of the experiment.
So far, we have only created the experiment. But we need to start it and control it. The next code section employs a callback mechanism specific to Qt, called signals and slots. Callbacks are used to take an action when a specified condition is met i.e. control the workflow. For simplicity, we provided some common slots related to our API with comments inside, on what you can do. You can read more about Qt signals and slots in the following link: https://doc.qt.io/qt-5/signalsandslots.html
Reading this document should still cover most of what is needed. Basically, a signal can be emitted when an event happens. If a slot is connected to that signal, whatever is inside that slot will be executed when the signal is emitted. You can think of a signal as a condition and a slot is what will be executed once a corresponding condition is met. The only difference is the order of execution. Normal execution have sequential order. However, a slot can be emitted at anytime. Whenever that happens, the slot will execute no matter where the connection has been made (as long as a connection has been made prior). That is how we can have extra control on how and when things are executed.
An experiment is run on a specific channel of a device. You may have more than one device connected. A single device has up to 4 channels. Any channel on a specific device can run a single experiment at a time. To start an experiment, we specify the device and the channel and, then start it. To stop or pause that experiment, we need to specify its corresponding device and channel. We need to keep track of the device and channel for each experiment we start so we can control it later.
We can control a device, including starting, pausing and stopping an experiment on a specific channel using an AisInstrumentHandler A device/instrument handler can be created given a device name that we detect.
We have two parts below: one that creates logic using signals and slots. The second part assigns that logic to an instrument handler which will discuss in a bit. The first part below is creating some control-flow logic that we can assign to a handler. We can also create other logics in the same way that can be assigned to different handlers which can be used to control different devices. If we only have one device, all the logic will be handled with one handler. We can then have further control within, based on channels.
The first part is a lambda function called "connectHandlerSignals" which takes a handler as an argument and connects some of the handler signals to slots. We have other signals related to a handler you can add, which you can find in the AisInstrumentHandler This example logic has four conditions on which we can perform other tasks. That is, when we assign this logic to a specific handler, this logic will execute for that handler. The four signals and slots below in the first part are examples for you to follow in order to add other connections.
For a more complex logic for running a sequence of experiments, please refer to this example
If you would like to output the incoming data to a file such as a CSV file, you may modify the last block to something as follows:
Here we output the DC data to a CSV file but, you may do that for AC data as well in the same manner.
You may also find it useful to refer to C++ lambdas documentation: https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp
There are two signals related to a device tracker: when a device is connected and second, when a device is disconnected.
This connects a slot to the device tracker's AisDeviceTracker::newDeviceConnected signal that provides the device name. Because we have the device name, we can create a device handler and do whatever a handler can do. In this slot example, we are creating a handler, assigning the previously created logic to this handler and then starting an experiment.
Please refer to AisInstrumentHandler for possible errors that may occur when performing operations such as uploading and starting an experiment. For example, when uploading an experiment, AisInstrumentHandler::uploadExperimentToChannel may return an AisErrorCode::InvalidParameters error if the parameters are out of range where you can display the message to check which parameter was not supported for your device.
The following code connects a slot to the device tracker's AisDeviceTracker::deviceDisconnected signal with the device name.
We still have not started the experiment, we've only created an experiment and setup callback functions via signals. When we connect a device using the tracker as shown below, the AisDeviceTracker::newDeviceConnected signal will be emitted with the device name. As a result, the slot we connected earlier to the signal AisDeviceTracker::newDeviceConnected will execute (connecting the other signals and running the experiment).
Now to connect the device, the easiest way to connect all plugged-in devices is to call AisDeviceTracker::connectAllPluggedInDevices:
To connect specific devices, you may alternatively call AisDeviceTracker::connectToDeviceOnComPort with a specific COM port.
Finally, we can start the application by calling:
In the next section, we introduce a more advanced control flow.