Low-Energy Muon (LEM) Experiment  0.5.1
bronkhorst.c
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: bronkhorst.c
4  Created by: Andreas Suter 2003/09/12
5 
6  Contents: device driver for Bronkhorst He gas flowcontroller,
7  defined as a multi class device.
8 
9  RS232: 38400 baud, 8 data bits, 1 stop bit, no parity bit,
10  protocol: no flow control, termination \r\n (CR\LF)
11 
12  device driver: Naming of the input and output channels in "../Settings/Names Input" and
13  "../Settings/Names Ouput". The channel names are defined in the device driver
14  settings key ("../Settings/Device/<Name of Device>/DD").
15 
16 \********************************************************************/
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <string.h>
22 
23 #include "midas.h"
24 #include "msystem.h"
25 
26 #include "bronkhorst.h"
27 
28 #include "ets_logout.h"
29 #include "lemSCWatchdog.h"
30 
31 /*---- globals -----------------------------------------------------*/
32 
34 #define BH_TIME_OUT 2000
35 
37 #define BH_RECONNECTION_TIMEOUT 5
38 #define BH_MAX_READBACK_FAILURE 5
40 #define BH_MAX_RECONNECTION_FAILURE 5
42 
43 /* --------- to handle error messages ------------------------------*/
44 #define BH_MAX_ERROR 10
45 #define BH_DELTA_TIME_ERROR 3600
46 
47 #define BH_WAIT 500
48 
49 #define BH_CMD_ERROR -3
50 #define BH_INIT_ERROR -2
51 #define BH_READ_ERROR -1
52 
53 #define BH_ETS_LOGOUT_SLEEP 10000
55 
56 /* --------- Bronkhorst stuff --------------------------------------*/
57 
64 #define BH_SUCCESS 1
65 
66 #ifndef DOXYGEN_SHOULD_SKIP_THIS
67 
68 #define BH_CMD_UNKNOWN 2
69 #define BH_COMM_ERR 3
70 #define BH_STATUS_ERR 4
71 #define BH_DECODE_ERR 5
72 
73 // bronkhorst commands
74 #define BH_NO_CMD -1
75 #define BH_IDENTSTRNG 1
76 #define BH_MEASURE 8
77 #define BH_SETPOINT 9
78 #define BH_SETSLOPE 10
79 #define BH_CNTRLMODE 12
80 #define BH_POLYCNSTA 13
81 #define BH_POLYCNSTB 14
82 #define BH_POLYCNSTC 15
83 #define BH_POLYCNSTD 16
84 #define BH_POLYCNSTE 17
85 #define BH_POLYCNSTF 18
86 #define BH_POLYCNSTG 19
87 #define BH_POLYCNSTH 20
88 #define BH_CAPACITY 21
89 #define BH_SENSORTYPE 22
90 #define BH_CAPUNIT 23
91 #define BH_FLUIDNR 24
92 #define BH_FLUIDNAME 25
93 #define BH_ALARMINFO 28
94 #define BH_ALARMMSGTA 33
95 #define BH_ALARMMSGNR 34
96 #define BH_VALVEOUT 55
97 #define BH_IOSTATUS 86
98 #define BH_DEVICETYPE 90
99 #define BH_MODELNUM 91
100 #define BH_SERIALNUM 92
101 #define BH_VERSION 105
102 #define BH_TEMPERATUR 142
103 #define BH_FLUIDTEMP 181
104 // etc, rest still missing
105 
106 // bronkhorst flowbus commands, addresses
107 #define BH_STATUSMSG 0
108 #define BH_SETPARAM 1
109 #define BH_GETPARAM 4
110 
111 #define BH_CHAR 0x00
112 #define BH_INTEGER 0x20
113 #define BH_LONG 0x40
114 #define BH_FLOAT 0x40
115 #define BH_STRING 0x60
116 
117 // bronkhorst status and error messages
118 #define BH_NOERROR 0x00
119 #define BH_PROCESS_CLAIMED 0x01
120 #define BH_CMD_ERR 0x02
121 #define BH_PROC_ERR 0x03
122 // etc, rest still missing
123 
124 // bronkhorst node
125 #define BH_NODE 0x80
126 
127 // bronkhorst chained
128 #define BH_UNCHAINED 0x00
129 #define BH_CHAINED 0x80
130 
131 // bronkhorst max needle valve value = 2^24 - 1
132 #define BH_MAX_NEEDLE_VALVE 16777215
133 
134 #define BH_IN_CHANNELS 2
135 #define BH_OUT_CHANNELS 2
136 
137 #endif // DOXYGEN_SHOULD_SKIP_THIS
138 
143 typedef struct {
147  char name[BH_IN_CHANNELS][32];
149 
154 typedef struct {
155  char name[BH_OUT_CHANNELS][32];
157 
159 #define BH_IN_SETTINGS_STR "\
160 Detailed Messages = INT : 0\n\
161 ETS_IN_USE = INT : 1\n\
162 SCW_IN_USE = INT : 0\n\
163 Input = STRING[2]:\n\
164 [32] BH Flow measured\n\
165 [32] BH ValvePos Get\n\
166 "
167 
169 #define BH_OUT_SETTINGS_STR "\
170 Output = STRING[2] :\n\
171 [32] BH Flow setpoint\n\
172 [32] BH ValvePos Set\n\
173 "
174 
176 #define BH_SCW_STR "\
177 Proc Name = STRING : [32]\n\
178 PID = INT : -1\n\
179 Log Name = STRING : [64]\n\
180 DD Name = STRING : [32] bronkhorst\n\
181 Last Updated = DWORD : 0\n\
182 Timeout = DWORD : 180\n\
183 "
184 
188 typedef struct {
191  LEM_SC_WATCHDOG scw;
192  HNDLE hkey;
195  INT (*bd)(INT cmd, ...);
196  void *bd_info;
201  DWORD lasterrtime;
203  float last_valid_value[2];
207 } BH_INFO;
208 
210 
211 /*---- support routines ------------------------------------------------------------*/
212 
213 /*----------------------------------------------------------------------------------*/
223 int bh_success(char *str, char *error_msg)
224 {
225  int error = 0;
226  int error_byte = 0;
227 
228  strcpy(error_msg, ""); // initialize error message
229 
230  if (strstr(str, ":01")) { // error message
231  sscanf(str, ":01%02d", &error);
232  switch (error) {
233  case 1:
234  strcpy(error_msg, "BH ERROR: no ':' at the start of the message.");
235  break;
236  case 2:
237  strcpy(error_msg, "BH ERROR: error in 1st byte.");
238  break;
239  case 3:
240  strcpy(error_msg, "BH ERROR: error in 2nd byte or number of bytes is 0 or message to long.");
241  break;
242  case 4:
243  strcpy(error_msg, "BH ERROR: error in recieved message (reciever overrun, framing error, etc.).");
244  break;
245  case 5:
246  strcpy(error_msg, "BH ERROR: flowbus communication BH ERROR: timeout or message rejected by reciver.");
247  break;
248  case 8:
249  strcpy(error_msg, "BH ERROR: timeout during sending.");
250  break;
251  case 9:
252  strcpy(error_msg, "BH ERROR: no answer recieved within timeout.");
253  break;
254  default:
255  strcpy(error_msg, "BH ERROR: unknown error, obscure.");
256  break;
257  } // end switch
258  } // end if
259 
260  if (strstr(str, ":04")) { // status error messages
261  sscanf(str, ":048000%02d%02d", &error, &error_byte);
262  switch (error) {
263  case 0x00:
264  break;
265  case 0x01:
266  sprintf(error_msg, "BH ERROR: process claimed. claimed process = %x\n", error_byte);
267  break;
268  case 0x02:
269  sprintf(error_msg, "BH ERROR: command error. error_byte = %d\n", error_byte);
270  break;
271  case 0x03:
272  sprintf(error_msg, "BH ERROR: process error. error_byte = %d\n", error_byte);
273  break;
274  case 0x04:
275  sprintf(error_msg, "BH ERROR: parameter error. error_byte = %d\n", error_byte);
276  break;
277  case 0x05:
278  sprintf(error_msg, "BH ERROR: parameter type error. error_byte = %d\n", error_byte);
279  break;
280  case 0x06:
281  sprintf(error_msg, "BH ERROR: parameter value error. error_byte = %d\n", error_byte);
282  break;
283  case 0x07:
284  sprintf(error_msg, "BH ERROR: network not active. error_byte = %d\n", error_byte);
285  break;
286  case 0x08:
287  sprintf(error_msg, "BH ERROR: timeout start character. error_byte = %d\n", error_byte);
288  break;
289  case 0x09:
290  sprintf(error_msg, "BH ERROR: timeout serial line. error_byte = %d\n", error_byte);
291  break;
292  case 0x0A:
293  sprintf(error_msg, "BH ERROR: hardware memory error. error_byte = %d\n", error_byte);
294  break;
295  case 0x0B:
296  sprintf(error_msg, "BH ERROR: node number error. error_byte = %d\n", error_byte);
297  break;
298  case 0x0C:
299  sprintf(error_msg, "BH ERROR: general communication error. error_byte = %d\n", error_byte);
300  break;
301  case 0x0D:
302  sprintf(error_msg, "BH ERROR: read only parameter. error_byte = %d\n", error_byte);
303  break;
304  case 0x0E:
305  sprintf(error_msg, "BH ERROR: error pc-communication. error_byte = %d\n", error_byte);
306  break;
307  case 0x0F:
308  sprintf(error_msg, "BH ERROR: no rs232 connection. error_byte = %d\n", error_byte);
309  break;
310  case 0x10:
311  sprintf(error_msg, "BH ERROR: pc out of memory. error_byte = %d\n", error_byte);
312  break;
313  case 0x11:
314  sprintf(error_msg, "BH ERROR: write only parameter. error_byte = %d\n", error_byte);
315  break;
316  case 0x12:
317  sprintf(error_msg, "BH ERROR: system configuration unknown. error_byte = %d\n", error_byte);
318  break;
319  case 0x13:
320  sprintf(error_msg, "BH ERROR: no free node address. error_byte = %d\n", error_byte);
321  break;
322  case 0x14:
323  sprintf(error_msg, "BH ERROR: wrong interface type. error_byte = %d\n", error_byte);
324  break;
325  case 0x15:
326  sprintf(error_msg, "BH ERROR: error serial port connection. error_byte = %d\n", error_byte);
327  break;
328  case 0x16:
329  sprintf(error_msg, "BH ERROR: error opening communication. error_byte = %d\n", error_byte);
330  break;
331  case 0x17:
332  sprintf(error_msg, "BH ERROR: communication error. error_byte = %d\n", error_byte);
333  break;
334  case 0x18:
335  sprintf(error_msg, "BH ERROR: error interface bus master. error_byte = %d\n", error_byte);
336  break;
337  case 0x19:
338  sprintf(error_msg, "BH ERROR: timeout answer. error_byte = %d\n", error_byte);
339  break;
340  case 0x1A:
341  sprintf(error_msg, "BH ERROR: no start character. error_byte = %d\n", error_byte);
342  break;
343  case 0x1B:
344  sprintf(error_msg, "BH ERROR: error first digit. error_byte = %d\n", error_byte);
345  break;
346  case 0x1C:
347  sprintf(error_msg, "BH ERROR: buffer overflow in host. error_byte = %d\n", error_byte);
348  break;
349  case 0x1D:
350  sprintf(error_msg, "BH ERROR: buffer overflow. error_byte = %d\n", error_byte);
351  break;
352  case 0x1E:
353  sprintf(error_msg, "BH ERROR: no answer found. error_byte = %d\n", error_byte);
354  break;
355  case 0x1F:
356  sprintf(error_msg, "BH ERROR: error closing communication. error_byte = %d\n", error_byte);
357  break;
358  case 0x20:
359  sprintf(error_msg, "BH ERROR: synchronization error. error_byte = %d\n", error_byte);
360  break;
361  case 0x21:
362  sprintf(error_msg, "BH ERROR: send error. error_byte = %d\n", error_byte);
363  break;
364  case 0x22:
365  sprintf(error_msg, "BH ERROR: protocol error. error_byte = %d\n", error_byte);
366  break;
367  case 0x23:
368  sprintf(error_msg, "BH ERROR: buffer overflow in module. error_byte = %d\n", error_byte);
369  break;
370  default:
371  sprintf(error_msg, "BH ERROR: unknown error, obscure. error_byte = %d\n", error_byte);
372  break;
373  } // end switch
374  } // end if
375 
376  if (strlen(error_msg)>0)
377  return BH_STATUS_ERR;
378  else
379  return BH_SUCCESS;
380 }
381 
382 /*----------------------------------------------------------------------------------*/
390 void hex2ascii(char *str, int len, char *result)
391 {
392  int i, j;
393  char hexchar[3];
394 
395  strcpy(result, "");
396  for (i=0; i<len; i++) {
397  strncpy(hexchar, str+2*i, 2);
398  hexchar[2]='\0';
399  sscanf(hexchar, "%x", &j);
400  strcat(result, (const char *)&j);
401  }
402 }
403 
404 
405 /*----------------------------------------------------------------------------------*/
418 int bh_decode_number(char *rply, int decode_tag, char *err_msg, float *result)
419 {
420  int totlen, len;
421  int ivalue;
422  char str[128];
423  union {
424  int ival;
425  float fval;
426  } hexfloat;
427 
428  totlen = strlen(rply);
429  if (totlen == 0) { // no input string
430  strcpy(err_msg, "BH ERROR: no string to decode ...");
431  return BH_DECODE_ERR;
432  }
433 
434  switch (decode_tag) {
435  case BH_CHAR:
436  case BH_INTEGER:
437  sscanf(rply, ":%02x%s", &len, str);
438  if (totlen != 2*len+5) {
439  strcpy(err_msg, "BH ERROR: wrong string length ...");
440  return BH_DECODE_ERR;
441  }
442  sscanf(rply, ":%10x%x", &len, &ivalue);
443  *result = (float)ivalue;
444  break;
445  case BH_FLOAT:
446  sscanf(rply, ":%02x%s", &len, str);
447  if (totlen != 2*len+5) {
448  strcpy(err_msg, "BH ERROR: wrong string length ...");
449  return BH_DECODE_ERR;
450  }
451  sscanf(rply, ":%10x%x", &len, &(hexfloat.ival));
452  *result = hexfloat.fval;
453  break;
454  default:
455  break;
456  }
457  return BH_SUCCESS;
458 }
459 
460 /*----------------------------------------------------------------------------------*/
472 int bh_decode_string(char *rply, char *err_msg, char *result)
473 {
474  int totlen, len;
475  int ivalue;
476  char str[128];
477 
478  totlen = strlen(rply);
479  if (totlen == 0) { // no string to decode
480  strcpy(err_msg, "BH ERROR: no string to decode ...");
481  return BH_DECODE_ERR;
482  }
483 
484  sscanf(rply, ":%02x%s", &len, str);
485  if (totlen != 2*len+5) {
486  strcpy(err_msg, "BH ERROR: wrong string length ...");
487  return BH_DECODE_ERR;
488  }
489  sscanf(rply, ":%10x%02x%s", &ivalue, &len, str);
490  hex2ascii(str, len, result);
491 
492  return BH_SUCCESS;
493 }
494 
495 /*----------------------------------------------------------------------------------*/
505 INT bh_get_send_rcv(BH_INFO *info, INT cmd, char *result)
506 {
507  char str[128], err_msg[128];
508  int status;
509  int cmd_length, process, parameter, decode_tag;
510 
511  // filter command and generate command string for device
512  switch (cmd) {
513  case BH_IDENTSTRNG:
514  cmd_length = 7;
515  process = 0;
516  parameter = 0;
517  decode_tag = BH_STRING;
518  sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X%02X\r\n",
519  cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
520  BH_UNCHAINED|BH_STRING, process, BH_STRING|parameter, 12);
521  break;
522  case BH_MEASURE:
523  cmd_length = 6;
524  process = 1;
525  parameter = 0;
526  decode_tag = BH_INTEGER;
527  sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X\r\n",
528  cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
529  BH_UNCHAINED|BH_INTEGER, process, BH_INTEGER|parameter);
530  break;
531  case BH_SETPOINT:
532  cmd_length = 6;
533  process = 1;
534  parameter = 1;
535  decode_tag = BH_INTEGER;
536  sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X\r\n",
537  cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
538  BH_UNCHAINED|BH_LONG, process, BH_LONG|parameter);
539  break;
540  case BH_VALVEOUT:
541  cmd_length = 6;
542  process = 114;
543  parameter = 1;
544  decode_tag = BH_INTEGER;
545  sprintf(str, ":%02X%02X%02X%02X%02X%02X%02X\r\n",
546  cmd_length, BH_NODE, BH_GETPARAM, BH_UNCHAINED|process,
547  BH_UNCHAINED|BH_LONG, process, BH_LONG|parameter);
548  break;
549  default:
550  return BH_CMD_UNKNOWN;
551  break;
552  }
553 
554  // send command to device
555  BD_PUTS(str);
556  // read back response from device
557  status = BD_GETS(str, sizeof(str), "\r\n", BH_TIME_OUT);
558  strcpy(result, str);
559 
560  if (!status) { // no response
561  if ( info->errorcount < BH_MAX_ERROR ) {
562  if (info->bh_in_settings.detailed_msg)
563  cm_msg(MERROR, "bh_get_send_rcv", "Communication error with bronkhorst flowcontroller.");
564  info->errorcount++;
565  }
566  return BH_COMM_ERR;
567  }
568 
569  // check for errors
570  if (!bh_success(str, err_msg)) {
571  if ( info->errorcount < BH_MAX_ERROR ) {
572  if (info->bh_in_settings.detailed_msg)
573  cm_msg(MERROR, "bh_get_send_rcv", "%s", err_msg);
574  info->errorcount++;
575  }
576  return BH_COMM_ERR;
577  }
578 
579  return BH_SUCCESS;
580 }
581 
582 /*----------------------------------------------------------------------------------*/
593 INT bh_set_send_rcv(BH_INFO *info, INT cmd, float value)
594 {
595  char str[128], err_msg[128];
596  int status;
597  int cmd_length, process, parameter, decode_tag;
598 
599  // filter command and generate command string for device
600  switch (cmd) {
601  case BH_SETPOINT:
602  cmd_length = 6;
603  process = 1;
604  parameter = 1;
605  decode_tag = BH_INTEGER;
606  sprintf(str, ":%02X%02X%02X%02X%02X%04X\r\n",
607  cmd_length, BH_NODE, BH_SETPARAM, BH_UNCHAINED|process,
608  BH_UNCHAINED|BH_INTEGER|parameter, (int)value);
609  break;
610  case BH_VALVEOUT:
611  if (value >= 0) { // if value < 0 do nothing!!
612  cmd_length = 8;
613  process = 114;
614  parameter = 1;
615  decode_tag = BH_INTEGER;
616  sprintf(str, ":%02X%02X%02X%02X%02X%08X\r\n",
617  cmd_length, BH_NODE, BH_SETPARAM, BH_UNCHAINED|process,
618  BH_UNCHAINED|BH_LONG|parameter, value*BH_MAX_NEEDLE_VALVE);
619  } else {
620  return BH_SUCCESS;
621  }
622  break;
623  default:
624  return BH_CMD_UNKNOWN;
625  break;
626  }
627 
628  // send command to device
629  BD_PUTS(str);
630  // read back response from device
631  status = BD_GETS(str, sizeof(str), "\r\n", BH_TIME_OUT);
632 
633  if (!status) { // no response
634  if ( info->errorcount < BH_MAX_ERROR ) {
635  if (info->bh_in_settings.detailed_msg)
636  cm_msg(MERROR, "bh_set_send_rcv", "Communication error with bronkhorst flowcontroller.");
637  info->errorcount++;
638  }
639  return BH_COMM_ERR;
640  }
641 
642  // decode return string and check for errors
643  if (!bh_success(str, err_msg)) {
644  if ( info->errorcount < BH_MAX_ERROR ) {
645  if (info->bh_in_settings.detailed_msg)
646  cm_msg(MERROR, "bh_set_send_rcv", "%s", err_msg);
647  info->errorcount++;
648  }
649  return BH_COMM_ERR;
650  }
651 
652  return BH_SUCCESS;
653 }
654 
655 /*----------------------------------------------------------------------------------*/
663 INT bh_get_cmd(char *str, int *decode_tag)
664 {
665  int cmd=BH_NO_CMD;
666 
667  if (strstr(str,"measured")) {
668  cmd = BH_MEASURE;
669  *decode_tag = BH_INTEGER;
670  }
671  if (strstr(str,"setpoint")) {
672  cmd = BH_SETPOINT;
673  *decode_tag = BH_INTEGER;
674  }
675  if (strstr(str,"fluidtemp")) {
676  cmd = BH_FLUIDTEMP;
677  *decode_tag = BH_INTEGER;
678  }
679  if (strstr(str, "ValvePos")) {
680  cmd = BH_VALVEOUT;
681  *decode_tag = BH_INTEGER;
682  }
683 
684  return cmd;
685 }
686 
687 /*---- device driver routines ---------------------------------------------------------*/
700 INT bh_in_init(HNDLE hKey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
701 {
702  INT status, size, chno;
703  INT cmd;
704  HNDLE hDB, hkeydd;
705  char bh_id[128], result[128], err_msg[128];
706 
707  cm_get_experiment_database(&hDB, NULL);
708 
709  // allocate info structure
710  info = calloc(1, sizeof(BH_INFO));
711  *pinfo = info;
712 
713  // create BH settings record
714  status = db_create_record(hDB, hKey, "DD/BH", BH_IN_SETTINGS_STR);
715  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
716  cm_msg(MERROR, "bh_in_init", "bh_in_init: Couldn't create DD/BH in ODB: status=%d", status);
717  cm_yield(0);
718  return FE_ERR_ODB;
719  }
720 
721  // create BH slowcontrol watchdog DD settings
722  status = db_create_record(hDB, hKey, "DD/SCW", BH_SCW_STR);
723  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
724  cm_msg(MERROR, "bh_in_init", "bh_in_init: Couldn't create DD/SCW in ODB: status=%d", status);
725  cm_yield(0);
726  return FE_ERR_ODB;
727  }
728 
729  // copy DD entries into the info structure
730  db_find_key(hDB, hKey, "DD/BH", &hkeydd);
731  db_open_record(hDB, hkeydd, &info->bh_in_settings, sizeof(info->bh_in_settings), MODE_READ, NULL, NULL);
732 
733  /* initialize driver */
734  info->hkey = hKey;
735  info->num_channels_in = channels;
736  info->bd = bd;
737  info->errorcount = 0;
738  info->lasterrtime = ss_time();
739  info->startup_error = 0;
740  info->readback_failure = 0;
741  info->last_reconnect = ss_time();
742  info->reconnection_failures = 0;
743  info->first_bd_error = 1;
744  info->startup_tag = 0;
745 
746  if ( info->num_channels_in > BH_IN_CHANNELS ) {
747  chno = BH_IN_CHANNELS;
748  cm_msg(MERROR,"BH_in_init", "Error, max. number of BH input channels is %d, not %d.", chno, info->num_channels_in);
749  cm_yield(0);
750  info->startup_error = 1;
751  return FE_SUCCESS;
752  }
753 
754  if (!bd)
755  return FE_ERR_ODB;
756 
757  /* initialize bus driver */
758  status = info->bd(CMD_INIT, hKey, &info->bd_info);
759  if (status != FE_SUCCESS) {
760  info->startup_error = 1;
761  info->bd_connected = FALSE;
762  return FE_SUCCESS;
763  }
764  info->bd_connected = TRUE;
765 
766  /* initialize BH */
767  cmd = BH_IDENTSTRNG;
768  status = bh_get_send_rcv(info, cmd, result);
769 
770  if ( status != BH_SUCCESS ) { // error occurred
771  cm_msg(MERROR,"BH_in_init", "Error getting device query from BH, %s",info->bh_in_settings.name[0]);
772  cm_yield(0);
773  info->startup_error = 1;
774  return FE_SUCCESS;//FE_ERR_HW;
775  }
776 
777  if (bh_decode_string(result, err_msg, bh_id) != BH_SUCCESS) {
778  cm_msg(MERROR,"BH_in_init", "%s", err_msg);
779  cm_yield(0);
780  info->startup_error = 1;
781  return FE_SUCCESS;
782  }
783 
784  cm_msg(MINFO,"BH_in_init", "Device query of BH yields %s", bh_id);
785  cm_yield(0);
786 
787  if (info->bh_in_settings.scw_in_use) { // slowcontrol watchdog shall be used
788  // register with the slowcontrol watchdog -------------------------------------
789  // find scw record in DD
790  db_find_key(hDB, hKey, "DD/SCW", &hkeydd);
791  // get record
792  size = sizeof(info->scw);
793  db_get_record(hDB, hkeydd, &info->scw, &size, 0);
794  // fill watchdog structure
795  info->scw.pid = ss_getpid();
796  info->scw.last_updated = ss_time();
797  // write info back into ODB
798  db_set_record(hDB, hkeydd, &info->scw, sizeof(info->scw), 0);
799 
800  // register with slowcontrol watchdog
801  status = lem_scw_init(&info->scw);
802  if (status != LEM_SCW_SUCCESS) {
803  cm_msg(MINFO, "bh_in_init", "Couldn't register with lem watchdog");
804  cm_yield(0);
805  }
806  }
807 
808  return FE_SUCCESS;
809 }
810 
811 /*----------------------------------------------------------------------------------*/
824 INT bh_out_init(HNDLE hKey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
825 {
826  INT status, chno;
827  HNDLE hDB, hkeydd;
828 
829  cm_get_experiment_database(&hDB, NULL);
830 
831  *pinfo = info;
832 
833  /* create BH settings record */
834  status = db_create_record(hDB, hKey, "DD", BH_OUT_SETTINGS_STR);
835  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
836  cm_msg(MERROR, "bh_out_init", "Couldn't create DD: status=%d", status);
837  return FE_ERR_ODB;
838  }
839 
840  // copy DD entries into the info structure
841  db_find_key(hDB, hKey, "DD", &hkeydd);
842  db_open_record(hDB, hkeydd, &info->bh_out_settings, sizeof(info->bh_out_settings), MODE_READ, NULL, NULL);
843 
844  /* initialize driver */
845  info->num_channels_out = channels;
846 
847  if ( info->num_channels_out != BH_OUT_CHANNELS ) {
848  chno = BH_OUT_CHANNELS;
849  cm_msg(MERROR,"bh_out_init", "Error, allowed number of BH output channels is %d, not %d.", chno, info->num_channels_out);
850  info->startup_error = 1;
851  return FE_ERR_HW;
852  }
853 
854  return FE_SUCCESS;
855 }
856 
857 /*----------------------------------------------------------------------------------*/
864 INT bh_exit(BH_INFO *info)
865 {
866  // call EXIT function of bus driver, usually closes device
867  info->bd(CMD_EXIT, info->bd_info);
868 
869  if (info->bh_in_settings.scw_in_use && !info->startup_error) { // slowcontrol watchdog in use
870  // deregister from the slowcontrol watchdog
871  lem_scw_exit(&info->scw);
872  }
873 
874  free(info);
875 
876  return FE_SUCCESS;
877 }
878 
879 /*----------------------------------------------------------------------------------*/
887 INT bh_set(BH_INFO *info, INT channel, float value)
888 {
889  int cmd, status, decode_tag;
890 
891  if (info->startup_error)
892  return FE_SUCCESS;
893 
894  if (!info->bd_connected) {
895  if (info->first_bd_error) {
896  info->first_bd_error = 0;
897  cm_msg(MINFO, "BH_set",
898  "BH_set: set values not possible at the moment, since the bus driver is not available!");
899  }
900  ss_sleep(10);
901  return FE_SUCCESS;
902  }
903 
904  // if dd is starting up, do not do anything!!
905  if (info->startup_tag < 2) {
906  info->startup_tag++;
907  return FE_SUCCESS;
908  }
909 
910  // get command and decode tag from the name
911  cmd = bh_get_cmd(info->bh_out_settings.name[channel], &decode_tag);
912 
913  // set value in the flowcontroller
914  status = bh_set_send_rcv(info, cmd, value);
915 
916  if (status != BH_SUCCESS) {
917  if ( info->errorcount < BH_MAX_ERROR ) {
918  if (info->bh_in_settings.detailed_msg)
919  cm_msg(MERROR, "BH_set", "BH communication or command error.");
920  info->errorcount++;
921  }
922  }
923 
924  return FE_SUCCESS;
925 }
926 
927 /*----------------------------------------------------------------------------------*/
935 INT bh_get(BH_INFO *info, INT channel, float *pvalue)
936 {
937  int cmd, status, decode_tag;
938  char str[128], err_msg[128];
939  DWORD nowtime, difftime;
940 
941  // error timeout facility
942  nowtime = ss_time();
943  difftime = nowtime - info->lasterrtime;
944  if ( difftime > BH_DELTA_TIME_ERROR ) {
945  info->errorcount = 0;
946  info->lasterrtime = ss_time();
947  }
948 
949  // check if there was a startup error
950  if ( info->startup_error ) {
951  *pvalue = (float) BH_INIT_ERROR;
952  ss_sleep(10); // to keep CPU load low when Run active
953  return FE_SUCCESS;
954  }
955 
956  // check if they where too many reconnection failures
958  *pvalue = (float) BH_READ_ERROR;
960  cm_msg(MERROR, "BH_get", "too many reconnection failures, bailing out :-(");
961  info->reconnection_failures++;
962  }
963  return FE_SUCCESS;
964  }
965 
966  if (info->bh_in_settings.scw_in_use) { // slowcontrol watchdog in use
967  // feed slowcontrol watchdog
968  info->scw.last_updated = ss_time();
969  lem_scw_update(&info->scw);
970  }
971 
972  // if disconnected, try to reconnect after the timeout expires
973  if (!info->bd_connected) {
974  if (ss_time()-info->last_reconnect > BH_RECONNECTION_TIMEOUT) { // timeout expired
975  if (info->bh_in_settings.detailed_msg)
976  cm_msg(MINFO, "BH_get", "Bronkhorst: reconnection trial ...");
977  status = info->bd(CMD_INIT, info->hkey, &info->bd_info);
978  if (status != FE_SUCCESS) {
979  info->reconnection_failures++;
980  *pvalue = (float) BH_READ_ERROR;
981  if (info->bh_in_settings.detailed_msg)
982  cm_msg(MINFO, "BH_get", "Bronkhorst: reconnection attempted failed");
983  return FE_ERR_HW;
984  } else {
985  info->bd_connected = 1; // bus driver is connected again
986  info->last_reconnect = ss_time();
987  info->reconnection_failures = 0;
988  info->first_bd_error = 1;
989  if (info->bh_in_settings.detailed_msg)
990  cm_msg(MINFO, "BH_get", "Bronkhorst: successfully reconnected");
991  }
992  } else { // timeout still running
993  *pvalue = info->last_valid_value[channel];
994  return FE_SUCCESS;
995  }
996  }
997 
998  // get command and decode tag from the name
999  cmd = bh_get_cmd(info->bh_in_settings.name[channel], &decode_tag);
1000  if (cmd == BH_NO_CMD) { // error
1001  *pvalue = BH_CMD_ERROR;
1002 
1003  return FE_SUCCESS;
1004  }
1005 
1006  // get value from the flowcontroller
1007  status = bh_get_send_rcv(info, cmd, str);
1008 
1009  if (status != BH_SUCCESS) {
1010  if ( info->errorcount < BH_MAX_ERROR ) {
1011  if (info->bh_in_settings.detailed_msg)
1012  cm_msg(MERROR, "BH_get", "BH communication or command error.");
1013  info->errorcount++;
1014  }
1015  info->readback_failure++;
1016 
1018  info->readback_failure = 0;
1019  // try to disconnect and reconnect the bus driver
1020  if ((ss_time()-info->last_reconnect > BH_RECONNECTION_TIMEOUT) && info->bd_connected) {
1021  info->bd(CMD_EXIT, info->bd_info); // disconnect bus driver
1022  if (info->bh_in_settings.detailed_msg)
1023  cm_msg(MINFO, "BH_get", "Bronkhorst: try to disconnect and reconnect the bus driver");
1024  info->last_reconnect = ss_time();
1025  info->bd_connected = 0;
1026  if (info->bh_in_settings.ets_in_use)
1028  }
1029  }
1030  return FE_SUCCESS;
1031  }
1032 
1033  // decode return hexcode string
1034  status = bh_decode_number(str, decode_tag, err_msg, pvalue);
1035 
1036  if (status != BH_SUCCESS) {
1037  if ( info->errorcount < BH_MAX_ERROR ) {
1038  if (info->bh_in_settings.detailed_msg)
1039  cm_msg(MERROR, "BH_get", "%s", err_msg);
1040  info->errorcount++;
1041  }
1042  }
1043 
1044  // rescale needle valve position from 0..2^24 - 1 to the intervall 0..1
1045  if (cmd == BH_VALVEOUT) {
1046  *pvalue /= BH_MAX_NEEDLE_VALVE;
1047  }
1048 
1049  info->last_valid_value[channel] = *pvalue;
1050  info->readback_failure = 0;
1051 
1052  ss_sleep(100);
1053 
1054  return FE_SUCCESS;
1055 }
1056 
1057 /*----------------------------------------------------------------------------------*/
1066 INT bh_in_get_label(BH_INFO *info, INT channel, char *name)
1067 {
1068  strcpy(name, info->bh_in_settings.name[channel]);
1069  return FE_SUCCESS;
1070 }
1071 
1072 /*----------------------------------------------------------------------------------*/
1081 INT bh_out_get_label(BH_INFO *info, INT channel, char *name)
1082 {
1083  strcpy(name, info->bh_out_settings.name[channel]);
1084  return FE_SUCCESS;
1085 }
1086 
1087 /*---- device driver entry point ---------------------------------------------------*/
1088 INT bh_flow_in(INT cmd, ...)
1089 {
1090 va_list argptr;
1091 HNDLE hKey;
1092 INT channel, status;
1093 float *pvalue;
1094 void *info, *bd;
1095 char *name;
1096 DWORD flags;
1097 
1098  va_start(argptr, cmd);
1099  status = FE_SUCCESS;
1100 
1101  switch (cmd)
1102  {
1103  case CMD_INIT:
1104  hKey = va_arg(argptr, HNDLE);
1105  info = va_arg(argptr, void *);
1106  channel = va_arg(argptr, INT);
1107  flags = va_arg(argptr, DWORD);
1108  bd = va_arg(argptr, void *);
1109  status = bh_in_init(hKey, info, channel, bd);
1110  break;
1111 
1112  case CMD_EXIT:
1113  info = va_arg(argptr, void *);
1114  status = bh_exit(info);
1115  break;
1116 
1117  case CMD_GET:
1118  info = va_arg(argptr, void *);
1119  channel = va_arg(argptr, INT);
1120  pvalue = va_arg(argptr, float*);
1121  status = bh_get(info, channel, pvalue);
1122  break;
1123 
1124  case CMD_GET_LABEL:
1125  info = va_arg(argptr, void *);
1126  channel = va_arg(argptr, INT);
1127  name = va_arg(argptr, char *);
1128  status = bh_in_get_label(info, channel, name);
1129  break;
1130 
1131  default:
1132  break;
1133  }
1134 
1135  va_end(argptr);
1136  return status;
1137 }
1138 
1139 /************************************************************************/
1140 
1141 INT bh_flow_out(INT cmd, ...)
1142 {
1143 va_list argptr;
1144 HNDLE hKey;
1145 INT channel, status;
1146 float value;
1147 void *info, *bd;
1148 char *name;
1149 DWORD flags;
1150 
1151  va_start(argptr, cmd);
1152  status = FE_SUCCESS;
1153 
1154  switch (cmd)
1155  {
1156  case CMD_INIT:
1157  hKey = va_arg(argptr, HNDLE);
1158  info = va_arg(argptr, void *);
1159  channel = va_arg(argptr, INT);
1160  flags = va_arg(argptr, DWORD);
1161  bd = va_arg(argptr, void *);
1162  status = bh_out_init(hKey, info, channel, bd);
1163  break;
1164 
1165  case CMD_SET:
1166  info = va_arg(argptr, void *);
1167  channel = va_arg(argptr, INT);
1168  value = (float) va_arg(argptr, double);
1169  status = bh_set(info, channel, value);
1170  break;
1171 
1172  case CMD_GET_LABEL:
1173  info = va_arg(argptr, void *);
1174  channel = va_arg(argptr, INT);
1175  name = va_arg(argptr, char *);
1176  status = bh_out_get_label(info, channel, name);
1177  break;
1178 
1179  default:
1180  break;
1181  }
1182 
1183  va_end(argptr);
1184 
1185  return status;
1186 }
1187 
1188 /*------------------------------------------------------------------*/
int bh_decode_number(char *rply, int decode_tag, char *err_msg, float *result)
Definition: bronkhorst.c:418
char name[BH_IN_CHANNELS][32]
input channel names
Definition: bronkhorst.c:147
#define BH_CMD_ERROR
unvalid command error
Definition: bronkhorst.c:49
#define BH_READ_ERROR
read error tag
Definition: bronkhorst.c:51
DWORD lasterrtime
timer for error handling
Definition: bronkhorst.c:201
INFO info
Definition: vme_fe.c:206
INT bh_out_init(HNDLE hKey, void **pinfo, INT channels, INT(*bd)(INT cmd,...))
Definition: bronkhorst.c:824
INT num_channels_in
number of in-channels
Definition: bronkhorst.c:193
#define BH_SUCCESS
Definition: bronkhorst.c:64
LEM_SC_WATCHDOG scw
slowcontrol watchdog info structure
Definition: bronkhorst.c:191
BH_IN_SETTINGS bh_in_settings
internal DD settings for the in-channels
Definition: bronkhorst.c:189
HNDLE hkey
ODB key for bus driver info.
Definition: bronkhorst.c:192
INT errorcount
error coutner
Definition: bronkhorst.c:199
int bh_success(char *str, char *error_msg)
Definition: bronkhorst.c:223
INT bh_out_get_label(BH_INFO *info, INT channel, char *name)
Definition: bronkhorst.c:1081
INT bh_set_send_rcv(BH_INFO *info, INT cmd, float value)
Definition: bronkhorst.c:593
INT bh_in_get_label(BH_INFO *info, INT channel, char *name)
Definition: bronkhorst.c:1066
INT detailed_msg
flag indicating if detailed status/error messages are wanted
Definition: bronkhorst.c:144
INT bh_get(BH_INFO *info, INT channel, float *pvalue)
Definition: bronkhorst.c:935
DWORD last_reconnect
timer for bus driver reconnect error handling
Definition: bronkhorst.c:204
#define BH_TIME_OUT
timeout in (ms) for the communication between pc and bronkhorst
Definition: bronkhorst.c:34
int ets_logout(void *info, int wait, int detailed_msg)
Definition: ets_logout.c:113
HNDLE hKey
Definition: write_summary.c:97
void * bd_info
private info of bus driver
Definition: bronkhorst.c:196
INT bh_set(BH_INFO *info, INT channel, float value)
Definition: bronkhorst.c:887
INT bh_in_init(HNDLE hKey, void **pinfo, INT channels, INT(*bd)(INT cmd,...))
Definition: bronkhorst.c:700
#define BH_DELTA_TIME_ERROR
reset error counter after BH_DELTA_TIME_ERROR seconds
Definition: bronkhorst.c:45
INT bh_exit(BH_INFO *info)
Definition: bronkhorst.c:864
float last_valid_value[2]
stores the last valid value
Definition: bronkhorst.c:203
INT startup_tag
tag indicating that the DD is starting (see bh_in_init and BH_out_init)
Definition: bronkhorst.c:206
INT startup_error
startup error tag; if set, the get and bh_set and bh_get routines wont do anything ...
Definition: bronkhorst.c:200
HNDLE hDB
Definition: write_summary.c:97
int bd_connected
flag showing if bus driver is connected
Definition: bronkhorst.c:197
#define BH_IN_SETTINGS_STR
initializing string for the BH_IN_SETTINGS structure.
Definition: bronkhorst.c:159
#define BH_MAX_ERROR
maximum number of error messages
Definition: bronkhorst.c:44
INT bh_flow_out(INT cmd,...)
Definition: bronkhorst.c:1141
INT readback_failure
counts the number of readback failures
Definition: bronkhorst.c:202
INT(* bd)(INT cmd,...)
bus driver entry function
Definition: bronkhorst.c:195
int first_bd_error
flag showing if the bus driver error message is already given
Definition: bronkhorst.c:198
BH_OUT_SETTINGS bh_out_settings
internal DD settings for the out-channels
Definition: bronkhorst.c:190
#define BH_INIT_ERROR
initialize error tag
Definition: bronkhorst.c:50
INT num_channels_out
number of out-channels
Definition: bronkhorst.c:194
#define BH_RECONNECTION_TIMEOUT
timeout in (sec) between logout terminal server an reconnection trial
Definition: bronkhorst.c:37
#define BH_SCW_STR
defines the slowcontrol default watchdog info structure
Definition: bronkhorst.c:176
#define BH_MAX_READBACK_FAILURE
maximum number of readback failures before a reconnect will take place
Definition: bronkhorst.c:39
INT scw_in_use
flag indicating if the slowcontrol watchdog shall be used
Definition: bronkhorst.c:146
char name[BH_OUT_CHANNELS][32]
output channel names
Definition: bronkhorst.c:155
INT bh_get_send_rcv(BH_INFO *info, INT cmd, char *result)
Definition: bronkhorst.c:505
#define BH_OUT_SETTINGS_STR
initializing string for the BH_OUT_SETTINGS structure.
Definition: bronkhorst.c:169
void hex2ascii(char *str, int len, char *result)
Definition: bronkhorst.c:390
#define BH_ETS_LOGOUT_SLEEP
sleep time (us) between the telnet commands of the ets_logout
Definition: bronkhorst.c:54
INT bh_flow_in(INT cmd,...)
Definition: bronkhorst.c:1088
int reconnection_failures
how often reconnection failed
Definition: bronkhorst.c:205
INT bh_get_cmd(char *str, int *decode_tag)
Definition: bronkhorst.c:663
int bh_decode_string(char *rply, char *err_msg, char *result)
Definition: bronkhorst.c:472
#define BH_MAX_RECONNECTION_FAILURE
maximum number of reconnections before bailing off
Definition: bronkhorst.c:41
INT ets_in_use
flag indicating if the rs232 terminal server is in use
Definition: bronkhorst.c:145