Example MdsDataAcquisition#

  1// Copyright [2018] Zurich Instruments AG
  2//
  3// Example for the Data Acquisition Module (introduced in LabOne 17.12).
  4
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8
  9#include <algorithm>
 10#include <fstream>
 11#include <limits>
 12#include <stdexcept>
 13#include <vector>
 14
 15#include "ziAPI.h"
 16#include "ziUtils.hpp"
 17
 18// MS VC creates a define for min which of course collides with std::min
 19// needed for gcc.
 20#undef max
 21#undef min
 22
 23int main()
 24{
 25  // Define the device address of the device to run the example on.
 26  std::string serverAddress = ziUtilsGetEnv("LABONE_SERVER", "localhost");
 27  std::string deviceLeader = ziUtilsGetEnv("LABONE_DEVICE_LEADER", "dev3133");
 28  std::string deviceFollower =
 29      ziUtilsGetEnv("LABONE_DEVICE_FOLLOWER", "dev3144");
 30
 31  std::string devM = "/" + deviceLeader;
 32  std::string devS = "/" + deviceFollower;
 33
 34  // Over which interface the connection to the
 35  // device should be established. Can be either
 36  // - 1: "1GbE" - Ethernet
 37  // - 2: "USB" - USB
 38  // - 3: "PCIe" - PCIe
 39  const char* deviceInterface = "1GbE";
 40
 41  // Port of the data server.
 42  const uint16_t port = 8004;
 43
 44  ZIConnection conn = nullptr;
 45
 46  if (isError(ziAPIInit(&conn)))
 47  {
 48    return 1;
 49  }
 50
 51  ziAPISetDebugLevel(0);
 52  ziAPIWriteDebugLog(0, "Logging enabled.");
 53
 54  // Create an API Session to the Data Server reported by discovery.
 55  try
 56  {
 57    checkError(ziAPIConnectEx(
 58        conn, serverAddress.c_str(), port, ZI_API_VERSION_6, nullptr));
 59    ziApiServerVersionCheck(conn);
 60    checkError(
 61        ziAPIConnectDevice(conn, deviceLeader.c_str(), deviceInterface, NULL));
 62    checkError(ziAPIConnectDevice(
 63        conn, deviceFollower.c_str(), deviceInterface, NULL));
 64
 65    // Create instrument configuration: disable all outputs, demods and scopes.
 66    checkError(ziAPISetValueI(conn, (devM + "/demods/*/enable").c_str(), 0));
 67    checkError(ziAPISetValueI(conn, (devM + "/demods/*/trigger").c_str(), 0));
 68    checkError(ziAPISetValueI(conn, (devM + "/sigouts/*/enables").c_str(), 0));
 69    checkError(ziAPISetValueI(conn, (devM + "/scopes/*/enable").c_str(), 0));
 70    checkError(ziAPISetValueI(conn, (devM + "/imps/*/enable").c_str(), 0));
 71    checkError(ziAPISetValueI(conn, (devS + "/demods/*/enable").c_str(), 0));
 72    checkError(ziAPISetValueI(conn, (devS + "/demods/*/trigger").c_str(), 0));
 73    checkError(ziAPISetValueI(conn, (devS + "/sigouts/*/enables").c_str(), 0));
 74    checkError(ziAPISetValueI(conn, (devS + "/scopes/*/enable").c_str(), 0));
 75    checkError(ziAPISetValueI(conn, (devS + "/imps/*/enable").c_str(), 0));
 76    checkError(ziAPISync(conn));
 77
 78    printf(
 79        "Synchronizing devices %s, %s...\n",
 80        deviceLeader.c_str(),
 81        deviceFollower.c_str());
 82
 83    ZIModuleHandle mdsModule;
 84    checkError(ziAPIModCreate(conn, &mdsModule, "multiDeviceSyncModule"));
 85
 86    checkError(ziAPIModSetIntegerData(conn, mdsModule, "start", 0));
 87    checkError(ziAPIModSetIntegerData(conn, mdsModule, "group", 0));
 88    checkError(ziAPIModExecute(conn, mdsModule));
 89    checkError(ziAPIModSetString(
 90        conn,
 91        mdsModule,
 92        "devices",
 93        (deviceLeader + "," + deviceFollower).c_str()));
 94    checkError(ziAPIModSetIntegerData(conn, mdsModule, "start", 1));
 95
 96    // Wait for MDS to complete
 97    double local_timeout = 20.0;
 98    ZIIntegerData status = 0;
 99    while (status != 2 && local_timeout > 0.0)
100    {
101      checkError(ziAPIModGetInteger(conn, mdsModule, "status", &status));
102      sleep(100);  // [ms]
103      local_timeout -= 0.1;
104    }
105
106    if (status != 2)
107    {
108      printf("Error during synchronization.\n");
109      return 1;
110    }
111    printf("Devices successfully synchronized.\n");
112
113    // Device settings
114    // int out_c = 0;    // signal output channel
115    // int out_mixer_c = 0;
116    // int in_c = 0;     // signal input channel
117
118    double time_constant = 1.0e-3;  // [s]
119    double demod_rate = 10e3;       // [Sa/s]
120    int filter_order = 8;
121    double osc_freq = 1e3;   // [Hz]
122    double out_amp = 0.600;  // [V]
123
124    // Device settings
125    checkError(ziAPISetValueI(conn, (devM + "/demods/*/enable").c_str(), 0));
126    std::vector<std::string> devices(2);
127    devices[0] = devM;
128    devices[1] = devS;
129
130    for (int i = 0; i < 2; i++)
131    {
132      std::string dev = devices[i];
133      checkError(
134          ziAPISetValueD(conn, (dev + "/demods/0/phaseshift").c_str(), 0));
135      checkError(ziAPISetValueI(
136          conn, (dev + "/demods/0/order").c_str(), filter_order));
137      checkError(
138          ziAPISetValueD(conn, (dev + "/demods/0/rate").c_str(), demod_rate));
139      checkError(ziAPISetValueI(conn, (dev + "/demods/0/harmonic").c_str(), 1));
140      checkError(ziAPISetValueI(conn, (dev + "/demods/0/enable").c_str(), 1));
141      checkError(
142          ziAPISetValueI(conn, (dev + "/demods/0/oscselect").c_str(), 0));
143      checkError(
144          ziAPISetValueI(conn, (dev + "/demods/0/adcselect").c_str(), 0));
145      checkError(ziAPISetValueD(
146          conn, (dev + "/demods/0/timeconstant").c_str(), time_constant));
147      checkError(
148          ziAPISetValueD(conn, (dev + "/oscs/0/freq").c_str(), osc_freq));
149      checkError(ziAPISetValueI(conn, (dev + "/sigins/0/imp50").c_str(), 0));
150      checkError(ziAPISetValueI(conn, (dev + "/sigins/0/ac").c_str(), 0));
151      checkError(
152          ziAPISetValueD(conn, (dev + "/sigins/0/range").c_str(), out_amp / 2));
153    }
154    // settings on leader
155    checkError(ziAPISetValueI(conn, (devM + "/sigouts/0/on").c_str(), 1));
156    checkError(ziAPISetValueI(conn, (devM + "/sigouts/0/range").c_str(), 1));
157    checkError(ziAPISetValueD(
158        conn, (devM + "/sigouts/0/amplitudes/0").c_str(), out_amp));
159    checkError(
160        ziAPISetValueI(conn, (devM + "/sigouts/0/enables/0").c_str(), 0));
161
162    // Synchronization
163    checkError(ziAPISync(conn));
164
165    // measuring the transient state of demodulator filters using DAQ module
166
167    // DAQ module
168    ZIModuleHandle daqModule;
169    checkError(ziAPIModCreate(conn, &daqModule, "dataAcquisitionModule"));
170
171    // Configure the Data Acquisition Module
172    // Device on which trigger will be performed
173    checkError(
174        ziAPIModSetString(conn, daqModule, "device", deviceLeader.c_str()));
175    checkError(ziAPIModSetIntegerData(conn, daqModule, "count", 1));
176    checkError(ziAPIModSetIntegerData(conn, daqModule, "endless", 0));
177    checkError(ziAPIModSetIntegerData(conn, daqModule, "grid/mode", 2));
178    checkError(ziAPIModSetIntegerData(conn, daqModule, "type", 1));
179    checkError(ziAPIModSetString(
180        conn, daqModule, "triggernode", (devM + "/demods/0/sample.r").c_str()));
181    checkError(ziAPIModSetIntegerData(conn, daqModule, "edge", 1));
182    checkError(
183        ziAPIGetValueD(conn, (devM + "/demods/0/rate").c_str(), &demod_rate));
184    double trigger_duration = time_constant * 30;
185    ZIIntegerData sample_count =
186        static_cast<ZIIntegerData>(demod_rate * trigger_duration);
187    checkError(
188        ziAPIModSetIntegerData(conn, daqModule, "grid/cols", sample_count));
189    checkError(
190        ziAPIModSetDoubleData(conn, daqModule, "duration", trigger_duration));
191    checkError(
192        ziAPIModSetDoubleData(conn, daqModule, "delay", -trigger_duration / 4));
193    checkError(ziAPIModSetDoubleData(conn, daqModule, "holdoff/time", 0));
194    checkError(ziAPIModSetDoubleData(conn, daqModule, "holdoff/count", 0));
195    checkError(ziAPIModSetDoubleData(conn, daqModule, "level", out_amp / 6));
196    checkError(ziAPIModSetDoubleData(conn, daqModule, "hysteresis", 0.01));
197    checkError(ziAPISync(conn));
198
199    // Recording
200
201    // Subscribe to the demodulators
202    checkError(ziAPIModUnSubscribe(conn, daqModule, "*"));
203    checkError(ziAPIModSubscribe(
204        conn, daqModule, (devM + "/demods/0/sample.r").c_str()));
205    checkError(ziAPIModSubscribe(
206        conn, daqModule, (devS + "/demods/0/sample.r").c_str()));
207
208    // Execute the module
209    checkError(ziAPIModExecute(conn, daqModule));
210
211    // Send a trigger
212    checkError(
213        ziAPISetValueI(conn, (devM + "/sigouts/0/enables/0").c_str(), 1));
214
215    ZIIntegerData finished;
216    while (true)
217    {
218      checkError(ziAPIModFinished(conn, daqModule, &finished));
219      if (finished)
220      {
221        break;
222      }
223
224      sleep(1000);
225      double progress;
226      checkError(ziAPIModProgress(conn, daqModule, &progress));
227      printf("Progress %.2f\n", progress);
228    }
229
230    checkError(ziAPIModFinish(conn, daqModule));
231    checkError(ziAPIModUnSubscribe(conn, daqModule, "*"));
232
233    // Read the result
234    char path[1024];
235    checkError(ziAPIModRead(conn, daqModule, ""));
236    ZIValueType_enum valueType;
237    ZIModuleEventPtr ev = NULL;
238    uint64_t chunks;
239    ZIResult_enum res =
240        ziAPIModNextNode(conn, daqModule, path, 1024, &valueType, &chunks);
241    std::vector<ZITimeStamp> t;
242    std::vector<ZIDoubleData> mDemodR;
243    std::vector<ZIDoubleData> sDemodR;
244
245    while (res == ZI_INFO_SUCCESS)
246    {
247      printf(
248          "Reading finished result, got node: %s with %" PRIu64
249          " chunks of type ",
250          path,
251          chunks);
252      printf("%d\n", valueType);
253      for (uint64_t chunk = 0; chunk < chunks; ++chunk)
254      {
255        checkError(ziAPIModGetChunk(conn, daqModule, chunk, &ev));
256        printf(
257            "Data of chunk %" PRIu64 ": type %d, header time %" PRId64 "\n",
258            chunk,
259            ev->value->valueType,
260            ev->header->systemTime);
261
262        ZIEvent& e = *ev->value;
263        if (path == devM + "/demods/0/sample.r")
264        {
265          if (e.valueType != ZI_VALUE_TYPE_DOUBLE_DATA_TS)
266          {
267            printf("Data does not have the expected type.\n");
268            return 1;
269          }
270          for (uint32_t i = 0; i < e.count; i++)
271          {
272            t.push_back(e.value.doubleDataTS[i].timeStamp);
273            mDemodR.push_back(e.value.doubleDataTS[i].value);
274          }
275        }
276        if (path == devS + "/demods/0/sample.r")
277        {
278          if (e.valueType != ZI_VALUE_TYPE_DOUBLE_DATA_TS)
279          {
280            printf("Data does not have the expected type.\n");
281            return 1;
282          }
283          for (uint32_t i = 0; i < e.count; i++)
284          {
285            sDemodR.push_back(e.value.doubleDataTS[i].value);
286          }
287        }
288      }
289      printf("\n");
290      res = ziAPIModNextNode(conn, daqModule, path, 1024, &valueType, &chunks);
291    }
292
293    // Turn off the trigger
294    checkError(
295        ziAPISetValueI(conn, (devM + "/sigouts/0/enables/0").c_str(), 0));
296
297    // Deallocate ev which gets allocated in ziAPIModGetChunk()
298    checkError(ziAPIModEventDeallocate(conn, daqModule, ev));
299
300    // Finish the DAQ module
301    // Release module resources. Especially important if modules are created
302    // inside a loop to prevent excessive resource consumption.
303    checkError(ziAPIModClear(conn, daqModule));
304
305    // Stopping the MDS module
306    checkError(ziAPIModClear(conn, mdsModule));
307
308    // Extracting and saving the data
309    double mClockbase;
310    checkError(
311        ziAPIGetValueD(conn, (devM + "/clockbase").c_str(), &mClockbase));
312
313    std::ofstream myfile("mds_dataacquisition.txt");
314    for (size_t i = 0; i < t.size(); i++)
315    {
316      myfile << (t[i] - t[0]) / mClockbase << "," << mDemodR[i] << ","
317             << sDemodR[i] << std::endl;
318    }
319    myfile.close();
320    ziAPIDisconnect(conn);
321  }
322  catch (std::runtime_error& e)
323  {
324    char extErrorMessage[1024] = "";
325    ziAPIGetLastError(conn, extErrorMessage, 1024);
326    fprintf(stderr, "Error: %s\ndetails: %s\n", e.what(), extErrorMessage);
327    return 1;
328  }
329
330  ziAPIDestroy(conn);
331  return 0;
332}