Example ScopeModule#

  1#include <stdio.h>
  2
  3#include <algorithm>
  4#include <numeric>
  5#include <stdexcept>
  6
  7#include "ziAPI.h"
  8#include "ziUtils.hpp"
  9
 10
 11// MS VC creates a define for min which of course collides with std::min
 12// needed for gcc.
 13#undef max
 14#undef min
 15
 16void decodeScopeInterleaving(ZIScopeWaveEx& scopeData);
 17
 18int main()
 19{
 20
 21  // Define the device address of the device to run the example on.
 22  const char* deviceAddress = ziUtilsGetEnv("LABONE_DEVICE", "dev3020");
 23  printf("ENV LABONE_DEVICE=%s\n", deviceAddress);
 24  // Modify the following value to suit the device type you are using.
 25  bool isHF2Device = false;
 26
 27  // Address of the data server.
 28  const char* dataServer = ziUtilsGetEnv("LABONE_SERVER", "localhost");
 29
 30  // Port of the data server.
 31  const uint16_t port = 8004;
 32  // Port of the HF2 data server
 33  const uint16_t hf2Port = 8005;
 34
 35  // Over which interface the connection to the
 36  // device should be established. Can be either
 37  // - 1: "1GbE" - Ethernet
 38  // - 2: "USB" - USB
 39  // - 3: "PCIe" - PCIe
 40  const char* deviceInterface = "1GbE";
 41
 42  ZIConnection conn = nullptr;
 43
 44  if (isError(ziAPIInit(&conn)))
 45  {
 46    return 1;
 47  }
 48
 49  ziAPISetDebugLevel(0);
 50  ziAPIWriteDebugLog(0, "Logging enabled.");
 51
 52  try
 53  {
 54    checkError(ziAPIConnectEx(
 55        conn,
 56        dataServer,
 57        isHF2Device ? hf2Port : port,
 58        isHF2Device ? ZI_API_VERSION_0 : ZI_API_VERSION_6,
 59        nullptr));
 60    ziApiServerVersionCheck(conn);
 61    checkError(
 62        ziAPIConnectDevice(conn, deviceAddress, deviceInterface, nullptr));
 63    // This example uses mostly the default scope settings.
 64    ZIModuleHandle scope;
 65    checkError(ziAPIModCreate(conn, &scope, "scopeModule"));
 66    printf("module created, handle=%" PRIu64 "\n", scope);
 67    // Tell the module to apply scaling to the raw scope data.
 68    // This does not work for HF2 instruments.
 69    checkError(ziAPIModSetIntegerData(conn, scope, "mode", 1));
 70
 71    char path[1024];
 72    snprintf(path, sizeof(path), "/%s/sigouts/0/on", deviceAddress);
 73    checkError(ziAPISetValueI(conn, path, 1));
 74    if (!isHF2Device)
 75    {
 76      snprintf(path, sizeof(path), "/%s/scopes/0/length", deviceAddress);
 77      // length not available on HF2. Scope shots are of length 2048 samples.
 78      checkError(ziAPISetValueI(conn, path, 4096));
 79    }
 80    snprintf(path, sizeof(path), "/%s/scopes/0/wave", deviceAddress);
 81    checkError(ziAPIModSubscribe(conn, scope, path));
 82    snprintf(path, sizeof(path), "/%s/scopes/0/enable", deviceAddress);
 83    checkError(ziAPISetValueI(conn, path, 1));
 84    snprintf(
 85        path, sizeof(path), "/%s/scopes/0/stream/enables/0", deviceAddress);
 86    checkError(ziAPISetValueI(conn, path, 1));
 87    snprintf(path, sizeof(path), "/%s/scopes/0/channel", deviceAddress);
 88    if (isHF2Device)
 89    {
 90      // HF2 has only one scope channel.
 91      checkError(ziAPISetValueI(conn, path, 0x1));
 92    }
 93    else
 94    {
 95      // Enable both channels.
 96      checkError(ziAPISetValueI(conn, path, 0x3));
 97    }
 98    checkError(ziAPISync(conn));
 99
100    checkError(ziAPIModExecute(conn, scope));
101    ZIIntegerData finished;
102    checkError(ziAPIModFinished(conn, scope, &finished));
103    ZIDoubleData progress = 0.0;
104    ZIIntegerData records;
105    while ((progress < 1.0) || (records < 1))
106    {
107      sleep(500);  // [ms]
108      checkError(ziAPIModGetInteger(conn, scope, "records", &records));
109      checkError(ziAPIModProgress(conn, scope, &progress));
110
111      snprintf(
112          path,
113          sizeof(path),
114          "progress %.2f, finished = %d, records = %d",
115          progress,
116          static_cast<int>(finished),
117          static_cast<int>(records));
118      ziAPIWriteDebugLog(0, path);
119      checkError(ziAPIModFinished(conn, scope, &finished));
120    }
121    printf("\n\n");
122    checkError(ziAPIModFinish(conn, scope));
123    checkError(ziAPIModUnSubscribe(conn, scope, "*"));
124
125    checkError(ziAPIModRead(conn, scope, ""));
126    ZIModuleEventPtr ev = NULL;
127    ZIValueType_enum valueType;
128    uint64_t chunks;
129    ZIResult_enum res =
130        ziAPIModNextNode(conn, scope, path, 1024, &valueType, &chunks);
131    while (res == ZI_INFO_SUCCESS)
132    {
133      printf(
134          "Got node: %s with %" PRIu64 " chunks of type %d\n",
135          path,
136          chunks,
137          valueType);
138      for (uint64_t chunk = 0; chunk < chunks; ++chunk)
139      {
140        checkError(ziAPIModGetChunk(conn, scope, chunk, &ev));
141        printf(
142            "Data of chunk %" PRIu64 ": type %d, header time %" PRId64 "\n",
143            chunk,
144            ev->value->valueType,
145            ev->header->systemTime);
146        printf(
147            "  - Chunk header: created=%" PRId64 ", changed=%" PRId64 "\n",
148            ev->header->createdTimeStamp,
149            ev->header->changedTimeStamp);
150        switch (/*ev->value->*/ valueType)
151        {
152        case ZI_VALUE_TYPE_NONE:  // 0
153          printf("  - Type 'None' can't be decoded and should not appear in "
154                 "the lookup!\n");
155          break;
156        case ZI_VALUE_TYPE_DOUBLE_DATA:  // 1
157        {
158          ZIEvent& e = *ev->value;
159          printf("  - %d samples:\n", e.count);
160          for (size_t i = 0; i < e.count; ++i)
161          {
162            printf(
163                "    - sample %" PRsize_t "d = %f\n", i, e.value.doubleData[i]);
164          }
165        }
166        break;
167        case ZI_VALUE_TYPE_INTEGER_DATA:  // 2
168        {
169          ZIEvent& e = *ev->value;
170          printf("  - %d samples:\n", e.count);
171          for (size_t i = 0; i < e.count; ++i)
172          {
173            printf(
174                "    - sample %" PRsize_t "d = %" PRId64 "\n",
175                i,
176                e.value.integerData[i]);
177          }
178        }
179        break;
180        case ZI_VALUE_TYPE_BYTE_ARRAY:  // 7
181        {
182          ZIByteArray& v = *ev->value->value.byteArray;
183          printf("  - length = %u\n", v.length);
184          char* str = reinterpret_cast<char*>(malloc(v.length + 1));
185          strncpy(str, reinterpret_cast<char*>(v.bytes), v.length);
186          str[v.length] = '\0';
187          printf("  - value = '%s'\n", str);
188          free(str);
189        }
190        break;
191        case ZI_VALUE_TYPE_SCOPE_WAVE_EX:  // 36
192        {
193          printf("ZI_VALUE_TYPE_SCOPE_WAVE_EX\n");
194          ZIEvent& e = *ev->value;
195          decodeScopeInterleaving(*e.value.scopeWaveEx);
196        }
197        break;
198        default:
199          printf("  - Unhandled data type!\n");
200        }
201      }
202      printf("\n");
203      res = ziAPIModNextNode(conn, scope, path, 1024, &valueType, &chunks);
204    }
205    if (res != ZI_WARNING_NOTFOUND)
206    {
207      checkError(res);
208    }
209    checkError(ziAPIModEventDeallocate(conn, scope, ev));
210    // Release module resources. Especially important if modules are created
211    // inside a loop to prevent excessive resource consumption.
212    checkError(ziAPIModClear(conn, scope));
213    ziAPIDisconnect(conn);
214  }
215  catch (std::runtime_error& e)
216  {
217    char extErrorMessage[1024] = "";
218    ziAPIGetLastError(conn, extErrorMessage, 1024);
219    fprintf(stderr, "Error: %s\ndetails: %s\n", e.what(), extErrorMessage);
220  }
221
222  ziAPIDestroy(conn);
223  return 0;
224}
225
226void decodeScopeInterleaving(ZIScopeWaveEx& scopeData)
227{
228  const unsigned int channelsEnabled = std::accumulate(
229      std::begin(scopeData.channelEnable),
230      std::end(scopeData.channelEnable),
231      0u,
232      [](unsigned int a, unsigned int b) -> unsigned int
233      { return a + (b != 0); });
234  printf(
235      "%d scope channels with %d samples\n",
236      static_cast<int>(channelsEnabled),
237      static_cast<int>(scopeData.totalSamples));
238  unsigned int step = 1;
239  bool isInterleaved =
240      (scopeData.sampleFormat & ZI_SCOPE_SAMPLE_FORMAT_MASK_INTERLEAVED) != 0;
241  if (isInterleaved)
242  {
243    step = channelsEnabled;
244  }
245  uint64_t startIndex = 0;
246  unsigned int channelIndex = 0;
247  const int multiplier = isInterleaved ? channelsEnabled : 1;
248  for (auto channelEnabled : scopeData.channelEnable)
249  {
250    if (channelEnabled != 0)
251    {
252      printf("Channel %d:\n", channelIndex);
253      for (auto i = startIndex;
254           i < startIndex + scopeData.totalSamples * multiplier;
255           i += step)
256      {
257        // The scope module delivers only floats so we can use the dataFloat
258        // field without first testing.
259        printf("%8.6f\n", scopeData.data.dataFloat[i]);
260      }
261      startIndex += isInterleaved ? 1 : scopeData.totalSamples * multiplier;
262    }
263    ++channelIndex;
264  }
265  printf("\n");
266}