Low-Energy Muon (LEM) Experiment  0.5.2
hv_nhq_20xm_mscb.c
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: hv_nhq_20xm_mscb.c
4  Created by: Andreas Suter, 2005/09/05
5 
6  Contents: iseg NHQ 20xM High Voltage Device Driver
7 
8  RS232: 9600 baud, 8 data bits, 1 stop bit, no parity bit,
9  protocol: none, termination: "\r\n"
10 
11 \********************************************************************/
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <math.h>
18 #include <time.h>
19 #include "midas.h"
20 #include "mscb.h"
21 #include "hv_nhq_20xm_mscb.h"
22 
23 #define NHQ_MAX_INIT_LOOP 5
24 
25 #define NHQ_DEBUG 0
26 
27 #define NHQ_ON 0x000
28 #define NHQ_OFF 0x001
29 #define NHQ_MAN 0x002
30 #define NHQ_ERR 0x004
31 #define NHQ_INH 0x008
32 #define NHQ_QUA 0x010
33 #define NHQ_TRP 0x020
34 
35 //--- NHQ status flags ---------------------------------------------
36 #define NHQ_CH_MAN 0x02
37 #define NHQ_POL_POS 0x04
38 #define NHQ_CH_OFF 0x08
39 #define NHQ_KILL_ENABLE 0x10
40 #define NHQ_CH_INHIBIT 0x20
41 #define NHQ_TOO_HIGH 0x40
42 #define NHQ_BAD_QUAL 0x80
43 
44 #define NHQ_NO_CHS 2
46 
48 #define NHQ_NO_VARS 29
49 
50 //---- NHQ commands ------------------------------------------------
51 #define NHQ_CMD 0x01
52 #define NHQ_CMD_D 0x02
53 #define NHQ_CMD_V 0x04
54 #define NHQ_ID 0x06
55 #define NHQ_WAITTIME 0x07
56 #define NHQ_U 0x08
57 #define NHQ_I 0x0A
58 #define NHQ_M 0x0C
59 #define NHQ_N 0x0E
60 #define NHQ_D 0x10
61 #define NHQ_V 0x12
62 #define NHQ_L 0x14
63 #define NHQ_S 0x16
64 #define NHQ_T 0x18
65 #define NHQ_A 0x1A
66 #define NHQ_BAUD 0x1C
67 
68 #define NHQ_MAX_ALLOWED_ERR 25
70 
71 //---- globals -----------------------------------------------------
72 
76 typedef struct {
77  BOOL enabled;
78  BOOL debug;
79  char port[NAME_LENGTH];
80  char pwd[NAME_LENGTH];
81  INT group_addr;
82  INT node_addr;
83  char reboot_time[NAME_LENGTH];
84  int odb_offset;
85  char device_name[NAME_LENGTH];
86  float max_voltage;
87  float max_current;
88  char ch_names[NHQ_NO_CHS][NAME_LENGTH];
89  float update_threshold_measured[NHQ_NO_CHS];
90  float update_threshold_current[NHQ_NO_CHS];
91  float voltage_limit[NHQ_NO_CHS];
92  float current_limit[NHQ_NO_CHS];
93  float ramp_speed_up[NHQ_NO_CHS];
94  float ramp_speed_down[NHQ_NO_CHS];
96 
98 #define HV_NHQ_20XM_SETTINGS_STR "\
99 Enabled = BOOL : 0\n\
100 Debug = BOOL : 0\n\
101 Device = STRING : [32] mscbfff \n\
102 PWD = STRING : [32] ???? \n\
103 Group Addr = INT : 1\n\
104 Node Addr = INT : 11\n\
105 Reboot Time = STRING : [32] 00:57\n\
106 ODB Offset = INT : 0\n\
107 Device Name = STRING : [32] NHQ 204M Trigger Module 1 \n\
108 Max. Voltage (kV) = FLOAT : 4.f \n\
109 Max. Current (mA) = FLOAT : 3.f \n\
110 CH_Name = STRING[2] : \n\
111 [32] NHQ 204M%A \n\
112 [32] NHQ 204M%B \n\
113 Update Threshold Measured = FLOAT[2] : \n\
114 0.005 \n\
115 0.005 \n\
116 Update Threshold Current = FLOAT[2] : \n\
117 0.005 \n\
118 0.005 \n\
119 Voltage Limit = FLOAT[2] : \n\
120 4.0 \n\
121 4.0 \n\
122 Current Limit = FLOAT[2] : \n\
123 0.001 \n\
124 0.001 \n\
125 Ramp Speed Up = FLOAT[2] : \n\
126 0.1 \n\
127 0.1 \n\
128 Ramp Speed Down = FLOAT[2] : \n\
129 0.0 \n\
130 0.0 \n\
131 "
132 
136 typedef struct {
137  char id[32];
138  int wait_time;
139  float u[2];
140  float i[2];
141  int m[2];
142  int n[2];
143  float d[2];
144  float v[2];
145  int l[2];
146  char s[2][8];
147  int t[2];
148  int a[2];
150 
154 typedef struct {
157  int reboot_time[2];
158  int fd;
159  int ch_status[NHQ_NO_CHS];
160  int ch_pol[NHQ_NO_CHS];
162  HNDLE hDB;
163  HNDLE dd_hkey;
165  DWORD timer;
166  int rebooting;
167  int err;
169 
170 
171 //---- device driver routines ------------------------------------------------
172 
173 //----------------------------------------------------------------------------
181 {
182  int status;
183  int i;
184  unsigned char buffer[256];
185  int size = sizeof(buffer);
186  int value;
187  float fvalue, fexp;
188 
189  FILE *fp;
190 
191  if (read_all) { // only needed at startup
192  // read id
193  size = 32*sizeof(char);
194  status = mscb_read(info->fd, info->settings.node_addr, NHQ_ID, buffer, &size);
195  if (status != MSCB_SUCCESS) { // not successfull
196  info->err++;
197  return status;
198  }
199  strncpy(info->data.id, (const char *)buffer, 32);
200 
201  // read wait time
202  size = 6*sizeof(char);
203  status = mscb_read(info->fd, info->settings.node_addr, NHQ_WAITTIME, buffer, &size);
204  if (status != MSCB_SUCCESS) { // not successfull
205  info->err++;
206  return status;
207  }
208  status = sscanf((const char *)buffer, "%d", &value);
209  if (status != 1) // error
210  return -1;
211  info->data.wait_time = value;
212 
213  for (i=0; i<NHQ_NO_CHS; i++) {
214  // read HV limit
215  size = 6*sizeof(char);
216  status = mscb_read(info->fd, info->settings.node_addr, NHQ_M+i, buffer, &size);
217  if (status != MSCB_SUCCESS) { // not successfull
218  info->err++;
219  return status;
220  }
221  status = sscanf((const char *)buffer, "%d", &value);
222  if (status != 1) // error
223  return -1;
224  info->data.m[i] = value;
225 
226  // read current limit
227  size = 6*sizeof(char);
228  status = mscb_read(info->fd, info->settings.node_addr, NHQ_N+i, buffer, &size);
229  if (status != MSCB_SUCCESS) { // not successfull
230  info->err++;
231  return status;
232  }
233  status = sscanf((const char *)buffer, "%d", &value);
234  if (status != 1) // error
235  return -1;
236  info->data.n[i] = value;
237 
238  // read ramping speed
239  size = 6*sizeof(char);
240  status = mscb_read(info->fd, info->settings.node_addr, NHQ_V+i, buffer, &size);
241  if (status != MSCB_SUCCESS) { // not successfull
242  info->err++;
243  return status;
244  }
245  status = sscanf((const char *)buffer, "%d", &value);
246  if (status != 1) // error
247  return -1;
248  info->data.v[i] = (float)value/1.0e3; // V/s -> kV/s
249 
250  // read current trip level
251  size = 6*sizeof(char);
252  status = mscb_read(info->fd, info->settings.node_addr, NHQ_L+i, buffer, &size);
253  if (status != MSCB_SUCCESS) { // not successfull
254  info->err++;
255  return status;
256  }
257  status = sscanf((const char *)buffer, "%d", &value);
258  if (status != 1) // error
259  return -1;
260  info->data.l[i] = value;
261 
262  // read autostart tag
263  size = 6*sizeof(char);
264  status = mscb_read(info->fd, info->settings.node_addr, NHQ_A+i, buffer, &size);
265  if (status != MSCB_SUCCESS) { // not successfull
266  info->err++;
267  return status;
268  }
269  status = sscanf((const char *)buffer, "%d", &value);
270  if (status != 1) // error
271  return -1;
272  info->data.a[i] = value;
273  }
274  }
275 
276  for (i=0; i<NHQ_NO_CHS; i++) {
277 
278  ss_sleep(50);
279 
280  // read measured HV
281  size = 6*sizeof(char);
282  status = mscb_read(info->fd, info->settings.node_addr, NHQ_U+i, buffer, &size);
283  if (status != MSCB_SUCCESS) { // not successfull
284  info->err++;
285  return status;
286  }
287  status = sscanf((const char *)buffer, "%d", &value);
288  if (status != 1) // error
289  return -1;
290  info->data.u[i] = (float)value/1.0e3; // V -> kV
291 
292  ss_sleep(50);
293 
294  // read demand HV
295  size = 6*sizeof(char);
296  status = mscb_read(info->fd, info->settings.node_addr, NHQ_D+i, buffer, &size);
297  if (status != MSCB_SUCCESS) { // not successfull
298  info->err++;
299  return status;
300  }
301  status = sscanf((const char *)buffer, "%d", &value);
302  if (status != 1) // error
303  return -1;
304  info->data.d[i] = (float)value/1.0e3; // V -> kV
305 
306  ss_sleep(50);
307 
308  // read measured current
309  size = 8*sizeof(char);
310  status = mscb_read(info->fd, info->settings.node_addr, NHQ_I+i, buffer, &size);
311  if (status != MSCB_SUCCESS) { // not successfull
312  info->err++;
313  return status;
314  }
315  status = sscanf((const char *)buffer, "%f%f,", &fvalue, &fexp);
316  if (status != 2) // error
317  return -1;
318  sprintf((char *)buffer, "%0.1fE%f", fvalue, fexp); // construct a 'float string'
319  sscanf((const char *)buffer, "%f", &fvalue); // extract float from 'float string'
320  info->data.i[i] = fvalue*1.0e3; // A -> mA
321 
322  ss_sleep(50);
323 
324  // read status
325  size = 8*sizeof(char);
326  status = mscb_read(info->fd, info->settings.node_addr, NHQ_S+i, buffer, &size);
327  if (status != MSCB_SUCCESS) { // not successfull
328  info->err++;
329  return status;
330  }
331  strncpy(info->data.s[i], (const char *)buffer, 8);
332 
333  ss_sleep(50);
334 
335  // read device status
336  size = 6*sizeof(char);
337  status = mscb_read(info->fd, info->settings.node_addr, NHQ_T+i, buffer, &size);
338  if (status != MSCB_SUCCESS) { // not successfull
339  info->err++;
340  return status;
341  }
342  status = sscanf((const char *)buffer, "%d", &value);
343  if (status != 1) // error
344  return -1;
345  info->data.t[i] = value;
346  }
347 
348  info->err = 0;
349 
350  if (info->settings.debug) {
351  fp = fopen("hv_nhq_20xm_mscb.log", "a");
352 
353  if (read_all) {
354  fprintf(fp, "id: %s\n", info->data.id);
355  fprintf(fp, "wait_time: %d\n", info->data.wait_time);
356  fprintf(fp, "u: %f, %f\n", info->data.u[0], info->data.u[1]);
357  fprintf(fp, "i: %f, %f\n", info->data.i[0], info->data.i[1]);
358  fprintf(fp, "m: %d, %d\n", info->data.m[0], info->data.m[1]);
359  fprintf(fp, "n: %d, %d\n", info->data.n[0], info->data.n[1]);
360  fprintf(fp, "d: %f, %f\n", info->data.d[0], info->data.d[1]);
361  fprintf(fp, "v: %f, %f\n", info->data.v[0], info->data.v[1]);
362  fprintf(fp, "l: %d, %d\n", info->data.l[0], info->data.l[1]);
363  fprintf(fp, "s: %s, %s\n", info->data.s[0], info->data.s[1]);
364  fprintf(fp, "t: %d, %d\n", info->data.t[0], info->data.t[1]);
365  fprintf(fp, "a: %d, %d\n", info->data.a[0], info->data.a[1]);
366  fprintf(fp, "------------------------\n");
367  } else {
368  fprintf(fp, "u: %f, %f\n", info->data.u[0], info->data.u[1]);
369  fprintf(fp, "i: %f, %f\n", info->data.i[0], info->data.i[1]);
370  fprintf(fp, "d: %f, %f\n", info->data.d[0], info->data.d[1]);
371  fprintf(fp, "s: %s, %s\n", info->data.s[0], info->data.s[1]);
372  fprintf(fp, "t: %d, %d\n", info->data.t[0], info->data.t[1]);
373  fprintf(fp, "------------------------\n");
374  }
375 
376  fclose(fp);
377  }
378 
379  return MSCB_SUCCESS;
380 }
381 
382 //----------------------------------------------------------------------------
391 {
392  if (strstr(info->data.s[ch], "?")) { // synchronization error
393  return;
394  }
395  if (strstr(info->data.s[ch], "ON")) {
396  if (info->ch_status[ch] != NHQ_ON) {
397  info->ch_status[ch]=NHQ_ON;
398  cm_msg(MINFO, "hv_nhq_20xm_check_status", "%s, ch %s, channel switched on at the frontpanel. (%s)",
399  info->settings.device_name, info->settings.ch_names[ch], info->data.s[ch]);
400  }
401  }
402  if (strstr(info->data.s[ch], "OFF")) {
403  if (!(info->ch_status[ch] & NHQ_OFF)) {
404  info->ch_status[ch] |= NHQ_OFF;
405  cm_msg(MERROR, "hv_nhq_20xm_check_status", "%s, ch %s, channel switched off at the frontpanel. (%s)",
406  info->settings.device_name, info->settings.ch_names[ch], info->data.s[ch]);
407  }
408  } else if (strstr(info->data.s[ch], "MAN")) {
409  if (!(info->ch_status[ch] & NHQ_MAN)) {
410  info->ch_status[ch] |= NHQ_MAN;
411  cm_msg(MERROR, "hv_nhq_20xm_check_status", "%s, ch %s, hv switched to manual.",
412  info->settings.device_name, info->settings.ch_names[ch]);
413  }
414  } else if (strstr(info->data.s[ch], "ERR")) {
415  if (!(info->ch_status[ch] & NHQ_ERR)) {
416  info->ch_status[ch] |= NHQ_ERR;
417  cm_msg(MERROR, "hv_nhq_20xm_check_status", "%s, ch %s, V_max or I_max exceeded.",
418  info->settings.device_name, info->settings.ch_names[ch]);
419  }
420  } else if (strstr(info->data.s[ch], "INH")) {
421  if (!(info->ch_status[ch] & NHQ_INH)) {
422  info->ch_status[ch] |= NHQ_INH;
423  cm_msg(MERROR, "hv_nhq_20xm_check_status", "%s, ch %s, inhibit signal was active.",
424  info->settings.device_name, info->settings.ch_names[ch]);
425  }
426  } else if (strstr(info->data.s[ch], "QUA")) {
427  if (!(info->ch_status[ch] & NHQ_QUA)) {
428  info->ch_status[ch] |= NHQ_QUA;
429  cm_msg(MERROR, "hv_nhq_20xm_check_status",
430  "%s, ch %s, quality of output voltage not guaranteed at present.",
431  info->settings.device_name, info->settings.ch_names[ch]);
432  }
433  } else if (strstr(info->data.s[ch], "TRP")) {
434  if (!(info->ch_status[ch] & NHQ_TRP)) {
435  info->ch_status[ch] |= NHQ_TRP;
436  cm_msg(MERROR, "hv_nhq_20xm_check_status", "%s, ch %s, current trip was active.",
437  info->settings.device_name, info->settings.ch_names[ch]);
438  }
439  }
440 }
441 
442 //----------------------------------------------------------------------------
453 {
454  int status, i;
455  HNDLE hKey;
456  int offset = info->settings.odb_offset;
457  float value;
458 
459  // Update Threshold Measured
460  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Update Threshold Measured", &hKey);
461  if (status != DB_SUCCESS)
462  return status;
463  for (i=0; i<channels; i++) {
464  db_set_data_index(info->hDB, hKey, &info->settings.update_threshold_measured[i],
465  sizeof(float), i+offset, TID_FLOAT);
466  }
467 
468  // Update Threshold Current
469  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Update Threshold Current", &hKey);
470  if (status != DB_SUCCESS)
471  return status;
472  for (i=0; i<channels; i++) {
473  db_set_data_index(info->hDB, hKey, &info->settings.update_threshold_current[i],
474  sizeof(float), i+offset, TID_FLOAT);
475  }
476 
477  // Voltage Limit
478  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Voltage Limit", &hKey);
479  if (status != DB_SUCCESS)
480  return status;
481  for (i=0; i<channels; i++) {
482  db_set_data_index(info->hDB, hKey, &info->settings.voltage_limit[i],
483  sizeof(float), i+offset, TID_FLOAT);
484  }
485 
486  // Current Limit
487  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Current Limit", &hKey);
488  if (status != DB_SUCCESS)
489  return status;
490  for (i=0; i<channels; i++) {
491  db_set_data_index(info->hDB, hKey, &info->settings.current_limit[i],
492  sizeof(float), i+offset, TID_FLOAT);
493  }
494 
495  // Ramp Up Speed
496  value = 0.1; // ramping is done in the nhq itself, therefore the class driver ramping speed = 0.0
497  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Ramp Up Speed", &hKey);
498  if (status != DB_SUCCESS)
499  return status;
500  for (i=0; i<channels; i++) {
501  db_set_data_index(info->hDB, hKey, &value, sizeof(float), i+offset, TID_FLOAT);
502  }
503 
504  // Ramp Down Speed
505  value = 0.0; // ramping is done in the nhq itself, therefore the class driver ramping speed = 0.0
506  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Ramp Down Speed", &hKey);
507  if (status != DB_SUCCESS)
508  return status;
509  for (i=0; i<channels; i++) {
510  db_set_data_index(info->hDB, hKey, &value, sizeof(float), i+offset, TID_FLOAT);
511  }
512 
513  return DB_SUCCESS;
514 }
515 
516 //----------------------------------------------------------------------------
527 {
528  int status, i, size;
529  HNDLE hKey;
530  int offset = info->settings.odb_offset;
531  float value;
532  char cmd[16];
533 
534  status = db_find_key(info->hDB, 0, "/Equipment/HV Detectors/Settings/Ramp Up Speed", &hKey);
535  if (status != DB_SUCCESS)
536  return status;
537 
538  for (i=0; i<channels; i++) {
539  size = sizeof(float);
540  status = db_get_data_index(info->hDB, hKey, &value, &size, i+offset, TID_FLOAT);
541  if (status != DB_SUCCESS)
542  break;
543  size = sizeof(cmd);
544  sprintf(cmd, "V%d=%03d", i+1, abs((int)(value*1.0e3)));
545  status = mscb_write(info->fd, info->settings.node_addr, (unsigned char)NHQ_CMD_V+i, cmd, size);
546  }
547 
548  return DB_SUCCESS;
549 }
550 
551 //----------------------------------------------------------------------------
560 {
561  int status, hh, mm;
562 
563  // extract hour and min from the DD entry
564  status = sscanf(info->settings.reboot_time, "%d:%d", &hh, &mm);
565 
566  // check for correctness
567  if ((status == 2) && ((hh>=0) && (hh<=23)) && ((mm>=0) && (mm<=59))) { // correct
568  info->reboot_time[0] = hh;
569  info->reboot_time[1] = mm;
570  } else { // not correct
571  info->reboot_time[0] = -1;
572  info->reboot_time[1] = -1;
573  }
574 }
575 
576 //----------------------------------------------------------------------------
588 INT hv_nhq_20xm_mscb_init(HNDLE hKey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
589 {
590  int status, size, i;
591  char pol[16];
592  HNDLE hDB, ddhKey;
594 
595  // allocate info structure
596  info = (HV_NHQ_20XM_INFO *)calloc(1, sizeof(HV_NHQ_20XM_INFO));
597  *pinfo = info;
598 
599  cm_get_experiment_database(&hDB, NULL);
600 
601  // create HV_NHQ_20XM device driver setting record
602  status = db_create_record(hDB, hKey, "DD", HV_NHQ_20XM_SETTINGS_STR);
603  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
604  cm_msg(MERROR, "hv_nhq_20xm_init", "hv_nhq_20xm_init: Error creating NHQ DD record in ODB, status=%d", status);
605  cm_yield(0);
606  return FE_ERR_ODB;
607  }
608 
609  db_find_key(hDB, hKey, "DD", &ddhKey);
610 
611  size = sizeof(info->settings);
612  db_get_record(hDB, ddhKey, &info->settings, &size, 0);
613 
614  // check if the device is enabled
615  if (!info->settings.enabled) {
616  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "\"%s\" is disabled from the ODB.", info->settings.device_name);
617  cm_yield(0);
618  info->startup_error = 1;
619  return FE_SUCCESS;
620  }
621 
622  // initialize driver settings
623  info->num_channels = channels;
624  info->hDB = hDB;
625  info->dd_hkey = ddhKey;
626  info->startup_error = FALSE;
627  info->timer = ss_millitime();
628  info->rebooting = 0;
629  info->ch_status[0] = NHQ_ON;
630  info->ch_status[1] = NHQ_ON;
631  info->err = 0;
632 
633  // get reboot time
635 
636  // update ODB HV settings
637  status = hv_nhq_20xm_mscb_update_odb(info, channels);
638  if (status != DB_SUCCESS) {
639  cm_msg(MERROR, "hv_nhq_20xm_mscb_update_odb", "Error by updating ODB HV settings.");
640  cm_yield(0);
641  }
642 
643  cm_msg(MINFO, "hv_nhq_20xm_mscb_init","initialize %s.", info->settings.device_name);
644  cm_yield(0);
645 
646  // init mscb
647  info->fd = mscb_init(info->settings.port, sizeof(info->settings.port), info->settings.pwd, NHQ_DEBUG);
648  if (info->fd < 0) {
649  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "hv_nhq_20xm_mscb_init: Couldn't initialize %s, MSCB device %s",
650  info->settings.device_name, info->settings.port);
651  cm_yield(0);
652  info->startup_error = 1;
653  return FE_SUCCESS;
654  }
655  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "hv_nhq_20xm_mscb_init: %s, MSCB node %d initialized.",
656  info->settings.device_name, info->settings.node_addr);
657  cm_yield(0);
658 
659  // set ramping speed
660  hv_nhq_20xm_mscb_set_ramping(info, channels);
661 
662  // read variables
663  for (i=0; i<NHQ_MAX_INIT_LOOP; i++) {
664  status = hv_nhq_20xm_mscb_get_all(info, TRUE);
665  if (status == MSCB_SUCCESS)
666  break;
667  ss_sleep(500);
668  }
669 
670  if (status != MSCB_SUCCESS) {
671  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "hv_nhq_20xm_mscb_init: %s, Couldn't read data.",
672  info->settings.device_name);
673  cm_yield(0);
674  info->startup_error = 1;
675  return FE_SUCCESS;
676  }
677 
678  // report id
679  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "hv_nhq_20xm_mscb_init: %s, node %d, id=%s",
680  info->settings.device_name, info->settings.node_addr, info->data.id);
681 
682  // report wait time
683  cm_msg(MINFO, "hv_nhq_20xm_mscb_init", "hv_nhq_20xm_mscb_init: %s, node %d, wait time=%d (ms)",
684  info->settings.device_name, info->settings.node_addr, info->data.wait_time);
685 
686  // report hv limits
687  for (i=0; i<NHQ_NO_CHS; i++) {
688  cm_msg(MINFO, "hv_nhq_20xm_init", "%s: channel %d - hardware voltage limit = %d%% of %f (kV)",
689  info->settings.device_name, i+1, info->data.m[i], info->settings.max_voltage);
690  }
691 
692  // report current limits
693  for (i=0; i<NHQ_NO_CHS; i++) {
694  cm_msg(MINFO, "hv_nhq_20xm_init", "%s: channel %d - hardware current limit = %d%% of %f (mA)",
695  info->settings.device_name, i+1, info->data.n[i], info->settings.max_current);
696  }
697 
698  // report status infos
699  for (i=0; i<NHQ_NO_CHS; i++) {
700  cm_msg(MINFO, "hv_nhq_20xm_init", "%s: status info channel %d: %s",
701  info->settings.device_name, i+1, info->data.s[i]);
702  }
703 
704  // report polarities
705  for (i=0; i<NHQ_NO_CHS; i++) {
706  if (info->data.t[i] & NHQ_POL_POS) { // positive polarity
707  info->ch_pol[i] = 1;
708  strcpy(pol, "positive");
709  } else { // negative polarity
710  info->ch_pol[i] = -1;
711  strcpy(pol, "negative");
712  }
713  cm_msg(MINFO, "hv_nhq_20xm_init", "%s: channel %s - pol = %s",
714  info->settings.device_name, info->settings.ch_names[i], pol);
715  }
716  cm_yield(0);
717 
718  return FE_SUCCESS;
719 }
720 
721 //----------------------------------------------------------------------------
731 {
732  if (info->startup_error) return FE_SUCCESS;
733 
734  // call EXIT function of the mscb lib
735  mscb_exit(info->fd);
736 
737  free(info);
738 
739  return FE_SUCCESS;
740 }
741 
742 //----------------------------------------------------------------------------
752 INT hv_nhq_20xm_mscb_set(HV_NHQ_20XM_INFO *info, INT channel, float value)
753 {
754  int status, size;
755  char cmd[16];
756 
757  if (info->startup_error) {
758  ss_sleep(10);
759  return FE_SUCCESS;
760  }
761 
762  // check if demand hv setting is within allowed limits
763  if (value > info->settings.voltage_limit[channel]) {
764  cm_msg(MERROR, "hv_nhq_20xm_mscb_set", "%s: %s set value = %f exceeds voltage limit = %f.",
765  info->settings.device_name, info->settings.ch_names[channel], value,
766  info->settings.voltage_limit[channel]);
767  return FE_SUCCESS;
768  }
769 
770  // set new voltage
771  size = sizeof(cmd);
772  sprintf(cmd, "D%d=%04d", channel+1, abs((int)(value*1.0e3)));
773  status = mscb_write(info->fd, info->settings.node_addr, (unsigned char)NHQ_CMD_D+channel, cmd, size);
774 
775  return FE_SUCCESS;
776 }
777 
778 //----------------------------------------------------------------------------
789 INT hv_nhq_20xm_mscb_get_label(HV_NHQ_20XM_INFO *info, INT channel, char *name)
790 {
791  strcpy(name, info->settings.ch_names[channel]);
792 
793  return FE_SUCCESS;
794 }
795 
796 //----------------------------------------------------------------------------
806 INT hv_nhq_20xm_mscb_get(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
807 {
808  time_t tt;
809  struct tm now;
810  int status;
811 
812  // check if there have been any startup errors
813  if (info->startup_error) {
814  *pvalue = -999.;
815  ss_sleep(10); // to keep CPU load low when Run active
816  return FE_SUCCESS;
817  }
818 
819  // check if a reboot time is set and if yes, if it is reached
820  if ((info->reboot_time[0] != -1) && !info->rebooting) {
821  time(&tt);
822  localtime_r(&tt, &now);
823  if ((now.tm_hour == info->reboot_time[0]) && (now.tm_min == info->reboot_time[1])) {
824  // reboot
825  mscb_reboot(info->fd, info->settings.node_addr, info->settings.group_addr, 0);
826  // prevent reading data for a while
827  info->timer = ss_millitime() + 60000; // shift timer 60 sec into the future
828  // tell the system that a reboot is taking place
829  info->rebooting = 1;
830  }
831  }
832 
833  // just after a reboot, do nothing
834  // (necessary since if info->timer > ss_millitime(), i.e. ss_millitime() - info->timer < 0
835  // there is a problem, since DWORD will see negative times as positive ones!)
836  if (info->timer > ss_millitime())
837  return FE_SUCCESS;
838 
839 
840  if ((ss_millitime() - info->timer) > 5000) { // read data from nhq
841  // reset rebooting flag
842  info->rebooting = 0;
843  info->timer = ss_millitime(); // restart timer
844  status = hv_nhq_20xm_mscb_get_all(info, FALSE);
845  if (status != MSCB_SUCCESS)
846  return FE_SUCCESS;
847  }
848 
849  ss_sleep(10); // in order to keep the frontend CPU load low
850 
851  hv_nhq_20xm_mscb_check_status(info, channel); // check status
852 
853  *pvalue = info->data.u[channel];
854 
855  if (info->err == NHQ_MAX_ALLOWED_ERR) {
856  cm_msg(MERROR, "hv_nhq_20xm_mscb_get",
857  "hv_nhq_20xm_mscb_get: Too many read back errors. Probably a communication problem.");
858  }
859 
860  return FE_SUCCESS;
861 }
862 
863 //----------------------------------------------------------------------------
873 INT hv_nhq_20xm_mscb_get_demand(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
874 {
875  // check if there have been any startup errors
876  if (info->startup_error) {
877  *pvalue = -999.f;
878  ss_sleep(10); // to keep CPU load low when Run active
879  return FE_SUCCESS;
880  }
881 
882  // return demand HV
883  *pvalue = info->data.d[channel];
884 
885  return FE_SUCCESS;
886 }
887 
888 //----------------------------------------------------------------------------
898 INT hv_nhq_20xm_mscb_get_current(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
899 {
900 
901  // check if there have been any startup errors
902  if (info->startup_error) {
903  *pvalue = -999.f;
904  ss_sleep(10); // to keep CPU load low when Run active
905  return FE_SUCCESS;
906  }
907 
908  if (info->data.i[channel]<1.0)
909  *pvalue = info->data.i[channel];
910 
911  return FE_SUCCESS;
912 }
913 
914 //----------------------------------------------------------------------------
915 //---- device driver entry point ---------------------------------------------
916 //----------------------------------------------------------------------------
917 INT hv_nhq_20xm_mscb(INT cmd, ...)
918 {
919 va_list argptr;
920 HNDLE hKey;
921 INT channel, status;
922 float value, *pvalue;
923 void *info, *bd;
924 char *name;
925 DWORD flags;
926 
927  va_start(argptr, cmd);
928  status = FE_SUCCESS;
929 
930  switch (cmd)
931  {
932  case CMD_INIT:
933  hKey = va_arg(argptr, HNDLE);
934  info = va_arg(argptr, void *);
935  channel = va_arg(argptr, INT);
936  flags = va_arg(argptr, DWORD);
937  bd = va_arg(argptr, void *);
938  status = hv_nhq_20xm_mscb_init(hKey, info, channel, bd);
939  break;
940 
941  case CMD_EXIT:
942  info = va_arg(argptr, void *);
943  status = hv_nhq_20xm_mscb_exit(info);
944  break;
945 
946  case CMD_SET:
947  info = va_arg(argptr, void *);
948  channel = va_arg(argptr, INT);
949  value = (float) va_arg(argptr, double);
950  status = hv_nhq_20xm_mscb_set(info, channel, value);
951  break;
952 
953  case CMD_GET:
954  info = va_arg(argptr, void *);
955  channel = va_arg(argptr, INT);
956  pvalue = va_arg(argptr, float*);
957  status = hv_nhq_20xm_mscb_get(info, channel, pvalue);
958  break;
959 
960  case CMD_GET_DEMAND:
961  info = va_arg(argptr, void *);
962  channel = va_arg(argptr, INT);
963  pvalue = va_arg(argptr, float*);
964  status = hv_nhq_20xm_mscb_get_demand(info, channel, pvalue);
965  break;
966 
967  case CMD_GET_LABEL:
968  info = va_arg(argptr, void *);
969  channel = va_arg(argptr, INT);
970  name = va_arg(argptr, char *);
971  status = hv_nhq_20xm_mscb_get_label(info, channel, name);
972  break;
973 
974  case CMD_GET_CURRENT:
975  info = va_arg(argptr, void *);
976  channel = va_arg(argptr, INT);
977  pvalue = va_arg(argptr, float*);
978  status = hv_nhq_20xm_mscb_get_current(info, channel, pvalue);
979  break;
980 
981 
982  // this are known commands of the class driver but not implmented yet or not needed
983  case CMD_SET_TRIP_TIME:
984  case CMD_SET_CURRENT_LIMIT:
985  case CMD_SET_RAMPUP:
986  case CMD_SET_RAMPDOWN:
987  case CMD_SET_VOLTAGE_LIMIT:
988  case CMD_GET_VOLTAGE_LIMIT:
989  case CMD_SET_LABEL:
990  case CMD_GET_THRESHOLD:
991  case CMD_GET_THRESHOLD_CURRENT:
992  case CMD_GET_CURRENT_LIMIT:
993  case CMD_GET_TRIP_TIME:
994  case CMD_GET_RAMPUP:
995  case CMD_GET_RAMPDOWN:
996  case CMD_STOP:
997  break;
998 
999  default:
1000  break;
1001  }
1002 
1003  va_end(argptr);
1004 
1005  return status;
1006 }
1007 
1008 //----------------------------------------------------------------------------
1009 // end -----------------------------------------------------------------------
1010 //----------------------------------------------------------------------------
#define NHQ_S
get channel status command tag for the scs210_nhq_m2xm
#define NHQ_ID
get id command tag for the scs210_nhq_m2xm
float voltage_limit[NHQ_NO_CHS]
voltage limit in (kV)
void hv_nhq_20xm_mscb_check_status(HV_NHQ_20XM_INFO *info, int ch)
int num_channels
number of channels
#define NHQ_N
get current command tag for the scs210_nhq_m2xm
INT group_addr
group address within the MSCB
#define NHQ_TRP
nhq tag indicating that hv channel has triped
#define NHQ_CMD_D
set demand voltage command tag for the scs210_nhq_m2xm
BOOL debug
if debug flag is on, the read data will be dumped into a file
#define NHQ_MAX_INIT_LOOP
how often mscb_info is called before an startup error is generated
INT hv_nhq_20xm_mscb_exit(HV_NHQ_20XM_INFO *info)
char port[NAME_LENGTH]
MSCB port, e.g. /dev/parport0.
#define NHQ_ON
nhq tag indicating that hv channel is switched on
int t[2]
device status tag
float current_limit[NHQ_NO_CHS]
current limit in (mA)
INT hv_nhq_20xm_mscb(INT cmd,...)
INT hv_nhq_20xm_mscb_init(HNDLE hKey, void **pinfo, INT channels, INT(*bd)(INT cmd,...))
#define NHQ_INH
nhq tag indicating that hv channel inhibit signal fired
int rebooting
flag indicating if NHQ is just rebooting
#define NHQ_T
get device status command tag for the scs210_nhq_m2xm
#define NHQ_A
get auto start command tag for the scs210_nhq_m2xm
float u[2]
measured voltage (kV)
HV_NHQ_20XM_SETTINGS settings
device specifc settings
INT hv_nhq_20xm_mscb_get_current(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
int fd
mscb device descriptor
static INT offset
char device_name[NAME_LENGTH]
name of the device as will be shown in MIDAS
#define NHQ_MAX_ALLOWED_ERR
maximal allowed tolerable errors
int wait_time
wait time between send and echo
int l[2]
current trip value (0 -&gt; no current trip)
#define NHQ_V
get ramping speed command tag for the scs210_nhq_m2xm
char pwd[NAME_LENGTH]
MSCB ethernet password.
#define NHQ_WAITTIME
get wait time command tag for the scs210_nhq_m2xm
INT node_addr
node address within the MSCB
float update_threshold_measured[NHQ_NO_CHS]
update threshold for the high voltage in (kV)
BOOL enabled
flag telling if the device is enabled
#define NHQ_D
get demand voltage command tag for the scs210_nhq_m2xm
int ch_status[NHQ_NO_CHS]
channel status tag
int reboot_time[2]
reboot time structure
INFO info
Definition: analyzer.cxx:94
#define NHQ_M
get voltage limit command tag for the scs210_nhq_m2xm
char reboot_time[NAME_LENGTH]
reboot time string hh:mm, if invalid no reboot will take place
#define NHQ_ERR
nhq tag indicating that hv channel exceeded either max. HV or max. current
#define NHQ_OFF
nhq tag indicating that hv channel is switched off
int ch_pol[NHQ_NO_CHS]
channel polarity
int odb_offset
ODB offset.
int err
global readback error counter
char ch_names[NHQ_NO_CHS][NAME_LENGTH]
name of the channels as will be shown in MIDAS
int hv_nhq_20xm_mscb_get_all(HV_NHQ_20XM_INFO *info, BOOL read_all)
INT hv_nhq_20xm_mscb_get(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
int hv_nhq_20xm_mscb_set_ramping(HV_NHQ_20XM_INFO *info, INT channels)
INT hv_nhq_20xm_mscb_update_odb(HV_NHQ_20XM_INFO *info, int channels)
#define NHQ_I
get current command tag for the scs210_nhq_m2xm
INT startup_error
startup error flag
#define NHQ_U
get measured high voltage command tag for the scs210_nhq_m2xm
INT hv_nhq_20xm_mscb_get_demand(HV_NHQ_20XM_INFO *info, INT channel, float *pvalue)
int m[2]
voltage limit in (%) of the maximal voltage
DWORD timer
cyclic timer to read channels
float update_threshold_current[NHQ_NO_CHS]
update threshild for the current in (mA)
INT hv_nhq_20xm_mscb_get_label(HV_NHQ_20XM_INFO *info, INT channel, char *name)
float max_current
maximal current of the high voltage module
HNDLE hKey
int a[2]
autostart flag
#define HV_NHQ_20XM_SETTINGS_STR
Init ODB string for the HV_NHQ_20XM_SETTINGS. Used if the DD entry doesn&#39;t exist yet.
char id[32]
device id
#define NHQ_DEBUG
debug flag
#define NHQ_MAN
nhq tag indicating that hv channel is switched to manual
float max_voltage
maximal high voltage of the module
MSCB_NODE_VARS data
data read back from NHQ
#define NHQ_QUA
nhq tag indicating that hv channel output HV quality is not guaranteed at the moment ...
#define NHQ_POL_POS
status flag showing that the nhq channel has positive polarization
HNDLE hDB
ODB main key.
float v[2]
ramping speed in (kV/s)
void hv_nhq_20xm_mscb_get_reboot_time(HV_NHQ_20XM_INFO *info)
int n[2]
current limit in (%) of the maximal current
char s[2][8]
status tag
#define NHQ_CMD_V
set ramping speed command tag for the scs210_nhq_m2xm
HNDLE hDB
HNDLE dd_hkey
ODB key to the device driver info.
INT hv_nhq_20xm_mscb_set(HV_NHQ_20XM_INFO *info, INT channel, float value)
#define NHQ_L
get current trip level command tag for the scs210_nhq_m2xm
float d[2]
demand voltage (kV)
#define NHQ_NO_CHS
number of HV channels of the NHQ
float i[2]
measured current (mA)