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}