Line data Source code
1 : /********************************************************************\
2 :
3 : Name: multi.c
4 : Created by: Stefan Ritt
5 :
6 : Contents: Multimeter Class Driver
7 :
8 : $Id$
9 :
10 : \********************************************************************/
11 :
12 : #include <stdio.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 : #include <assert.h>
16 : #include "midas.h"
17 : #include "tinyexpr.h"
18 : #include "mstrlcpy.h"
19 :
20 : #define FORMULA_SIZE 64
21 :
22 : typedef struct {
23 : /* ODB keys */
24 : HNDLE hDB, hKeyRoot;
25 : HNDLE hKeyOutput, hKeyInput;
26 :
27 : /* globals */
28 : INT num_channels_input, num_channels_output;
29 : INT format;
30 : INT last_channel;
31 : DWORD last_update_input;
32 : DWORD last_update_output;
33 :
34 : /* items in /Variables record */
35 : char *names_input, *names_output;
36 : float *var_input;
37 : float *var_output;
38 :
39 : /* items in /Settings */
40 : float *update_threshold;
41 : float *factor_input, *factor_output;
42 : float *offset_input, *offset_output;
43 :
44 : char *formula_input;
45 : te_expr **expr_input;
46 : double *expr_x;
47 :
48 : /* mirror arrays */
49 : float *input_mirror;
50 : float *output_mirror;
51 :
52 : DEVICE_DRIVER **driver_input, **driver_output;
53 : INT *channel_offset_input, *channel_offset_output;
54 :
55 : } MULTI_INFO;
56 :
57 : #ifndef abs
58 : #define abs(a) (((a) < 0) ? -(a) : (a))
59 : #endif
60 :
61 : /*----------------------------------------------------------------------------*/
62 :
63 0 : static void free_mem(MULTI_INFO *m_info) {
64 0 : free(m_info->names_input);
65 0 : free(m_info->names_output);
66 :
67 0 : free(m_info->var_input);
68 0 : free(m_info->var_output);
69 :
70 0 : free(m_info->update_threshold);
71 0 : free(m_info->offset_input);
72 0 : free(m_info->factor_input);
73 :
74 0 : free(m_info->formula_input);
75 0 : free(m_info->expr_input);
76 0 : free(m_info->expr_x);
77 :
78 0 : free(m_info->offset_output);
79 0 : free(m_info->factor_output);
80 :
81 0 : free(m_info->input_mirror);
82 0 : free(m_info->output_mirror);
83 :
84 0 : free(m_info->channel_offset_input);
85 0 : free(m_info->channel_offset_output);
86 :
87 0 : free(m_info->driver_input);
88 0 : free(m_info->driver_output);
89 :
90 0 : free(m_info);
91 0 : }
92 :
93 : /*----------------------------------------------------------------------------*/
94 :
95 0 : void multi_read(EQUIPMENT *pequipment, int channel) {
96 : int i, status;
97 : MULTI_INFO *m_info;
98 : HNDLE hDB;
99 :
100 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
101 0 : cm_get_experiment_database(&hDB, NULL);
102 :
103 0 : if (channel == -1)
104 0 : for (i = 0; i < m_info->num_channels_input; i++) {
105 0 : if (m_info->driver_input[i]->flags & DF_MULTITHREAD)
106 0 : status = device_driver(m_info->driver_input[i], CMD_GET_DIRECT,
107 0 : i - m_info->channel_offset_input[i],
108 0 : &m_info->var_input[i]);
109 : else
110 0 : status = device_driver(m_info->driver_input[i], CMD_GET,
111 0 : i - m_info->channel_offset_input[i],
112 0 : &m_info->var_input[i]);
113 0 : if (status != FE_SUCCESS)
114 0 : m_info->var_input[i] = (float) ss_nan();
115 : else
116 0 : if (m_info->formula_input[i*FORMULA_SIZE] != 0) {
117 0 : if (m_info->expr_input[i] == NULL) {
118 : int error;
119 0 : te_variable vars[] = {{"x", &m_info->expr_x[i]}};
120 0 : m_info->expr_input[i] = te_compile(&m_info->formula_input[i * FORMULA_SIZE], vars, 1, &error);
121 : }
122 0 : m_info->expr_x[i] = (double) m_info->var_input[i];
123 0 : m_info->var_input[i] = (float) te_eval(m_info->expr_input[i]);
124 : } else
125 0 : m_info->var_input[i] = m_info->var_input[i] * m_info->factor_input[i] -
126 0 : m_info->offset_input[i];
127 : }
128 : else {
129 0 : status = device_driver(m_info->driver_input[channel], CMD_GET,
130 0 : channel - m_info->channel_offset_input[channel],
131 0 : &m_info->var_input[channel]);
132 0 : if (status != FE_SUCCESS)
133 0 : m_info->var_input[channel] = (float) ss_nan();
134 : else {
135 0 : if (m_info->formula_input[channel * FORMULA_SIZE] != 0) { // evaluate formula
136 0 : if (m_info->expr_input[channel] == NULL) {
137 : int error;
138 0 : te_variable vars[] = {{"x", &m_info->expr_x[channel]}};
139 0 : m_info->expr_input[channel] = te_compile(&m_info->formula_input[channel * FORMULA_SIZE], vars, 1, &error);
140 : }
141 0 : m_info->expr_x[channel] = (double) m_info->var_input[channel];
142 0 : m_info->var_input[channel] = (float) te_eval(m_info->expr_input[channel]);
143 : } else // evaluate factor & offset
144 0 : m_info->var_input[channel] =
145 0 : m_info->var_input[channel] * m_info->factor_input[channel] -
146 0 : m_info->offset_input[channel];
147 :
148 0 : if (status == FE_NOT_YET_READ)
149 0 : return;
150 : }
151 : }
152 :
153 : /* check if significant change since last ODB update */
154 0 : for (i = 0; i < m_info->num_channels_input; i++)
155 0 : if ((!ss_isnan(m_info->var_input[i]) && !ss_isnan(m_info->input_mirror[i]) &&
156 0 : abs(m_info->var_input[i] - m_info->input_mirror[i]) >
157 0 : m_info->update_threshold[i]) ||
158 0 : (ss_isnan(m_info->var_input[i]) && !ss_isnan(m_info->input_mirror[i])) ||
159 0 : (!ss_isnan(m_info->var_input[i]) && ss_isnan(m_info->input_mirror[i])))
160 0 : break;
161 :
162 : #ifdef DEBUG_THRESHOLDS
163 : if (i < m_info->num_channels_input) {
164 : printf("%d: %lf -> %lf, threshold %lf\n", i,
165 : m_info->var_input[i], m_info->input_mirror[i], m_info->update_threshold[i]);
166 : }
167 : #endif
168 :
169 : /* update if change is more than update_sensitivity or last update more
170 : than a minute ago */
171 0 : if (i < m_info->num_channels_input || ss_time() - m_info->last_update_input > 60) {
172 :
173 0 : m_info->last_update_input = ss_time();
174 :
175 0 : for (i = 0; i < m_info->num_channels_input; i++)
176 0 : m_info->input_mirror[i] = m_info->var_input[i];
177 :
178 0 : db_set_data(hDB, m_info->hKeyInput, m_info->var_input,
179 0 : m_info->num_channels_input * sizeof(float), m_info->num_channels_input,
180 : TID_FLOAT);
181 :
182 0 : pequipment->odb_out++;
183 : }
184 : }
185 :
186 : /*----------------------------------------------------------------------------*/
187 :
188 0 : void multi_read_output(EQUIPMENT *pequipment, int channel) {
189 : int i;
190 : float value;
191 : MULTI_INFO *m_info;
192 : HNDLE hDB;
193 :
194 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
195 0 : cm_get_experiment_database(&hDB, NULL);
196 :
197 0 : if (channel == -1) {
198 0 : for (i = 0; i < m_info->num_channels_output; i++) {
199 0 : if (m_info->driver_output[i]->flags & DF_MULTITHREAD)
200 0 : device_driver(m_info->driver_output[i], CMD_GET_DIRECT,
201 0 : i - m_info->channel_offset_output[i],
202 : &value);
203 : else
204 0 : device_driver(m_info->driver_output[i], CMD_GET,
205 0 : i - m_info->channel_offset_input[i],
206 : &value);
207 :
208 0 : value = (value + m_info->offset_output[i]) / m_info->factor_output[i];
209 :
210 0 : m_info->last_update_output = ss_time();
211 0 : m_info->output_mirror[i] = value;
212 0 : m_info->var_output[i] = value;
213 :
214 0 : db_set_record(hDB, m_info->hKeyOutput, m_info->output_mirror,
215 0 : m_info->num_channels_output * sizeof(float), 0);
216 :
217 : }
218 0 : pequipment->odb_out++;
219 :
220 : } else {
221 :
222 0 : device_driver(m_info->driver_output[channel], CMD_GET,
223 0 : channel - m_info->channel_offset_output[channel], &value);
224 :
225 0 : value = (value + m_info->offset_output[channel]) / m_info->factor_output[channel];
226 :
227 0 : if (!ss_isnan(value) &&
228 0 : (value != m_info->output_mirror[channel] || // write if changed
229 0 : ss_time() > m_info->last_update_output + 60)) { // write at least once per minute
230 :
231 0 : m_info->last_update_output = ss_time();
232 0 : m_info->output_mirror[channel] = value;
233 0 : m_info->var_output[channel] = value;
234 :
235 0 : db_set_record(hDB, m_info->hKeyOutput, m_info->output_mirror,
236 0 : m_info->num_channels_output * sizeof(float), 0);
237 :
238 0 : pequipment->odb_out++;
239 : }
240 : }
241 :
242 0 : }
243 :
244 : /*----------------------------------------------------------------------------*/
245 :
246 0 : void multi_output(INT, INT, void *info) {
247 : INT i;
248 : MULTI_INFO *m_info;
249 : EQUIPMENT *pequipment;
250 :
251 0 : pequipment = (EQUIPMENT *) info;
252 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
253 :
254 0 : for (i = 0; i < m_info->num_channels_output; i++) {
255 : /* only set channel if demand value differs */
256 0 : if (m_info->var_output[i] != m_info->output_mirror[i]) {
257 0 : m_info->output_mirror[i] =
258 0 : m_info->var_output[i] * m_info->factor_output[i] - m_info->offset_output[i];
259 :
260 0 : device_driver(m_info->driver_output[i], CMD_SET,
261 0 : i - m_info->channel_offset_output[i],
262 0 : m_info->output_mirror[i]);
263 : }
264 : }
265 :
266 0 : pequipment->odb_in++;
267 0 : }
268 :
269 : /*------------------------------------------------------------------*/
270 :
271 0 : void multi_update_label(INT, INT, void *info) {
272 : INT i;
273 : MULTI_INFO *m_info;
274 : EQUIPMENT *pequipment;
275 :
276 0 : pequipment = (EQUIPMENT *) info;
277 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
278 :
279 : /* update channel labels based on the midas channel names */
280 0 : for (i = 0; i < m_info->num_channels_input; i++)
281 0 : device_driver(m_info->driver_input[i], CMD_SET_LABEL,
282 0 : i - m_info->channel_offset_input[i],
283 0 : m_info->names_input + NAME_LENGTH * i);
284 :
285 0 : for (i = 0; i < m_info->num_channels_output; i++)
286 0 : device_driver(m_info->driver_output[i], CMD_SET_LABEL,
287 0 : i - m_info->channel_offset_output[i],
288 0 : m_info->names_output + NAME_LENGTH * i);
289 0 : }
290 :
291 : /*----------------------------------------------------------------------------*/
292 :
293 0 : void formula_invalidate(INT hDB, INT hKey, void *info) {
294 0 : MULTI_INFO *m_info = (MULTI_INFO *) info;
295 :
296 0 : for (int i = 0; i < m_info->num_channels_input; i++) {
297 0 : te_free(m_info->expr_input[i]);
298 0 : m_info->expr_input[i] = NULL;
299 : }
300 0 : }
301 :
302 0 : INT multi_init(EQUIPMENT *pequipment) {
303 : int status, size, i, j, index, ch_offset;
304 : char str[256];
305 : HNDLE hDB, hKey, hNamesIn, hNamesOut;
306 : MULTI_INFO *m_info;
307 : BOOL partially_disabled;
308 :
309 : /* allocate private data */
310 0 : pequipment->cd_info = calloc(1, sizeof(MULTI_INFO));
311 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
312 :
313 : /* get class driver root key */
314 0 : cm_get_experiment_database(&hDB, NULL);
315 0 : sprintf(str, "/Equipment/%s", pequipment->name);
316 0 : db_create_key(hDB, 0, str, TID_KEY);
317 0 : db_find_key(hDB, 0, str, &m_info->hKeyRoot);
318 :
319 : /* save event format */
320 0 : size = sizeof(str);
321 0 : db_get_value(hDB, m_info->hKeyRoot, "Common/Format", str, &size, TID_STRING, TRUE);
322 :
323 0 : if (equal_ustring(str, "Fixed"))
324 0 : m_info->format = FORMAT_FIXED;
325 0 : else if (equal_ustring(str, "MIDAS"))
326 0 : m_info->format = FORMAT_MIDAS;
327 : else {
328 0 : m_info->format = 0;
329 0 : cm_msg(MERROR, "multi_init", "Unknown Common/Format \"%s\", should be FIXED or MIDAS", str);
330 0 : return FE_ERR_ODB;
331 : }
332 :
333 : /* count total number of channels */
334 0 : for (i = m_info->num_channels_input = m_info->num_channels_output = 0;
335 0 : pequipment->driver[i].name[0]; i++) {
336 0 : if (pequipment->driver[i].flags & DF_INPUT)
337 0 : m_info->num_channels_input += pequipment->driver[i].channels;
338 0 : if (pequipment->driver[i].flags & DF_OUTPUT)
339 0 : m_info->num_channels_output += pequipment->driver[i].channels;
340 : }
341 :
342 0 : if (m_info->num_channels_input == 0 && m_info->num_channels_output == 0) {
343 0 : cm_msg(MERROR, "multi_init", "No channels found in device driver list");
344 0 : return FE_ERR_ODB;
345 : }
346 :
347 : /* Allocate memory for buffers */
348 0 : if (m_info->num_channels_input) {
349 0 : m_info->names_input = (char *) calloc(m_info->num_channels_input, NAME_LENGTH);
350 0 : m_info->var_input = (float *) calloc(m_info->num_channels_input, sizeof(float));
351 0 : m_info->update_threshold = (float *) calloc(m_info->num_channels_input, sizeof(float));
352 0 : m_info->offset_input = (float *) calloc(m_info->num_channels_input, sizeof(float));
353 0 : m_info->factor_input = (float *) calloc(m_info->num_channels_input, sizeof(float));
354 0 : m_info->formula_input = (char *) calloc(m_info->num_channels_input, FORMULA_SIZE);
355 0 : m_info->expr_input = (te_expr **) calloc(m_info->num_channels_input, sizeof(void *));
356 0 : m_info->expr_x = (double *) calloc(m_info->num_channels_input, sizeof(double));
357 0 : m_info->input_mirror = (float *) calloc(m_info->num_channels_input, sizeof(float));
358 0 : m_info->channel_offset_input = (INT *) calloc(m_info->num_channels_input, sizeof(INT));
359 0 : m_info->driver_input = (DEVICE_DRIVER **) calloc(m_info->num_channels_input, sizeof(void *));
360 : }
361 :
362 0 : if (m_info->num_channels_output) {
363 0 : m_info->names_output = (char *) calloc(m_info->num_channels_output, NAME_LENGTH);
364 0 : m_info->var_output = (float *) calloc(m_info->num_channels_output, sizeof(float));
365 0 : m_info->offset_output = (float *) calloc(m_info->num_channels_output, sizeof(float));
366 0 : m_info->factor_output = (float *) calloc(m_info->num_channels_output, sizeof(float));
367 0 : m_info->output_mirror = (float *) calloc(m_info->num_channels_output, sizeof(float));
368 0 : m_info->channel_offset_output = (INT *) calloc(m_info->num_channels_output, sizeof(DWORD));
369 0 : m_info->driver_output = (DEVICE_DRIVER **) calloc(m_info->num_channels_output, sizeof(void *));
370 : }
371 :
372 : /*---- Create/Read settings ----*/
373 :
374 0 : if (m_info->num_channels_input) {
375 : /* Update threshold */
376 0 : for (i = 0; i < m_info->num_channels_input; i++)
377 0 : m_info->update_threshold[i] = 0.1f; /* default 0.1 */
378 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Update Threshold",
379 0 : m_info->update_threshold, m_info->num_channels_input * sizeof(float),
380 : m_info->num_channels_input, TID_FLOAT);
381 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Update Threshold", &hKey);
382 0 : db_open_record(hDB, hKey, m_info->update_threshold,
383 0 : m_info->num_channels_input * sizeof(float), MODE_READ, NULL, NULL);
384 :
385 : /* Offset */
386 0 : for (i = 0; i < m_info->num_channels_input; i++)
387 0 : m_info->offset_input[i] = 0.f; /* default 0 */
388 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Input Offset",
389 0 : m_info->offset_input, m_info->num_channels_input * sizeof(float),
390 : m_info->num_channels_input, TID_FLOAT);
391 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Input Offset", &hKey);
392 0 : db_open_record(hDB, hKey, m_info->offset_input,
393 0 : m_info->num_channels_input * sizeof(float), MODE_READ, NULL, NULL);
394 :
395 : /* Unit */
396 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Unit Input", &hKey);
397 0 : if (status == DB_NO_KEY) {
398 0 : int n = m_info->num_channels_input;
399 0 : char *unit = (char *)calloc(n, 32);
400 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Unit Input", TID_STRING);
401 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Unit Input", &hKey);
402 0 : db_set_data(hDB, hKey, unit, n*32, n, TID_STRING);
403 0 : free(unit);
404 : }
405 :
406 : /* Format */
407 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Format Input", &hKey);
408 0 : if (status == DB_NO_KEY) {
409 0 : int n = m_info->num_channels_input;
410 0 : char *unit = (char *)calloc(n, 32);
411 0 : for (int i=0 ; i<n ; i++)
412 0 : mstrlcpy(unit + i*32, "%f2", 32);
413 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Format Input", TID_STRING);
414 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Format Input", &hKey);
415 0 : db_set_data(hDB, hKey, unit, n*32, n, TID_STRING);
416 0 : free(unit);
417 : }
418 : }
419 :
420 0 : for (i = 0; i < m_info->num_channels_output; i++)
421 0 : m_info->offset_output[i] = 0.f;
422 :
423 0 : if (m_info->num_channels_output) {
424 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Output Offset",
425 0 : m_info->offset_output, m_info->num_channels_output * sizeof(float),
426 : m_info->num_channels_output, TID_FLOAT);
427 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Output Offset", &hKey);
428 0 : db_open_record(hDB, hKey, m_info->offset_output,
429 0 : m_info->num_channels_output * sizeof(float), MODE_READ, NULL, NULL);
430 :
431 : /* Unit */
432 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Unit Output", &hKey);
433 0 : if (status == DB_NO_KEY) {
434 0 : int n = m_info->num_channels_input;
435 0 : char *unit = (char *)calloc(n, 32);
436 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Unit Output", TID_STRING);
437 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Unit Output", &hKey);
438 0 : db_set_data(hDB, hKey, unit, n*32, n, TID_STRING);
439 0 : free(unit);
440 : }
441 :
442 : /* Format */
443 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Format Output", &hKey);
444 0 : if (status == DB_NO_KEY) {
445 0 : int n = m_info->num_channels_input;
446 0 : char *format = (char *)calloc(n, 32);
447 0 : for (int ii=0 ; ii<n ; ii++)
448 0 : mstrlcpy(format + ii*32, "%f2", 32);
449 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Format Output", TID_STRING);
450 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Format Output", &hKey);
451 0 : db_set_data(hDB, hKey, format, n*32, n, TID_STRING);
452 0 : free(format);
453 : }
454 : }
455 :
456 : /* Factor */
457 0 : for (i = 0; i < m_info->num_channels_input; i++)
458 0 : m_info->factor_input[i] = 1.f; /* default 1 */
459 :
460 : /* Formula */
461 0 : for (i = 0; i < m_info->num_channels_input; i++)
462 0 : m_info->formula_input[i*FORMULA_SIZE] = 0;
463 :
464 0 : if (m_info->num_channels_input) {
465 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Input Factor",
466 0 : m_info->factor_input, m_info->num_channels_input * sizeof(float),
467 : m_info->num_channels_input, TID_FLOAT);
468 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Input Factor", &hKey);
469 0 : db_open_record(hDB, hKey, m_info->factor_input,
470 0 : m_info->num_channels_input * sizeof(float), MODE_READ, NULL, NULL);
471 :
472 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Input Formula",
473 0 : m_info->formula_input, m_info->num_channels_input * FORMULA_SIZE,
474 : m_info->num_channels_input, TID_STRING);
475 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Input Formula", &hKey);
476 0 : db_open_record(hDB, hKey, m_info->formula_input,
477 0 : m_info->num_channels_input * FORMULA_SIZE, MODE_READ, formula_invalidate, m_info);
478 :
479 : }
480 :
481 0 : if (m_info->num_channels_output) {
482 0 : for (i = 0; i < m_info->num_channels_output; i++)
483 0 : m_info->factor_output[i] = 1.f;
484 0 : db_merge_data(hDB, m_info->hKeyRoot, "Settings/Output Factor",
485 0 : m_info->factor_output, m_info->num_channels_output * sizeof(float),
486 : m_info->num_channels_output, TID_FLOAT);
487 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Output Factor", &hKey);
488 0 : db_open_record(hDB, hKey, m_info->factor_output,
489 0 : m_info->num_channels_output * sizeof(float), MODE_READ, NULL, NULL);
490 : }
491 :
492 : /*---- Create/Read variables ----*/
493 :
494 : /* Input */
495 0 : if (m_info->num_channels_input) {
496 0 : db_merge_data(hDB, m_info->hKeyRoot, "Variables/Input",
497 0 : m_info->var_input, m_info->num_channels_input * sizeof(float),
498 : m_info->num_channels_input, TID_FLOAT);
499 0 : db_find_key(hDB, m_info->hKeyRoot, "Variables/Input", &m_info->hKeyInput);
500 0 : memcpy(m_info->input_mirror, m_info->var_input,
501 0 : m_info->num_channels_input * sizeof(float));
502 : }
503 :
504 : /* Output */
505 0 : if (m_info->num_channels_output) {
506 0 : db_merge_data(hDB, m_info->hKeyRoot, "Variables/Output",
507 0 : m_info->var_output, m_info->num_channels_output * sizeof(float),
508 : m_info->num_channels_output, TID_FLOAT);
509 0 : db_find_key(hDB, m_info->hKeyRoot, "Variables/Output", &m_info->hKeyOutput);
510 : }
511 :
512 : /*---- Initialize device drivers ----*/
513 :
514 : /* call init method */
515 0 : partially_disabled = FALSE;
516 0 : for (i = 0; pequipment->driver[i].name[0]; i++) {
517 0 : sprintf(str, "Settings/Devices/%s", pequipment->driver[i].name);
518 0 : status = db_find_key(hDB, m_info->hKeyRoot, str, &hKey);
519 0 : if (status != DB_SUCCESS) {
520 0 : db_create_key(hDB, m_info->hKeyRoot, str, TID_KEY);
521 0 : status = db_find_key(hDB, m_info->hKeyRoot, str, &hKey);
522 0 : if (status != DB_SUCCESS) {
523 0 : cm_msg(MERROR, "multi_init", "Cannot create %s entry in online database",
524 : str);
525 0 : free_mem(m_info);
526 0 : return FE_ERR_ODB;
527 : }
528 : }
529 :
530 : /* check enabled flag */
531 0 : size = sizeof(pequipment->driver[i].enabled);
532 0 : pequipment->driver[i].enabled = 1;
533 0 : sprintf(str, "Settings/Devices/%s/Enabled", pequipment->driver[i].name);
534 0 : status = db_get_value(hDB, m_info->hKeyRoot, str, &pequipment->driver[i].enabled, &size, TID_BOOL, TRUE);
535 0 : if (status != DB_SUCCESS)
536 0 : return FE_ERR_ODB;
537 :
538 0 : if (pequipment->driver[i].enabled && pequipment->driver[i].channels > 0) {
539 0 : printf("Connecting %s:%s...", pequipment->name, pequipment->driver[i].name);
540 0 : fflush(stdout);
541 0 : status = device_driver(&pequipment->driver[i], CMD_INIT, hKey);
542 0 : if (status != FE_SUCCESS) {
543 0 : free_mem(m_info);
544 0 : return status;
545 : }
546 0 : printf("OK\n");
547 : } else
548 0 : partially_disabled = TRUE;
549 : }
550 :
551 : /* compose device driver channel assignment */
552 0 : for (i = 0, j = 0, index = 0, ch_offset = 0; i < m_info->num_channels_input; i++, j++) {
553 0 : while (pequipment->driver[index].name[0] &&
554 0 : (j >= pequipment->driver[index].channels ||
555 0 : (pequipment->driver[index].flags & DF_INPUT) == 0)) {
556 0 : ch_offset += j;
557 0 : index++;
558 0 : j = 0;
559 : }
560 :
561 0 : m_info->driver_input[i] = &pequipment->driver[index];
562 0 : m_info->channel_offset_input[i] = ch_offset;
563 : }
564 :
565 0 : for (i = 0, j = 0, index = 0, ch_offset = 0; i < m_info->num_channels_output; i++, j++) {
566 0 : while (pequipment->driver[index].name[0] &&
567 0 : (j >= pequipment->driver[index].channels ||
568 0 : (pequipment->driver[index].flags & DF_OUTPUT) == 0)) {
569 0 : ch_offset += j;
570 0 : index++;
571 0 : j = 0;
572 : }
573 :
574 0 : m_info->driver_output[i] = &pequipment->driver[index];
575 0 : m_info->channel_offset_output[i] = ch_offset;
576 : }
577 :
578 : /*---- get default names from device driver ----*/
579 0 : if (m_info->num_channels_input) {
580 0 : for (i = 0; i < m_info->num_channels_input; i++) {
581 0 : sprintf(m_info->names_input + NAME_LENGTH * i, "Input Channel %d", i);
582 0 : device_driver(m_info->driver_input[i], CMD_GET_LABEL,
583 0 : i - m_info->channel_offset_input[i],
584 0 : m_info->names_input + NAME_LENGTH * i);
585 :
586 : /* merge existing names with labels from driver */
587 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Input", &hKey);
588 0 : if (status != DB_SUCCESS) {
589 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Names Input", TID_STRING);
590 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Input", &hKey);
591 0 : db_set_data(hDB, hKey, m_info->names_input, NAME_LENGTH, 1, TID_STRING);
592 : } else {
593 0 : size = sizeof(str);
594 0 : db_get_data_index(hDB, hKey, str, &size, i, TID_STRING);
595 0 : if (!str[0])
596 0 : db_set_data_index(hDB, hKey, m_info->names_input + NAME_LENGTH * i, NAME_LENGTH, i, TID_STRING);
597 : }
598 : }
599 : }
600 :
601 0 : if (m_info->num_channels_output) {
602 0 : for (i = 0; i < m_info->num_channels_output; i++) {
603 0 : sprintf(m_info->names_output + NAME_LENGTH * i, "Output Channel %d", i);
604 0 : device_driver(m_info->driver_output[i], CMD_GET_LABEL,
605 0 : i - m_info->channel_offset_output[i],
606 0 : m_info->names_output + NAME_LENGTH * i);
607 :
608 : /* merge existing names with labels from driver */
609 0 : status = db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Output", &hKey);
610 0 : if (status != DB_SUCCESS) {
611 0 : db_create_key(hDB, m_info->hKeyRoot, "Settings/Names Output", TID_STRING);
612 0 : db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Output", &hKey);
613 0 : db_set_data(hDB, hKey, m_info->names_output, NAME_LENGTH, 1, TID_STRING);
614 : } else {
615 0 : size = sizeof(str);
616 0 : db_get_data_index(hDB, hKey, str, &size, i, TID_STRING);
617 0 : if (!str[0])
618 0 : db_set_data_index(hDB, hKey, m_info->names_output + NAME_LENGTH * i, NAME_LENGTH, i, TID_STRING);
619 : }
620 :
621 : }
622 : }
623 :
624 : /*---- set labels from midas SC names ----*/
625 0 : if (m_info->num_channels_input) {
626 0 : for (i = 0; i < m_info->num_channels_input; i++) {
627 0 : device_driver(m_info->driver_input[i], CMD_SET_LABEL,
628 0 : i - m_info->channel_offset_input[i],
629 0 : m_info->names_input + NAME_LENGTH * i);
630 : }
631 :
632 : /* open hotlink on input channel names */
633 0 : if (db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Input", &hNamesIn) ==
634 : DB_SUCCESS)
635 0 : db_open_record(hDB, hNamesIn, m_info->names_input,
636 0 : NAME_LENGTH * m_info->num_channels_input, MODE_READ,
637 : multi_update_label, pequipment);
638 : }
639 :
640 0 : for (i = 0; i < m_info->num_channels_output; i++) {
641 0 : device_driver(m_info->driver_output[i], CMD_SET_LABEL,
642 0 : i - m_info->channel_offset_output[i],
643 0 : m_info->names_output + NAME_LENGTH * i);
644 : }
645 :
646 : /* open hotlink on output channel names */
647 0 : if (m_info->num_channels_output) {
648 0 : if (db_find_key(hDB, m_info->hKeyRoot, "Settings/Names Output", &hNamesOut) ==
649 : DB_SUCCESS)
650 0 : db_open_record(hDB, hNamesOut, m_info->names_output,
651 0 : NAME_LENGTH * m_info->num_channels_output, MODE_READ,
652 : multi_update_label, pequipment);
653 :
654 : /* open hot link to output record */
655 0 : db_open_record(hDB, m_info->hKeyOutput, m_info->var_output,
656 0 : m_info->num_channels_output * (int) sizeof(float),
657 : MODE_READ, multi_output, pequipment);
658 : }
659 :
660 : /* set initial demand values */
661 0 : for (i = 0; i < m_info->num_channels_output; i++) {
662 0 : if (m_info->driver_output[i]->flags & DF_PRIO_DEVICE) {
663 : /* read default value directly from device bypassing multi-thread buffer */
664 0 : device_driver(m_info->driver_output[i], CMD_GET_DEMAND_DIRECT,
665 0 : i - m_info->channel_offset_output[i],
666 0 : &m_info->output_mirror[i]);
667 : } else {
668 : /* use default value from ODB */
669 0 : m_info->output_mirror[i] = m_info->var_output[i] * m_info->factor_output[i] -
670 0 : m_info->offset_output[i];
671 :
672 0 : device_driver(m_info->driver_output[i], CMD_SET,
673 0 : i - m_info->channel_offset_output[i],
674 0 : m_info->output_mirror[i]);
675 : }
676 : }
677 :
678 0 : if (m_info->num_channels_output)
679 0 : db_set_record(hDB, m_info->hKeyOutput, m_info->output_mirror,
680 0 : m_info->num_channels_output * (int) sizeof(float), 0);
681 :
682 : /* initially read all input channels */
683 0 : if (m_info->num_channels_input && (m_info->driver_input[0]->flags & DF_QUICKSTART) == 0)
684 0 : multi_read(pequipment, -1);
685 :
686 0 : if (partially_disabled)
687 0 : return FE_PARTIALLY_DISABLED;
688 :
689 0 : return FE_SUCCESS;
690 : }
691 :
692 : /*----------------------------------------------------------------------------*/
693 :
694 0 : INT multi_exit(EQUIPMENT *pequipment) {
695 : INT i;
696 :
697 0 : free_mem((MULTI_INFO *) pequipment->cd_info);
698 :
699 : /* call exit method of device drivers */
700 0 : for (i = 0; pequipment->driver[i].dd != NULL; i++)
701 0 : device_driver(&pequipment->driver[i], CMD_EXIT);
702 :
703 0 : return FE_SUCCESS;
704 : }
705 :
706 : /*----------------------------------------------------------------------------*/
707 :
708 0 : INT multi_start(EQUIPMENT *pequipment) {
709 : INT i;
710 :
711 : /* call start method of device drivers */
712 0 : for (i = 0; pequipment->driver[i].dd != NULL; i++)
713 0 : if (pequipment->driver[i].flags & DF_MULTITHREAD) {
714 0 : pequipment->driver[i].pequipment = &pequipment->info;
715 0 : device_driver(&pequipment->driver[i], CMD_START);
716 : }
717 :
718 0 : return FE_SUCCESS;
719 : }
720 :
721 : /*----------------------------------------------------------------------------*/
722 :
723 0 : INT multi_stop(EQUIPMENT *pequipment) {
724 : INT i;
725 :
726 : /* call close method of device drivers */
727 0 : for (i = 0; pequipment->driver[i].dd != NULL && pequipment->driver[i].flags & DF_MULTITHREAD; i++)
728 0 : device_driver(&pequipment->driver[i], CMD_STOP);
729 :
730 0 : return FE_SUCCESS;
731 : }
732 :
733 : /*----------------------------------------------------------------------------*/
734 :
735 0 : INT multi_idle(EQUIPMENT *pequipment) {
736 : int i;
737 : MULTI_INFO *m_info;
738 :
739 0 : m_info = (MULTI_INFO *) pequipment->cd_info;
740 :
741 : /* read input channels */
742 0 : for (i = 0; i < m_info->num_channels_input; i++)
743 0 : multi_read(pequipment, i);
744 :
745 : /* read output channels */
746 0 : for (i = 0; i < m_info->num_channels_output; i++)
747 0 : if (m_info->driver_output[i]->flags & DF_PRIO_DEVICE)
748 0 : multi_read_output(pequipment, i);
749 :
750 0 : return FE_SUCCESS;
751 : }
752 :
753 : /*----------------------------------------------------------------------------*/
754 :
755 0 : INT cd_multi_read(char *pevent, int) {
756 : float *pdata;
757 :
758 0 : EQUIPMENT* pequipment = *((EQUIPMENT **) pevent);
759 0 : MULTI_INFO* m_info = (MULTI_INFO *) pequipment->cd_info;
760 :
761 0 : if (m_info->format == FORMAT_FIXED) {
762 0 : memcpy(pevent, m_info->var_input, sizeof(float) * m_info->num_channels_input);
763 0 : pevent += sizeof(float) * m_info->num_channels_input;
764 :
765 0 : memcpy(pevent, m_info->var_output, sizeof(float) * m_info->num_channels_output);
766 0 : pevent += sizeof(float) * m_info->num_channels_output;
767 :
768 0 : return sizeof(float) * (m_info->num_channels_input + m_info->num_channels_output);
769 0 : } else if (m_info->format == FORMAT_MIDAS) {
770 0 : bk_init32(pevent);
771 :
772 : /* create INPT bank */
773 0 : if (m_info->num_channels_input) {
774 0 : bk_create(pevent, "INPT", TID_FLOAT, (void **) &pdata);
775 0 : memcpy(pdata, m_info->var_input, sizeof(float) * m_info->num_channels_input);
776 0 : pdata += m_info->num_channels_input;
777 0 : bk_close(pevent, pdata);
778 : }
779 :
780 : /* create OUTP bank */
781 0 : if (m_info->num_channels_output) {
782 0 : bk_create(pevent, "OUTP", TID_FLOAT, (void **) &pdata);
783 0 : memcpy(pdata, m_info->var_output, sizeof(float) * m_info->num_channels_output);
784 0 : pdata += m_info->num_channels_output;
785 0 : bk_close(pevent, pdata);
786 : }
787 :
788 0 : return bk_size(pevent);
789 : } else {
790 0 : assert(!"unsupported m_info->format, sorry!");
791 : }
792 :
793 : return 0;
794 : }
795 :
796 : /*----------------------------------------------------------------------------*/
797 :
798 0 : INT cd_multi(INT cmd, EQUIPMENT *pequipment) {
799 : INT status;
800 :
801 0 : switch (cmd) {
802 0 : case CMD_INIT:
803 0 : status = multi_init(pequipment);
804 0 : break;
805 :
806 0 : case CMD_EXIT:
807 0 : status = multi_exit(pequipment);
808 0 : break;
809 :
810 0 : case CMD_START:
811 0 : status = multi_start(pequipment);
812 0 : break;
813 :
814 0 : case CMD_STOP:
815 0 : status = multi_stop(pequipment);
816 0 : break;
817 :
818 0 : case CMD_IDLE:
819 0 : status = multi_idle(pequipment);
820 0 : break;
821 :
822 0 : default:
823 0 : cm_msg(MERROR, "Multimeter class driver", "Received unknown command %d", cmd);
824 0 : status = FE_ERR_DRIVER;
825 0 : break;
826 : }
827 :
828 0 : return status;
829 : }
|