Line data Source code
1 : /********************************************************************\
2 :
3 : Name: slowdev.c
4 : Created by: Pierre-Andre Amaudruz
5 :
6 : Contents: Slow Device Generic Class Driver
7 : Based on the generic class driver, implements a check channel
8 : in the idle task based on circular/alternate on minimum of
9 : n raised channels + one. See doc for further explanation.
10 :
11 : $Id$
12 :
13 : \********************************************************************/
14 :
15 : #include <stdio.h>
16 : #include <assert.h>
17 : #include <string.h> // memcpy()
18 : #include "midas.h"
19 :
20 : #define ODB_UPDATE_TIME 5000
21 :
22 : typedef struct {
23 :
24 : /* ODB keys */
25 : HNDLE hKeyRoot, hDemand, hMeasured;
26 :
27 : /* globals */
28 : INT num_channels;
29 : INT format;
30 : DWORD last_update;
31 : INT last_channel;
32 :
33 : /* items in /Variables record */
34 : float *demand;
35 : float *measured;
36 : BOOL *raised;
37 :
38 : /* items in /Settings */
39 : char *names;
40 : float *update_threshold;
41 :
42 : /* mirror arrays */
43 : float *demand_mirror;
44 : float *measured_mirror;
45 : DWORD *last_change;
46 :
47 : DEVICE_DRIVER **driver;
48 : INT *channel_offset;
49 :
50 : } GEN_INFO;
51 :
52 : #ifndef abs
53 : #define abs(a) (((a) < 0) ? -(a) : (a))
54 : #endif
55 :
56 : /*------------------------------------------------------------------*/
57 :
58 0 : static void free_mem(GEN_INFO * gen_info)
59 : {
60 0 : free(gen_info->names);
61 0 : free(gen_info->demand);
62 0 : free(gen_info->measured);
63 0 : free(gen_info->raised);
64 :
65 0 : free(gen_info->update_threshold);
66 :
67 0 : free(gen_info->demand_mirror);
68 0 : free(gen_info->measured_mirror);
69 0 : free(gen_info->last_change);
70 :
71 0 : free(gen_info->channel_offset);
72 0 : free(gen_info->driver);
73 :
74 0 : free(gen_info);
75 0 : }
76 :
77 : /*------------------------------------------------------------------*/
78 :
79 0 : INT gen_read(EQUIPMENT * pequipment, int channel)
80 : {
81 : int status;
82 : GEN_INFO *gen_info;
83 : HNDLE hDB;
84 :
85 : /*---- read measured value ----*/
86 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
87 0 : cm_get_experiment_database(&hDB, NULL);
88 :
89 : /* Get channel value */
90 0 : status = device_driver(gen_info->driver[channel], CMD_GET,
91 0 : channel - gen_info->channel_offset[channel],
92 0 : &gen_info->measured[channel]);
93 :
94 : /*---- read demand value ----*/
95 0 : status = device_driver(gen_info->driver[channel], CMD_GET,
96 0 : channel - gen_info->channel_offset[channel],
97 0 : &gen_info->demand[channel]);
98 :
99 0 : if (gen_info->demand[channel] != gen_info->demand_mirror[channel]) {
100 0 : gen_info->demand_mirror[channel] = gen_info->demand[channel];
101 0 : db_set_data(hDB, gen_info->hDemand, gen_info->demand,
102 0 : sizeof(float) * gen_info->num_channels, gen_info->num_channels,
103 : TID_FLOAT);
104 : }
105 :
106 0 : return status;
107 : }
108 :
109 : /*------------------------------------------------------------------*/
110 :
111 0 : void gen_demand(INT hDB, INT hKey, void *info)
112 : {
113 : INT i, status;
114 : GEN_INFO *gen_info;
115 : EQUIPMENT *pequipment;
116 :
117 0 : pequipment = (EQUIPMENT *) info;
118 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
119 :
120 : /* set individual channels only if demand value differs */
121 0 : for (i = 0; i < gen_info->num_channels; i++)
122 0 : if (gen_info->demand[i] != gen_info->demand_mirror[i]) {
123 0 : if ((gen_info->driver[i]->flags & DF_READ_ONLY) == 0) {
124 0 : status = device_driver(gen_info->driver[i], CMD_SET, // Voltage
125 0 : i - gen_info->channel_offset[i], gen_info->demand[i]);
126 : }
127 0 : gen_info->demand_mirror[i] = gen_info->demand[i];
128 0 : gen_info->last_change[i] = ss_millitime();
129 : }
130 :
131 0 : pequipment->odb_in++;
132 :
133 : (void)status; // defeat "set but unused" warning
134 0 : }
135 :
136 : /*------------------------------------------------------------------*/
137 :
138 0 : void gen_update_label(INT hDB, INT hKey, void *info)
139 : {
140 : INT i, status;
141 : GEN_INFO *gen_info;
142 : EQUIPMENT *pequipment;
143 :
144 0 : pequipment = (EQUIPMENT *) info;
145 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
146 :
147 : /* update channel labels based on the midas channel names */
148 0 : for (i = 0; i < gen_info->num_channels; i++)
149 0 : status = device_driver(gen_info->driver[i], CMD_SET_LABEL,
150 0 : i - gen_info->channel_offset[i],
151 0 : gen_info->names + NAME_LENGTH * i);
152 :
153 : (void)status; // defeat "set but unused" warning
154 0 : }
155 :
156 : /*------------------------------------------------------------------*/
157 :
158 0 : INT gen_init(EQUIPMENT * pequipment)
159 : {
160 : int status, size, i, j, index, offset;
161 : char str[256];
162 : HNDLE hDB, hKey, hNames, hThreshold;
163 : GEN_INFO *gen_info;
164 :
165 : /* allocate private data */
166 0 : pequipment->cd_info = calloc(1, sizeof(GEN_INFO));
167 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
168 :
169 : /* get class driver root key */
170 0 : cm_get_experiment_database(&hDB, NULL);
171 0 : sprintf(str, "/Equipment/%s", pequipment->name);
172 0 : db_create_key(hDB, 0, str, TID_KEY);
173 0 : db_find_key(hDB, 0, str, &gen_info->hKeyRoot);
174 :
175 : /* save event format */
176 0 : size = sizeof(str);
177 0 : db_get_value(hDB, gen_info->hKeyRoot, "Common/Format", str, &size, TID_STRING, TRUE);
178 :
179 0 : if (equal_ustring(str, "Fixed"))
180 0 : gen_info->format = FORMAT_FIXED;
181 0 : else if (equal_ustring(str, "MIDAS"))
182 0 : gen_info->format = FORMAT_MIDAS;
183 : else
184 0 : assert(!"unknown ODB Common/Format");
185 :
186 : /* count total number of channels */
187 0 : for (i = 0, gen_info->num_channels = 0; pequipment->driver[i].name[0]; i++) {
188 0 : if (pequipment->driver[i].channels == 0) {
189 0 : cm_msg(MERROR, "gen_init", "Driver with zero channels not allowed");
190 0 : return FE_ERR_ODB;
191 : }
192 :
193 : // db_create_key(hDB, gen_info->hKeyRoot, "Settings/Channels", TID_KEY);
194 : // db_find_key(hDB, gen_info->hKeyRoot, "Settings/Channels", &hKey);
195 :
196 : //for (i = 0, gen_info->num_channels = 0; pequipment->driver[i].name[0]; i++) {
197 : // /* ODB value has priority over driver list in channel number */
198 : // size = sizeof(INT);
199 : // db_get_value(hDB, hKey, pequipment->driver[i].name,
200 : // &pequipment->driver[i].channels, &size, TID_INT, TRUE);
201 :
202 : // if (pequipment->driver[i].channels == 0)
203 : // pequipment->driver[i].channels = 1;
204 :
205 0 : gen_info->num_channels += pequipment->driver[i].channels;
206 : }
207 :
208 0 : if (gen_info->num_channels == 0) {
209 0 : cm_msg(MERROR, "hv_init", "No channels found in device driver list");
210 0 : return FE_ERR_ODB;
211 : }
212 :
213 : /* Allocate memory for buffers */
214 0 : gen_info->names = (char *) calloc(gen_info->num_channels, NAME_LENGTH);
215 :
216 0 : gen_info->demand = (float *) calloc(gen_info->num_channels, sizeof(float));
217 0 : gen_info->measured = (float *) calloc(gen_info->num_channels, sizeof(float));
218 0 : gen_info->raised = (BOOL *) calloc(gen_info->num_channels, sizeof(BOOL));
219 :
220 0 : gen_info->update_threshold = (float *) calloc(gen_info->num_channels, sizeof(float));
221 :
222 0 : gen_info->demand_mirror = (float *) calloc(gen_info->num_channels, sizeof(float));
223 0 : gen_info->measured_mirror = (float *) calloc(gen_info->num_channels, sizeof(float));
224 0 : gen_info->last_change = (DWORD *) calloc(gen_info->num_channels, sizeof(DWORD));
225 :
226 0 : gen_info->channel_offset = (INT *) calloc(gen_info->num_channels, sizeof(INT));
227 0 : gen_info->driver = (DEVICE_DRIVER**) calloc(gen_info->num_channels, sizeof(void *));
228 :
229 0 : if (!gen_info->driver) {
230 0 : cm_msg(MERROR, "hv_init", "Not enough memory");
231 0 : return FE_ERR_ODB;
232 : }
233 :
234 : /*---- Initialize device drivers ----*/
235 :
236 : /* call init method */
237 0 : for (i = 0; pequipment->driver[i].name[0]; i++) {
238 0 : sprintf(str, "Settings/Devices/%s", pequipment->driver[i].name);
239 0 : status = db_find_key(hDB, gen_info->hKeyRoot, str, &hKey);
240 0 : if (status != DB_SUCCESS) {
241 0 : db_create_key(hDB, gen_info->hKeyRoot, str, TID_KEY);
242 0 : status = db_find_key(hDB, gen_info->hKeyRoot, str, &hKey);
243 0 : if (status != DB_SUCCESS) {
244 0 : cm_msg(MERROR, "hv_init", "Cannot create %s entry in online database", str);
245 0 : free_mem(gen_info);
246 0 : return FE_ERR_ODB;
247 : }
248 : }
249 :
250 0 : status = device_driver(&pequipment->driver[i], CMD_INIT, hKey);
251 0 : if (status != FE_SUCCESS) {
252 0 : free_mem(gen_info);
253 0 : return status;
254 : }
255 : }
256 :
257 : /* compose device driver channel assignment */
258 0 : for (i = 0, j = 0, index = 0, offset = 0; i < gen_info->num_channels; i++, j++) {
259 0 : while (j >= pequipment->driver[index].channels && pequipment->driver[index].name[0]) {
260 0 : offset += j;
261 0 : index++;
262 0 : j = 0;
263 : }
264 :
265 0 : gen_info->driver[i] = &pequipment->driver[index];
266 0 : gen_info->channel_offset[i] = offset;
267 : }
268 :
269 : /*---- create demand variables ----*/
270 : /* get demand from ODB */
271 0 : status = db_find_key(hDB, gen_info->hKeyRoot, "Variables/Demand", &gen_info->hDemand);
272 0 : if (status == DB_SUCCESS) {
273 0 : size = sizeof(float) * gen_info->num_channels;
274 0 : db_get_data(hDB, gen_info->hDemand, gen_info->demand, &size, TID_FLOAT);
275 : }
276 : /* let device driver overwrite demand values, if it supports it */
277 0 : for (i = 0; i < gen_info->num_channels; i++) {
278 0 : if (gen_info->driver[i]->flags & DF_PRIO_DEVICE) {
279 0 : device_driver(gen_info->driver[i], CMD_GET_DEMAND,
280 0 : i - gen_info->channel_offset[i], &gen_info->demand[i]);
281 0 : gen_info->demand_mirror[i] = gen_info->demand[i];
282 : } else
283 0 : gen_info->demand_mirror[i] = -12345.f; /* use -12345 as invalid value */
284 : }
285 : /* write back demand values */
286 : status =
287 0 : db_find_key(hDB, gen_info->hKeyRoot, "Variables/Demand", &gen_info->hDemand);
288 0 : if (status != DB_SUCCESS) {
289 0 : db_create_key(hDB, gen_info->hKeyRoot, "Variables/Demand", TID_FLOAT);
290 0 : db_find_key(hDB, gen_info->hKeyRoot, "Variables/Demand", &gen_info->hDemand);
291 : }
292 0 : size = sizeof(float) * gen_info->num_channels;
293 0 : db_set_data(hDB, gen_info->hDemand, gen_info->demand, size,
294 : gen_info->num_channels, TID_FLOAT);
295 0 : db_open_record(hDB, gen_info->hDemand, gen_info->demand,
296 0 : gen_info->num_channels * sizeof(float), MODE_READ, gen_demand,
297 : pequipment);
298 :
299 : /*---- create measured variables ----*/
300 0 : db_merge_data(hDB, gen_info->hKeyRoot, "Variables/Measured",
301 0 : gen_info->measured, sizeof(float) * gen_info->num_channels,
302 : gen_info->num_channels, TID_FLOAT);
303 0 : db_find_key(hDB, gen_info->hKeyRoot, "Variables/Measured", &gen_info->hMeasured);
304 0 : memcpy(gen_info->measured_mirror, gen_info->measured,
305 0 : gen_info->num_channels * sizeof(float));
306 :
307 : /*---- get default names from device driver ----*/
308 0 : for (i = 0; i < gen_info->num_channels; i++) {
309 0 : sprintf(gen_info->names + NAME_LENGTH * i, "Default%%CH %d", i);
310 0 : device_driver(gen_info->driver[i], CMD_GET_LABEL,
311 0 : i - gen_info->channel_offset[i], gen_info->names + NAME_LENGTH * i);
312 : }
313 0 : db_merge_data(hDB, gen_info->hKeyRoot, "Settings/Names",
314 0 : gen_info->names, NAME_LENGTH * gen_info->num_channels,
315 : gen_info->num_channels, TID_STRING);
316 :
317 : /*---- set labels form midas SC names ----*/
318 0 : for (i = 0; i < gen_info->num_channels; i++) {
319 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
320 0 : device_driver(gen_info->driver[i], CMD_SET_LABEL,
321 0 : i - gen_info->channel_offset[i], gen_info->names + NAME_LENGTH * i);
322 : }
323 :
324 : /* open hotlink on channel names */
325 0 : if (db_find_key(hDB, gen_info->hKeyRoot, "Settings/Names", &hNames) == DB_SUCCESS)
326 0 : db_open_record(hDB, hNames, gen_info->names, NAME_LENGTH * gen_info->num_channels,
327 : MODE_READ, gen_update_label, pequipment);
328 :
329 : /*---- get default update threshold from device driver ----*/
330 0 : for (i = 0; i < gen_info->num_channels; i++) {
331 0 : gen_info->update_threshold[i] = 1.f; /* default 1 unit */
332 0 : device_driver(gen_info->driver[i], CMD_GET_THRESHOLD,
333 0 : i - gen_info->channel_offset[i], &gen_info->update_threshold[i]);
334 : }
335 0 : db_merge_data(hDB, gen_info->hKeyRoot, "Settings/Update Threshold Measured",
336 0 : gen_info->update_threshold, sizeof(float) * gen_info->num_channels,
337 : gen_info->num_channels, TID_FLOAT);
338 :
339 : /* open hotlink on update threshold */
340 0 : if (db_find_key(hDB, gen_info->hKeyRoot, "Settings/Update Threshold Measured", &hThreshold) == DB_SUCCESS)
341 0 : db_open_record(hDB, hThreshold, gen_info->update_threshold, sizeof(float)*gen_info->num_channels,
342 : MODE_READ, NULL, NULL);
343 :
344 : /* initially read all channels */
345 0 : for (i = 0; i < gen_info->num_channels; i++)
346 0 : gen_read(pequipment, i);
347 :
348 0 : return FE_SUCCESS;
349 : }
350 :
351 : /*----------------------------------------------------------------------------*/
352 0 : INT gen_start(EQUIPMENT * pequipment)
353 : {
354 : INT i;
355 :
356 : /* call start method of device drivers */
357 0 : for (i = 0; pequipment->driver[i].dd != NULL ; i++)
358 0 : if (pequipment->driver[i].flags & DF_MULTITHREAD) {
359 0 : pequipment->driver[i].pequipment = &pequipment->info;
360 0 : device_driver(&pequipment->driver[i], CMD_START);
361 : }
362 :
363 0 : return FE_SUCCESS;
364 : }
365 : /*------------------------------------------------------------------*/
366 0 : INT gen_stop(EQUIPMENT * pequipment)
367 : {
368 : INT i;
369 :
370 : /* call stop method of device drivers */
371 0 : for (i = 0; pequipment->driver[i].dd != NULL && pequipment->driver[i].flags & DF_MULTITHREAD ; i++)
372 0 : device_driver(&pequipment->driver[i], CMD_STOP);
373 :
374 0 : return FE_SUCCESS;
375 : }
376 :
377 : /*------------------------------------------------------------------*/
378 0 : INT gen_exit(EQUIPMENT * pequipment)
379 : {
380 : INT i;
381 :
382 0 : free_mem((GEN_INFO *) pequipment->cd_info);
383 :
384 : /* call exit method of device drivers */
385 0 : for (i = 0; pequipment->driver[i].dd != NULL; i++)
386 0 : device_driver(&pequipment->driver[i], CMD_EXIT);
387 :
388 0 : return FE_SUCCESS;
389 : }
390 :
391 : /*------------------------------------------------------------------*/
392 0 : INT gen_idle(EQUIPMENT * pequipment)
393 : {
394 : static BOOL odb_update_flag = FALSE;
395 : static INT last_raised_channel = -1;
396 : static INT number_raised = 0;
397 : INT act, i, next_raised, loop;
398 0 : int status = 0;
399 : DWORD act_time;
400 : GEN_INFO *gen_info;
401 : HNDLE hDB;
402 :
403 : /* Class info shortcut */
404 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
405 :
406 : /* get current time */
407 0 : act_time = ss_millitime();
408 :
409 : /* Do loop N channel per idle */
410 0 : for (loop = 0; loop < number_raised + 1; loop++) {
411 :
412 : /* Select channel to read */
413 : /* k = last_raised_channel; */
414 :
415 0 : if (last_raised_channel < 0) {
416 : /* Normal channel */
417 0 : act = (gen_info->last_channel + 1) % gen_info->num_channels;
418 : // printf("N :%d ", act);
419 : } else {
420 : /* Raised channel */
421 0 : act = last_raised_channel;
422 : // printf(" R :%d ", act);
423 : }
424 :
425 : /* Read channel */
426 0 : status = gen_read(pequipment, act);
427 :
428 : /* Check read value against previous value (mirror) */
429 0 : if (abs(gen_info->measured[act] - gen_info->measured_mirror[act]) >
430 0 : gen_info->update_threshold[act]) {
431 : /* Greater than Delta => raise channel for close monitoring */
432 0 : gen_info->raised[act] = TRUE;
433 : /* Force an ODB update to reflect change */
434 0 : odb_update_flag = TRUE;
435 : } else {
436 : /* Within the limits => lower channel if it was raised */
437 0 : gen_info->raised[act] = FALSE;
438 : }
439 :
440 0 : printf("F:%d mes:%f mir:%f th:%f\n", gen_info->raised[act]
441 0 : , gen_info->measured[act]
442 0 : ,gen_info->measured_mirror[act], gen_info->update_threshold[act]);
443 :
444 : /* hold last value */
445 0 : gen_info->measured_mirror[act] = gen_info->measured[act];
446 :
447 : /* Get next raised channel if any (-1:none) */
448 0 : if (act == gen_info->num_channels) {
449 0 : next_raised = -1;
450 : } else {
451 0 : for (next_raised = act + 1; next_raised < gen_info->num_channels; next_raised++) {
452 0 : if (gen_info->raised[next_raised])
453 0 : break;
454 : }
455 0 : if (next_raised == gen_info->num_channels) {
456 0 : next_raised = -1;
457 : }
458 : }
459 :
460 : /* update last raised channel for next go */
461 0 : if (next_raised < 0) {
462 : /* no more raised channel set normal channel (increment channel) */
463 0 : gen_info->last_channel = (gen_info->last_channel + 1) % gen_info->num_channels;
464 0 : last_raised_channel = -1;
465 : } else {
466 : /* More raised channel then set for next round */
467 0 : last_raised_channel = next_raised;
468 : }
469 :
470 : /* count the raised channels
471 : to be used for possible multiple read per idle
472 : see for loop at begining of function.
473 : */
474 0 : for (i = 0, number_raised = 0; i < gen_info->num_channels; i++) {
475 0 : if (gen_info->raised[i])
476 0 : number_raised++;
477 : }
478 : }
479 :
480 : /* sends new values to ODB if:
481 : ODB_UPDATE_TIME timeout exceeded
482 : or
483 : At least one channel has been raised */
484 0 : if (odb_update_flag || ((act_time - gen_info->last_update) > ODB_UPDATE_TIME)) {
485 0 : cm_get_experiment_database(&hDB, NULL);
486 0 : db_set_data(hDB, gen_info->hMeasured, gen_info->measured,
487 0 : sizeof(float) * gen_info->num_channels, gen_info->num_channels,
488 : TID_FLOAT);
489 0 : gen_info->last_update = act_time;
490 0 : odb_update_flag = FALSE;
491 :
492 : /* Keep odb count */
493 0 : pequipment->odb_out++;
494 : }
495 0 : return status;
496 : }
497 :
498 : /*------------------------------------------------------------------*/
499 0 : INT cd_gen_read(char *pevent, int offset)
500 : {
501 : float *pdata;
502 : GEN_INFO *gen_info;
503 : EQUIPMENT *pequipment;
504 :
505 0 : pequipment = *((EQUIPMENT **) pevent);
506 0 : gen_info = (GEN_INFO *) pequipment->cd_info;
507 :
508 0 : if (gen_info->format == FORMAT_FIXED) {
509 0 : memcpy(pevent, gen_info->demand, sizeof(float) * gen_info->num_channels);
510 0 : pevent += sizeof(float) * gen_info->num_channels;
511 :
512 0 : memcpy(pevent, gen_info->measured, sizeof(float) * gen_info->num_channels);
513 0 : pevent += sizeof(float) * gen_info->num_channels;
514 :
515 0 : return 2 * sizeof(float) * gen_info->num_channels;
516 0 : } else if (gen_info->format == FORMAT_MIDAS) {
517 0 : bk_init(pevent);
518 :
519 : /* create DMND bank */
520 0 : bk_create(pevent, "DMND", TID_FLOAT, (void**) &pdata);
521 0 : memcpy(pdata, gen_info->demand, sizeof(float) * gen_info->num_channels);
522 0 : pdata += gen_info->num_channels;
523 0 : bk_close(pevent, pdata);
524 :
525 : /* create MSRD bank */
526 0 : bk_create(pevent, "MSRD", TID_FLOAT, (void**) &pdata);
527 0 : memcpy(pdata, gen_info->measured, sizeof(float) * gen_info->num_channels);
528 0 : pdata += gen_info->num_channels;
529 0 : bk_close(pevent, pdata);
530 :
531 0 : return bk_size(pevent);
532 : } else {
533 0 : assert(!"unknown gen_info->format");
534 : return 0;
535 : }
536 : }
537 :
538 : /*------------------------------------------------------------------*/
539 :
540 0 : INT cd_gen(INT cmd, EQUIPMENT * pequipment)
541 : {
542 : INT status;
543 :
544 0 : switch (cmd) {
545 0 : case CMD_INIT:
546 0 : status = gen_init(pequipment);
547 0 : break;
548 :
549 0 : case CMD_START:
550 0 : status = gen_start(pequipment);
551 0 : break;
552 :
553 0 : case CMD_STOP:
554 0 : status = gen_stop(pequipment);
555 0 : break;
556 :
557 0 : case CMD_EXIT:
558 0 : status = gen_exit(pequipment);
559 0 : break;
560 :
561 0 : case CMD_IDLE:
562 0 : status = gen_idle(pequipment);
563 0 : break;
564 :
565 0 : default:
566 0 : cm_msg(MERROR, "Generic class driver", "Received unknown command %d", cmd);
567 0 : status = FE_ERR_DRIVER;
568 0 : break;
569 : }
570 :
571 0 : return status;
572 : }
|