# C Programming

The LabOne C API, also known as ziAPI, provides a simple and robust way to communicate with the Data Server. It enables you to get or set parameters and receive streaming data.

 LabOne API documentation For a full reference of the ziAPI visit the LabOne API documentation.

## Getting Started

After installing the LabOne software package and relevant drivers for your instrument you are ready start programming with ziAPI. All you need is a C compiler, linker and editor. The structure of a program using ziAPI can be split into three parts: initialization/connection, data manipulation and disconnection/cleanup. The basic object that is always used is the ziConnection data structure. First, ziConnection is has to be initialized by calling ziAPIInit. After initialization ziConnection is ready to connect to a ziServer by calling ziAPIConnect. Then ziConnection is ready to be used for getting and setting parameters and streaming data. When ziConnection is not needed anymore the established connection to the ziServer has to be hung up using ziAPIDisconnect before cleaning it up by calling ziAPIDestroy.

### Examples

Along with the LabOne C API DLL, a LabOne installation includes examples to help getting started with the LabOne C API.

On Windows they are located in the folder:

C:\Program Files\Zurich Instruments\LabOne\API\C\examples\

and on Linux and macOS, after extracting the LabOne tarball, they are located in the folder:

API/C/examples.

Below you find a simple program, which sets the demodulator rate of all demods for all devices.

// Copyright [2016] Zurich Instruments AG
#include <stdlib.h>
#include <stdio.h>

#include "ziAPI.h"

int main() {
ZIResult_enum retVal;
ZIConnection conn;
char* errBuffer;
const char* serverAddress = getenv("LABONE_SERVER");
if (serverAddress == NULL) {
}

const char* device = getenv("LABONE_DEVICE_MF");
if (device == NULL) {
device = "dev3519";
}
printf("ENV LABONE_DEVICE_MF=%s\n", device);

// Initialize ZIConnection.
retVal = ziAPIInit(&conn);
if (retVal != ZI_INFO_SUCCESS) {
ziAPIGetError(retVal, &errBuffer, NULL);
fprintf(stderr, "Can't init Connection: %s\n", errBuffer);
return 1;
}

// Connect to the Data Server: Use port 8005 for the HF2 Data Server, use
// 8004 for the UHF and MF Data Servers. HF2 only support ZI_API_VERSION_1,
// see the LabOne Programming Manual for an explanation of API Levels.
retVal = ziAPIConnectEx(conn, serverAddress, 8004, ZI_API_VERSION_6, NULL);
if (retVal != ZI_INFO_SUCCESS) {
ziAPIGetError(retVal, &errBuffer, NULL);
fprintf(stderr, "Error, can't connect to the Data Server: %s.\n", errBuffer);
} else {
// Set all demodulator rates of device dev3519 to 150 Hz
char path[1024];
snprintf(path, sizeof(path), "/%s/demods/*/rate", device);
retVal = ziAPISetValueD(conn, path, 150);
if (retVal != ZI_INFO_SUCCESS) {
ziAPIGetError(retVal, &errBuffer, NULL);
fprintf(stderr, "Can't set parameter: %s\n", errBuffer);
}

// Disconnect from the Data Server. Since ZIAPIDisconnect always returns
// ZI_INFO_SUCCESS no error handling is required.
ziAPIDisconnect(conn);
}

// Destroy the ZIConnection. Since ZIAPIDestroy always returns
// ZI_INFO_SUCCESS, no error handling is required.
ziAPIDestroy(conn);

return 0;
}

## Error Handling and Logging in the LabOne C API

This section describes how to get more information when an error occurs.

In general, two types of errors can occur when using ziAPI. The two types are distinguished by the origin of the error: Whether it occurred within ziAPI itself or whether it occurred internally in the Zurich Instruments Core library.

All ziAPI functions (apart from a very few exceptions) return an exit code ZIResult_enum, which will be non-zero if the function call was not entirely successful. If the error originated in ziAPI itself, the exit code describes precisely the type of error that occurred (in other words, the exit code is not ZI_ERROR_GENERAL). In this case the error message corresponding to the exit code can be obtained with the function ziAPIGetError).

However, if the error has occurred internally, the exit code will be ZI_ERROR_GENERAL). In this case, the exit code does not describe the type of error precisely, instead a detailed error message is available to the user which can be obtained with the function ziAPIGetLastError). The function ziAPIGetLastError may be used with any function that takes a ZIConnection as an input argument (with the exception of ziAPIInit, ziAPIDestroy, ziAPIConnect, ziAPIConnectEx) and is the recommended function to use, if applicable, otherwise ziAPIGetError should be used.

The function ziAPIGetLastError was introduced in LabOne 15.11 due to the availability of ziCoreModules" in ziAPI - its not desirable in general to map every possible error to an exit code in ziAPI; what is more relevant is the associated error message.

In addition to these two functions, ziAPI’s log can be very helpful whilst debugging ziAPI-based programs. The log is not enabled by default; it’s enabled by specifying a logging level with ziAPISetDebugLevel.