1// Copyright [2017] Zurich Instruments AG
2#include <stdlib.h>
3
4#include "ziAPI.h"
5#include "ziUtils.hpp"
6
7
8int main()
9{
10 // Define the device address of the device to run the example on.
11 const char* deviceAddress = ziUtilsGetEnv("LABONE_DEVICE", "dev3123");
12 printf("ENV LABONE_DEVICE=%s\n", deviceAddress);
13
14 // Address of the data server.
15 const char* dataServer = ziUtilsGetEnv("LABONE_SERVER", "localhost");
16
17 // Port of the data server.
18 const uint16_t port = 8004;
19
20 // Over which interface the connection to the
21 // device should be established. Can be either
22 // - 1: "1GbE" - Ethernet
23 // - 2: "USB" - USB
24 // - 3: "PCIe" - PCIe
25 const char* deviceInterface = "1GbE";
26
27 ZIConnection conn = nullptr;
28
29 if (isError(ziAPIInit(&conn)))
30 {
31 return 1;
32 }
33
34 ziAPISetDebugLevel(0);
35 ziAPIWriteDebugLog(0, "Logging enabled.");
36
37 try
38 {
39 checkError(
40 ziAPIConnectEx(conn, dataServer, port, ZI_API_VERSION_6, nullptr));
41 ziApiServerVersionCheck(conn);
42 checkError(
43 ziAPIConnectDevice(conn, deviceAddress, deviceInterface, nullptr));
44 // The required parameters that will be cauclated by the PID Advisor.
45 ZIDoubleData pAdvisor = 0.0;
46 ZIDoubleData iAdvisor = 0.0;
47 ZIDoubleData dAdvisor = 0.0;
48 ZIDoubleData dlimittimeconstantAdvisor = 0.0;
49 ZIDoubleData rateAdvisor = 0.0;
50 ZIDoubleData bandwidthAdvisor = 0.0;
51
52 ZIModuleHandle pidAdvisor;
53 checkError(ziAPIModCreate(conn, &pidAdvisor, "pidAdvisor"));
54 printf("Module created, handle=%" PRIu64 ".\n", pidAdvisor);
55
56 int pidIndex = 0;
57 checkError(ziAPIModSetString(conn, pidAdvisor, "device", deviceAddress));
58
59 // Turn off auto-calc on param change. Enabled auto calculation can be used
60 // to automatically update response data based on user input.
61 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "auto", 0));
62 checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "pid/targetbw", 100e3));
63 // PID advising mode (bit coded)
64 // bit 0: optimize/tune P
65 // bit 1: optimize/tune I
66 // bit 2: optimize/tune D
67 // Example: mode = 7: Optimize/tune PID
68 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "pid/mode", 7));
69 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "index", pidIndex));
70 // DUT model
71 // source = 1: Lowpass first order
72 // source = 2: Lowpass second order
73 // source = 3: Resonator frequency
74 // source = 4: Internal PLL
75 // source = 5: VCO
76 // source = 6: Resonator amplitude
77 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "dut/source", 4));
78 // Note, if on HF2: Since the PLL and PID are 2 separate hardware units on
79 // the device, we need to additionally specify that the PID Advisor should
80 // model the HF2's PLL. checkError(ziAPIModSetString(conn, pidAdvisor,
81 // "pid/type", "pll"));
82 checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/delay", 0.0));
83 // Other DUT parameters (not required for the internal PLL model)
84 // checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/gain", 1.0));
85 // checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/bw", 1000));
86 // checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/fcenter", 15e6));
87 // checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/damping", 0.1));
88 // checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "dut/q", 10e3));
89
90 // Start values for the PID optimization. Zero values will imitate a
91 // guess. Other values can be used as hints for the optimization process.
92 checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "pid/p", 0));
93 checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "pid/i", 0));
94 checkError(ziAPIModSetDoubleData(conn, pidAdvisor, "pid/d", 0));
95 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "calculate", 0));
96
97 printf("Finished writing pidAdvisor parameters.\n");
98
99 // Start the module thread.
100 printf("Executing...\n");
101 checkError(ziAPIModExecute(conn, pidAdvisor));
102
103 printf(
104 "Starting advising. Optimization process may run up to a minute...\n");
105 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "calculate", 1));
106
107 ZIIntegerData pidAdvisorCalculate = 1;
108 while (pidAdvisorCalculate == 1)
109 {
110 sleep(500); // [ms]
111 checkError(ziAPIModGetInteger(
112 conn, pidAdvisor, "calculate", &pidAdvisorCalculate));
113 }
114 printf("Advising finished.\n");
115
116 ZIModuleEventPtr ev = NULL;
117 char path[1024];
118 ZIValueType_enum valueType;
119 uint64_t chunks;
120 checkError(ziAPIModRead(conn, pidAdvisor, ""));
121 ZIResult_enum res =
122 ziAPIModNextNode(conn, pidAdvisor, path, 1024, &valueType, &chunks);
123 while (res == ZI_INFO_SUCCESS)
124 {
125 printf("Got node: %s with %" PRIu64 " chunks of type ", path, chunks);
126 printf("%d\n", valueType);
127 for (uint64_t chunk = 0; chunk < chunks; ++chunk)
128 {
129 checkError(ziAPIModGetChunk(conn, pidAdvisor, chunk, &ev));
130 printf(
131 "Data of chunk %" PRIu64 ": type %d, header time %" PRId64 "\n",
132 chunk,
133 ev->value->valueType,
134 ev->header->systemTime);
135 printf(
136 " - Chunk header: created=%" PRId64 ", changed=%" PRId64 "\n",
137 ev->header->createdTimeStamp,
138 ev->header->changedTimeStamp);
139 switch (ev->value->valueType)
140 {
141 case ZI_VALUE_TYPE_NONE: // 0
142 printf(" - Type 'None' can't be decoded and should not appear in "
143 "the lookup!\n");
144 break;
145 case ZI_VALUE_TYPE_DOUBLE_DATA: // 1
146 {
147 ZIEvent& e = *ev->value;
148 printf(" - %d samples (double):\n", e.count);
149 for (size_t i = 0; i < e.count; ++i)
150 {
151 printf(
152 " - sample %" PRsize_t "d = %f\n", i, e.value.doubleData[i]);
153 }
154 if (strcmp(path, "/pid/p") == 0)
155 {
156 pAdvisor = e.value.doubleData[0];
157 printf("Got value of /pid/p: %f.\n", pAdvisor);
158 }
159 else if (strcmp(path, "/pid/i") == 0)
160 {
161 iAdvisor = e.value.doubleData[0];
162 printf("Got value of /pid/i: %f.\n", iAdvisor);
163 }
164 else if (strcmp(path, "/pid/d") == 0)
165 {
166 dAdvisor = e.value.doubleData[0];
167 printf("Got value of /pid/d: %f.\n", dAdvisor);
168 break;
169 }
170 else if (strcmp(path, "/pid/dlimittimeconstant") == 0)
171 {
172 dlimittimeconstantAdvisor = e.value.doubleData[0];
173 printf(
174 "Got value of /pid/dlimittimeconstant: %f.\n",
175 dlimittimeconstantAdvisor);
176 break;
177 }
178 else if (strcmp(path, "/pid/rate") == 0)
179 {
180 rateAdvisor = e.value.doubleData[0];
181 printf("Got value of /pid/rate: %f.\n", rateAdvisor);
182 break;
183 }
184 else if (strcmp(path, "/bw") == 0)
185 {
186 bandwidthAdvisor = e.value.doubleData[0];
187 printf("Got value of /pid/bw: %f.\n", bandwidthAdvisor);
188 break;
189 }
190 }
191 break;
192 case ZI_VALUE_TYPE_INTEGER_DATA: // 2
193 {
194 ZIEvent& e = *ev->value;
195 printf(" - %d samples (integer):\n", e.count);
196 for (size_t i = 0; i < e.count; ++i)
197 {
198 printf(
199 " - sample %" PRsize_t "d = %" PRId64 "\n",
200 i,
201 e.value.integerData[i]);
202 }
203 }
204 break;
205 case ZI_VALUE_TYPE_BYTE_ARRAY: // 7
206 {
207 ZIByteArray& v = *ev->value->value.byteArray;
208 printf(" - length = %u\n", v.length);
209 char* str = reinterpret_cast<char*>(malloc(v.length + 1));
210 strncpy(str, reinterpret_cast<char*>(v.bytes), v.length);
211 str[v.length] = '\0';
212 printf(" - value = '%s'\n", str);
213 free(str);
214 }
215 break;
216 case ZI_VALUE_TYPE_ADVISOR_WAVE: // 66
217 {
218 ZIAdvisorWave& v = *ev->value->value.advisorWave;
219 printf(" - timeStamp = %" PRIu64 "\n", v.timeStamp);
220 printf(" - sampleCount = %" PRIu64 "\n", v.header.sampleCount);
221 printf(" - flags = %d\n", v.header.flags);
222 // Sample format
223 // Bode = 0, Step = 1, Impulse = 2.
224 switch (v.header.sampleFormat)
225 {
226 case 0:
227 printf(
228 " sampleFormat : %d (Bode plot data).\n",
229 v.header.sampleFormat);
230 break;
231 case 1:
232 printf(
233 " sampleFormat : %d (Step plot data).\n",
234 v.header.sampleFormat);
235 break;
236 case 2:
237 printf(
238 " sampleFormat : %d (Impulse plot data).\n",
239 v.header.sampleFormat);
240 break;
241 default:
242 printf(" - Unknown sample format!\n");
243 }
244
245 printf(" - sampleFormat = %d\n", v.header.sampleFormat);
246 for (size_t i = 0; i < v.header.sampleCount; ++i)
247 {
248 printf(" - sample %" PRsize_t "d:\n", i);
249 ZIAdvisorSample& s = v.data.data[i];
250 // Note: 1. For Bode plot data, the complex result, bodeComplexData
251 // = x + j*y; the magnitude and phase must be calculated from this
252 // complex value. The unit of grid is Hz.
253 // 2. For Step plot data, x provides the value of the step response
254 // (y is always 0). The unit of grid is seconds.
255 printf(" - grid = %f\n", s.grid);
256 printf(" - x = %f\n", s.x);
257 printf(" - y = %f\n", s.y);
258 }
259 }
260 break;
261 default:
262 printf(" - Unexpected data type!\n");
263 }
264 }
265 printf("\n");
266 res = ziAPIModNextNode(conn, pidAdvisor, path, 1024, &valueType, &chunks);
267 }
268 if (res != ZI_WARNING_NOTFOUND)
269 {
270 checkError(res);
271 }
272
273 // Now we copy the values from the PID Advisor to the PID and enable the
274 // PID. Note on HF2, this sets the respective nodes in the PLLS branch, for
275 // other device classes it sets the nodes in the PIDS branch (on other
276 // device classes the PLL is implemented in the device's PID).
277 printf("Copying PID Advisor values to PID %d.\n", pidIndex);
278 checkError(ziAPIModSetIntegerData(conn, pidAdvisor, "todevice", 1));
279 checkError(ziAPIModFinish(conn, pidAdvisor));
280
281 checkError(ziAPIModEventDeallocate(conn, pidAdvisor, ev));
282
283 // Release module resources. Especially important if modules are created
284 // inside a loop to prevent excessive resource consumption.
285 checkError(ziAPIModClear(conn, pidAdvisor));
286
287 snprintf(path, sizeof(path), "/%s/pids/%d/rate", deviceAddress, pidIndex);
288 // checkError(ziAPISetValueD(conn, path, rateAdvisor));
289 printf("Enabling PID %d.\n", pidIndex);
290 snprintf(path, sizeof(path), "/%s/pids/%d/enable", deviceAddress, pidIndex);
291 checkError(ziAPISetValueI(conn, path, 1));
292 ziAPIDisconnect(conn);
293 }
294 catch (std::runtime_error& e)
295 {
296 char extErrorMessage[1024] = "";
297 ziAPIGetLastError(conn, extErrorMessage, 1024);
298 fprintf(stderr, "Error: %s\ndetails: %s\n", e.what(), extErrorMessage);
299 return 1;
300 }
301
302 ziAPIDestroy(conn);
303 return 0;
304}