-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathLJM_StreamUtilities.h
316 lines (269 loc) · 10.1 KB
/
LJM_StreamUtilities.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/**
* Name: LJM_StreamUtilities.c
* Desc: Provides some basic helper functions for stream applications
**/
#ifndef LJM_STREAM_UTILITIES
#define LJM_STREAM_UTILITIES
#include "LJM_Utilities.h"
#include <stdlib.h>
// Limit how many scans should be printed for each call to PrintScans
enum { MAX_SCANS_TO_PRINT = 4 };
// STREAM_OUT#(0:3)_LOOP_SIZE
enum { SET_LOOP_USE_NEW_DATA_IMMEDIATELY = 1 };
enum { SET_LOOP_WAIT_FOR_SYNCH = 2 };
enum { SET_LOOP_SYNCH = 3 };
/**
* Enables logging for stream purposes
**/
void SetupStreamDebugLogging();
/**
* Prints any scan information
**/
void PrintScans(int numScans, int numChannels, const char ** channelNames,
const int * channelAddresses, int deviceScanBacklog, int LJMScanBacklog,
int iteration, double * aData);
/**
* Prints information after stream has finished
**/
void PrintStreamConclusion(unsigned int timeStart, unsigned int timeEnd, int numReads,
int scansPerRead, int numChannels, int totalSkippedScans);
/**
* Calulates how many LJM_eStreamRead calls should be done.
* Para: numSeconds: the desired number of seconds to stream for.
* scanRate: the actual scan rate returned from the device.
* (LJM_eStreamStart returns this)
* scansPerRead: the ScansPerRead parameter of LJM_eStreamStart
**/
int CalculateNumReads(int numSeconds, double scanRate, int scansPerRead);
/**
* Checks if stream is enabled on the device, then disables it if so
**/
void DisableStreamIfEnabled(int handle);
/**
* Iterates through aData and returns the number of autorecovery scans.
* Para: numInChannels, the number of stream in channels.
* scansPerRead, the number of scans in one LJM_eStreamRead
* aData, the results of one LJM_eStreamRead
**/
int CountAndOutputNumSkippedScans(int numInChannels, int scansPerRead, double * aData);
/**
* Prints the iteration number, and prints the backlog values if they are greater than their
* respective thresholds.
**/
void OutputStreamIterationInfo(int iteration, int deviceScanBacklog, int deviceScanBacklogThreshold,
int LJMScanBacklog, int LJMScanBacklogThreshold);
/**
* Calculates how much sleep should be done based on how far behind stream is.
**/
double CalculateSleepFactor(int scansPerRead, int LJMScanBacklog);
/**
* Sleeps for approximately the expected amount of time until the next scan is
* ready to be read.
**/
void VariableStreamSleep(int scansPerRead, int scanRate, int LJMScanBacklog);
/**
* Enables externally clocked stream on the device. On the T7 and T8, externally
* clocked stream is read by pulses input to CIO3.
**/
void SetupExternalClockStream(int handle);
/**
* Enables FIO0 to pulse out for numPulses pulses. This is used in these
* examples for external stream. This is especially useful for testing external
* stream - connect a wire from FIO0 to CIO3 and call this function before
* starting stream. numPulses should be greater than the expected number of
* pulses needed because clock shift may occur.
**/
void EnableFIO0PulseOut(int handle, int pulseRate, int numPulses);
/**
* Does a printf of the message then outputs the text to the debug
* logger. Requires C99 or later standard and LABJACK_DEBUG_LOG_OUTPUT must be
* defined and set to 1
**/
void PrintAndLog(const char * outputString, ...);
// Source
void PrintScans(int numScans, int numChannels, const char ** channelNames,
const int * channelAddresses, int deviceScanBacklog, int LJMScanBacklog,
int iteration, double * aData)
{
int scanI, chanI;
int numSkippedScans = 0;
const int MAX_NUM = MAX_SCANS_TO_PRINT;
int limitScans = numScans > MAX_NUM;
int maxScansPerChannel = limitScans ? MAX_NUM : numScans;
char const * formatString;
unsigned short temp;
unsigned char * bytes;
for (chanI=0; chanI<numChannels; chanI++) {
if (channelAddresses[chanI] < 1000) {
formatString = "%10s%14s";
}
else {
formatString = "%10s%24s";
}
printf(formatString, channelNames[chanI], "");
}
printf("\n");
for (scanI = 0; scanI < maxScansPerChannel * numChannels; scanI += numChannels) {
for (chanI=0; chanI<numChannels; chanI++) {
if (aData[scanI+chanI] == LJM_DUMMY_VALUE) {
++numSkippedScans;
}
if (channelAddresses[chanI] < 1000) {
printf("aData[%3d]: %+.05f ", scanI+chanI, aData[scanI + chanI]);
}
else {
temp = (unsigned short) aData[scanI + chanI];
bytes = (unsigned char *)&temp;
printf("aData[%3d]: 0x ", scanI + chanI);
printf("%02x %02x", bytes[0], bytes[1]);
printf(" (% 7.00f) ", aData[scanI + chanI]);
}
}
printf("\n");
}
if (limitScans) {
printf("%d scans were omitted from this output.\n", numScans - MAX_NUM);
}
}
void PrintStreamConclusion(unsigned int timeStart, unsigned int timeEnd, int numReads,
int scansPerRead, int numChannels, int totalSkippedScans)
{
double msPerRead = ((double)timeEnd - timeStart) / numReads;
printf("\nFinished:\n\t%d iterations over approximately %d milliseconds\n",
numReads, timeEnd - timeStart);
printf("\t%f ms/read\n", msPerRead);
printf("\t%f ms/sample\n\n", msPerRead / (scansPerRead * numChannels));
if (totalSkippedScans) {
printf("\n****** Total number of skipped scans: %d ******\n\n", totalSkippedScans);
}
}
void SetupStreamDebugLogging()
{
// SetConfigString and SetConfigValue are defined in LJM_Utilities.h
SetConfigString(LJM_DEBUG_LOG_FILE, "default");
SetConfigValue(LJM_DEBUG_LOG_FILE_MAX_SIZE, 123456789);
SetConfigValue(LJM_DEBUG_LOG_LEVEL, LJM_STREAM_PACKET);
SetConfigValue(LJM_DEBUG_LOG_MODE, LJM_DEBUG_LOG_MODE_CONTINUOUS);
}
int CalculateNumReads(int numSeconds, double scanRate, int scansPerRead)
{
int numReads = (int)(numSeconds * scanRate / scansPerRead);
if (numReads < 1) {
numReads = 1;
}
return numReads;
}
void DisableStreamIfEnabled(int handle)
{
double firmwareVersion;
double enabled;
static const char * name = "STREAM_ENABLE";
static const int STREAM_NOT_RUNNING = 2620;
static const char * fwname = "FIRMWARE_VERSION";
int err = LJM_eReadName(handle, fwname, &firmwareVersion);
ErrorCheck(err, "LJM_eReadName(Handle=%d, Name=%s, ...)", handle, fwname);
// T7 FW 1.0024 and lower does not allow read of STREAM_ENABLE
if (GetDeviceType(handle) == LJM_dtT7 && firmwareVersion < 1.0025) {
printf("Forcing disable of stream for handle: %d\n", handle);
err = LJM_eStreamStop(handle);
if (err != LJME_NOERROR && err != STREAM_NOT_RUNNING) {
ErrorCheck(err, "LJM_eStreamStop(Handle=%d)", handle);
}
return;
}
err = LJM_eReadName(handle, name, &enabled);
ErrorCheck(err, "LJM_eReadName(Handle=%d, Name=%s, ...)", handle, name);
if ((int)enabled) {
printf("Disabling stream for handle: %d\n", handle);
err = LJM_eStreamStop(handle);
PrintErrorIfError(err, "LJM_eStreamStop(Handle=%d)", handle);
}
}
int CountAndOutputNumSkippedScans(int numInChannels, int scansPerRead, double * aData)
{
int j;
int numSkippedSamples = 0;
for (j = 0; j < numInChannels * scansPerRead; j++) {
if (aData[j] == LJM_DUMMY_VALUE) {
++numSkippedSamples;
}
}
if (numSkippedSamples) {
printf("****** %d data scans were placeholders for scans that were skipped ******\n",
numSkippedSamples / numInChannels);
printf("****** %.01f %% of the scans were skipped ******\n",
100 * (double)numSkippedSamples / scansPerRead / numInChannels);
}
return numSkippedSamples / numInChannels;
}
void OutputStreamIterationInfo(int iteration, int deviceScanBacklog, int deviceScanBacklogThreshold,
int LJMScanBacklog, int LJMScanBacklogThreshold)
{
printf("iteration: %d", iteration);
if (deviceScanBacklog > deviceScanBacklogThreshold) {
printf(", deviceScanBacklog: %d", deviceScanBacklog);
}
if (LJMScanBacklog > LJMScanBacklogThreshold) {
printf(", LJMScanBacklog: %d", LJMScanBacklog);
}
printf("\n");
}
double CalculateSleepFactor(int scansPerRead, int LJMScanBacklog)
{
static const double DECREASE_TOTAL = 0.9;
double portionScansReady = (double)LJMScanBacklog / scansPerRead;
if (portionScansReady > DECREASE_TOTAL) {
return 0;
}
return (1 - portionScansReady) * DECREASE_TOTAL;
}
void VariableStreamSleep(int scansPerRead, int scanRate, int LJMScanBacklog)
{
double sleepFactor = CalculateSleepFactor(scansPerRead, LJMScanBacklog);
int sleepMS = (int)(sleepFactor * 1000 * scansPerRead / (double)scanRate);
if (sleepMS < 1) {
return;
}
MillisecondSleep(sleepMS); // 1000 is to convert to milliseconds
}
void SetupExternalClockStream(int handle)
{
printf("Setting up externally clocked stream\n");
WriteNameOrDie(handle, "STREAM_CLOCK_SOURCE", 2);
WriteNameOrDie(handle, "STREAM_EXTERNAL_CLOCK_DIVISOR", 1);
}
void EnableFIO0PulseOut(int handle, int pulseRate, int numPulses)
{
// Set FIO0 to do a 50% duty cycle
// https://labjack.com/support/datasheets/t-series/digital-io/extended-features/pulse-out
int rollValue = 10000000 /* 10 MHz */ / pulseRate;
printf("Enabling %d pulses on FIO0 at a %d Hz pulse rate\n", numPulses, pulseRate);
WriteNameOrDie(handle, "DIO0_EF_ENABLE", 0);
WriteNameOrDie(handle, "DIO_EF_CLOCK0_DIVISOR", 8);
WriteNameOrDie(handle, "DIO_EF_CLOCK0_ROLL_VALUE", rollValue);
WriteNameOrDie(handle, "DIO_EF_CLOCK0_ENABLE", 1);
WriteNameOrDie(handle, "DIO0_EF_INDEX", 2);
WriteNameOrDie(handle, "DIO0_EF_OPTIONS", 0);
WriteNameOrDie(handle, "DIO0", 0);
WriteNameOrDie(handle, "DIO0_EF_CONFIG_A", rollValue/2);
WriteNameOrDie(handle, "DIO0_EF_CONFIG_B", 0);
WriteNameOrDie(handle, "DIO0_EF_CONFIG_C", numPulses);
WriteNameOrDie(handle, "DIO0_EF_ENABLE", 1);
}
#ifdef LABJACK_DEBUG_LOG_OUTPUT
void PrintAndLog(const char * outputString, ...)
{
char formattedString[256];
va_list myArgs, logArgs;
const char * logOutput = getenv("LABJACK_DEBUG_LOG_OUTPUT");
va_start(myArgs, outputString);
if(logOutput != NULL && strcmp(logOutput, "1") == 0) {
va_copy(logArgs, myArgs);
vsprintf(formattedString, outputString, logArgs);
LJM_Log(LJM_DEBUG, formattedString);
}
vprintf(outputString, myArgs);
va_end(myArgs);
}
#endif
#endif // #define LJM_STREAM_UTILITIES