Getting Started with LabOne Modules¶
In this Tutorial you will learn the basic usage of the LabOne Modules. The Tutorial uses the Device Settings Module to store the settings of a connected device to a file.
Introduction¶
LabOne Modules are small software components that help with common tasks. An instance of a LabOne Module is created based on existing session to a data server.
sequenceDiagram
actor User
User ->>+ Client: connect to Data Server
participant LabOne Module
Client->>+Data Server: create new session
Data Server-->>-Client:
Client-->>-User:
User ->>+ Client: create a LabOne Module
Client->>+LabOne Module: instanciate(Data Server)
LabOne Module->>+Data Server: create new session
Data Server-->>-LabOne Module:
LabOne Module-->>-Client:
Client-->>-User:
LabOne Data Server Session¶
The first step is therefore to create a connection to a LabOne Data Server and connect to a device.
from zhinst.core import ziDAQServer
daq = ziDAQServer("localhost", 8004, 6)
daq.connectDevice("DEV2345", "1GbE")
from zhinst.core import ziDAQServer
daq = ziDAQServer("localhost", 8005, 1)
daq.connectDevice("DEV2345", "USB")
from zhinst.toolkit import Session
session = Session("localhost")
device = session.connect_device("DEV2345")
from zhinst.toolkit import Session
session = Session("localhost", hf2=True)
device = session.connect_device("DEV2345")
#include <iostream>
#include <unistd.h>
#include "ziAPI.h"
/**
* Error handling for the ziAPI.
* Translate C API result codes into C++ exceptions
*
* @param[in] conn Pointer to the ziConnection for which the value(s) will be set.
* @param[in] resultCode Result code from the ziAPI.
*/
void handleError(ZIConnection conn, ZIResult_enum resultCode) {
if (resultCode == ZI_INFO_SUCCESS) {
return;
}
char *errorDescription;
ziAPIGetError(resultCode, &errorDescription, nullptr);
constexpr size_t maxErrorLength = 1000;
char errorDetails[maxErrorLength];
errorDetails[0] = 0;
ziAPIGetLastError(conn, errorDetails, maxErrorLength);
auto message = std::string{"LabOne C API error "} +
std::to_string(resultCode) + ": " + errorDescription +
"\nDetails: " + errorDetails;
throw std::runtime_error(message);
}
int main(int argc, char** argv)
{
ZIConnection conn = nullptr;
handleError(conn, ziAPIInit(&conn));
handleError(
conn, ziAPIConnectEx(conn, "localhost", 8004, ZI_API_VERSION_6, nullptr)
);
handleError(conn, ziAPIConnectDevice(conn, "DEV2345", "1GbE", nullptr));
}
#include <iostream>
#include <unistd.h>
#include "ziAPI.h"
/**
* Error handling for the ziAPI.
* Translate C API result codes into C++ exceptions
*
* @param[in] conn Pointer to the ziConnection for which the value(s) will be set.
* @param[in] resultCode Result code from the ziAPI.
*/
void handleError(ZIConnection conn, ZIResult_enum resultCode) {
if (resultCode == ZI_INFO_SUCCESS) {
return;
}
char *errorDescription;
ziAPIGetError(resultCode, &errorDescription, nullptr);
constexpr size_t maxErrorLength = 1000;
char errorDetails[maxErrorLength];
errorDetails[0] = 0;
ziAPIGetLastError(conn, errorDetails, maxErrorLength);
auto message = std::string{"LabOne C API error "} +
std::to_string(resultCode) + ": " + errorDescription +
"\nDetails: " + errorDetails;
throw std::runtime_error(message);
}
int main(int argc, char** argv)
{
ZIConnection conn = nullptr;
handleError(conn, ziAPIInit(&conn));
handleError(
conn, ziAPIConnectEx(conn, "localhost", 8005, ZI_API_VERSION_1, nullptr)
);
handleError(conn, ziAPIConnectDevice(conn, "DEV2345", "USB", nullptr));
}
ziDAQ('connect', 'localhost', 8004, 6);
ziDAQ('connectDevice', 'DEV2345', '1GbE')
ziDAQ('connect', 'localhost', 8005, 1);
ziDAQ('connectDevice', 'DEV2345', 'USB')
using zhinst;
namespace LabOneTutorial
{
class Program
{
static void Main(string[] args)
{
ziDotNET daq = new ziDotNET();
daq.init("localhost", 8004, (ZIAPIVersion_enum)6);
daq.connectDevice("DEV2345", "1GbE", "");
}
}
}
using zhinst;
namespace LabOneTutorial
{
class Program
{
static void Main(string[] args)
{
ziDotNET daq = new ziDotNET();
daq.init("localhost", 8005, (ZIAPIVersion_enum)1);
daq.connectDevice("DEV2345", "USB", "");
}
}
}
TODO
Module Instantiation¶
A new instance of a LabOne Module can be created at any time, and there is no limitation how many instances can be created. However, since every module creates a new session to the Data Server, it consumes resources both inside the client and the server. LabOne Modules should therefore be created with care.
For the purpose of this tutorial, we instantiate a Device Settings Module. However, the process is for all LabOne Modules the same.
module = daq.deviceSettings()
module = session.modules.device_settings
Note
Toolkit caches the instance of every LabOne Module. To create a new
instance of a LabOne Module one can use the create_...
method
module = session.modules.create_device_settings_module()
ZIModuleHandle module;
handleError(conn, ziAPIModCreate(conn, &module, "deviceSettings"));
module = ziDAQ('deviceSettings');
ziModule module = daq.deviceSettings();
TODO
The Module already created a separate session to the Data Server and is ready to use.
Module Configuration¶
Modules are controlled, similar like the devices and Data Server, through nodes. The commands in the API are identical.
module.setString("/DEVICE", "DEV2345")
module.setString("/COMMAND", "save")
module.setString("/FILENAME", "module_tutorial")
output_dir = module.getString("/PATH")
print(f"Config file module_tutorial.xml will be written to {output_dir}.")
module.device(device)
module.command("save")
module.filename("module_tutorial")
output_dir = module.path()
print(f"Config file module_tutorial.xml will be written to {output_dir}.")
handleError(conn, ziAPIModSetString(conn, module, "/DEVICE", "DEV2345"));
handleError(conn, ziAPIModSetString(conn, module, "/COMMAND", "save"));
handleError(conn, ziAPIModSetString(conn, module, "/FILENAME", "module_tutorial"));
char outputDir[1024];
unsigned int length = 0;
handleError(conn, ziAPIModGetString(conn, module, "/PATH", outputDir, &length, 1024));
std::cout << "Config file module_tutorial.xml will be written to " << outputDir << "." << std::endl;
ziDAQ('setString', module, '/DEVICE', 'DEV2345')
ziDAQ('setString', module, '/COMMAND', 'save')
ziDAQ('setString', module, '/FILENAME', 'module_tutorial')
output_dir = ziDAQ('getString', module, '/PATH');
fprintf('Config file module_tutorial.xml will be written to %s.', output_dir);
module.setString("/DEVICE", "DEV2345");
module.setString("/COMMAND", "save");
module.setString("/FILENAME", "module_tutorial");
String outputDir = daq.getString("/PATH");
System.Diagnostics.Trace.WriteLine(
String.Format("Config file module_tutorial.xml will be written to {0}.", outputDir));
TODO
The above commands configure the Device Settings Module to store the settings
for the connected Device to the default directory in a file called module_tutorial.xml
.
The output of the above command should be the default directory path where the
Device Settings Module stores and loads the settings from.
It becomes clear now the LabOne Modules can be controlled by nodes in the same way as the Devices and the Data Server. A list of available nodes can be found on the respective page.
Module Execution¶
The additional functions described in the overview page are available on all LabOne Modules and are used for general tasks such as starting, reading and checking the state of the Module.
Info
A lot of modules are in an idle state by default. After the configuration
the must be started with the execute
explicitly.
module.execute()
module.execute()
handleError(conn, ziAPIModExecute(conn, module));
ziDAQ('execute', module)
``` vbnet module.execute();
TODO
The execute
commands starts the execution. Since the modules run in a separate
thread the module execution is asynchronous and the user can either continuously
read the data or do something else in the meantime.
import time
while not module.finished():
time.sleep(0.01)
import time
while not module.finished():
time.sleep(0.01)
int64_t finished = 0;
handleError(conn, ziAPIModFinished(conn, module, &finished));
while(!finished)
{
handleError(conn, ziAPIModFinished(conn, module, &finished));
usleep(10);
}
while not ziDAQ('finished', module)
pause(0.01);
end
``` vbnet while (!module.finished()) { System.Threading.Thread.Sleep(50); }
TODO
The above lines block until the LabOne Module is finished.
Important
It is Important to wait before the module execution is finished before closing the program/session. Since the execution is asynchronous and the lifetime of the module thread is bound to the session object, the module would otherwise not be able to finish its task.
You have successfully used the LabOne Device Settings Module to store the settings
from a connected device to a file called module_tutorial
. The usage of the
Module applies similarly to all other LabOne modules.