Low-Energy Muon (LEM) Experiment  0.5.1
west6100.c
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: west6100.c
4  Created by: Andreas Suter 2004/02/23
5 
6  Contents: device driver for 'West 6100' LHe flow controller for the
7  moderation cryostate 'Moddy', defined as a multi class device.
8 
9 \********************************************************************/
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <math.h>
16 #include "midas.h"
17 #include "west6100.h"
18 
19 #include "ets_logout.h"
20 
21 /*---- globals -----------------------------------------------------*/
22 
24 #define W6100_ETS_LOGOUT_SLEEP 10000
25 
27 #define W6100_MAX_READBACK_FAILURE 5
28 
30 #define W6100_TIME_OUT 1000
31 
32 /* --------- output commands --------------------------------------*/
33 #define W6100_SET_PRESSURE 1
34 #define W6100_P 2
35 #define W6100_I 3
36 #define W6100_D 4
37 #define W6100_CTRL_MODE 5
38 #define W6100_NEEDLE_VALVE_POS 6
39 #define W6100_UPPER_OUTPUT_LIMIT 7
40 
41 /* --------- to handle error messages -----------Detailed Status/Error Messages = INT : 0\n\
42 -------------------*/
43 #define W6100_MAX_ERROR 3
44 #define W6100_DELTA_TIME_ERROR 600
45 
46 #define W6100_READ_ERROR -1
47 #define W6100_INIT_ERROR -2
48 #define W6100_OUT_OF_RANGE -3
49 
50 #define W6100_IN_CHANNELS 7
51 #define W6100_OUT_CHANNELS 8
52 
53 typedef struct {
55  INT enabled;
57  INT ets_in_use;
58  INT odb_offset;
59  char odb_output[2*NAME_LENGTH];
60  char name[W6100_IN_CHANNELS][64];
62 
64 typedef struct {
65  char name[W6100_OUT_CHANNELS][64];
67 
69 #define W6100_IN_SETTINGS_STR "\
70 Enabled = INT : 1\n\
71 Detailed Messages = INT : 0\n\
72 ETS_IN_USE = INT : 1\n\
73 ODB Offset = INT : 0\n\
74 ODB Output Path = STRING : [64] /Equipment/ModCryo/Variables/Output\n\
75 Input = STRING[7] : \n\
76 [64] W6100 Pressure (mbar)\n\
77 [64] W6100 Set Point Pressure (mbar, readback)\n\
78 [64] W6100 Needle Valve (0=Open, 100=Close)\n\
79 [64] W6100 PID-Gain (P, readback)\n\
80 [64] W6100 PID-Reset (I, readback)\n\
81 [64] W6100 PID-Rate (D, readback)\n\
82 [64] W6100 Controller State\n\
83 "
84 
86 #define W6100_OUT_SETTINGS_STR "\
87 Output = STRING[8] : \n\
88 [64] W6100 REMOTE\n\
89 [64] W6100 Set Point Pressure (mbar)\n\
90 [64] W6100 PID-Gain (P)\n\
91 [64] W6100 PID-Reset (I)\n\
92 [64] W6100 PID-Rate (D)\n\
93 [64] W6100 Ctrl-Mode\n\
94 [64] W6100 Needle Valve Pos.\n\
95 [64] W6100 Upper Output Limit\n\
96 "
97 
99 typedef struct {
100  float low_limit;
101  float high_limit;
102  int ctrl;
104 } W6100_param;
105 
107 typedef struct {
110  HNDLE hkey;
114  INT (*bd)(INT cmd, ...);
115  void *bd_info;
116  INT remote;
119  DWORD lasterrtime;
124 } W6100_INFO;
125 
127 
128 /*---- support routines --------------------------------------------*/
139 void w6100_error(W6100_INFO *info, char *who, char *msg)
140 {
141  if (info->errorcount < W6100_MAX_ERROR) {
142  info->errorcount++;
143  cm_msg(MERROR, who, msg);
144  }
145 
146  if (ss_time()-info->lasterrtime>W6100_DELTA_TIME_ERROR) { // time to reset error counter and error timer
147  info->errorcount = 0;
148  info->lasterrtime = ss_time();
149  }
150 }
151 
152 /*----------------------------------------------------------------------------*/
162 float w6100_decode_data(char *code)
163 {
164  char str[8];
165  float sign=0.0f, power=0.0f, value;
166 
167  if (strlen(code)!=10) { // something is wrong
168  return (float)W6100_READ_ERROR;
169  }
170  // get sign and power
171  switch (code[7]) {
172  case 48: // '0'
173  sign = 1.f;
174  power = 1.f;
175  break;
176  case 49: // '1'
177  sign = 1.f;
178  power = 0.1f;
179  break;
180  case 50: // '2'
181  sign = 1.f;
182  power = 0.01f;
183  break;
184  case 51: // '3'
185  sign = 1.f;
186  power = 0.001f;
187  break;
188  case 53: // '5'
189  sign = -1.f;
190  power = 1.f;
191  break;
192  case 54: // '6'
193  sign = -1.f;
194  power = 0.1f;
195  break;
196  case 55: // '7'
197  sign = -1.f;
198  power = 0.01f;
199  break;
200  case 56: // '8'
201  sign = -1.f;
202  power = 0.001f;
203  break;
204  default:
205  break;
206  } // switch
207 
208  if (sign==0.0f) { // error
209  return (float)W6100_READ_ERROR;
210  }
211 
212  strncpy(str, &code[3], 4); // extract data sub string
213  sscanf(str, "%f", &value); // convert data sub string to a number
214 
215  return sign*power*value;
216 }
217 
218 /*----------------------------------------------------------------------------*/
235 int w6100_set_cmd(W6100_INFO *info, char *who, char *cmd, char *activate_cmd)
236 {
237  int status;
238  char str[16], rcv[16];
239  char msg[128];
240 
241  // send command and check for errors
242  BD_PUTS(cmd); // send command
243  status = BD_GETS(rcv, sizeof(rcv), "*", W6100_TIME_OUT); // get reply
244  if (!strstr(rcv,"L1")) { // something went wrong in the first step of the command transmission
245  sprintf(msg, "%s: 'West 6100' does not respond properly.", who);
246  w6100_error(info, who, msg);
247  return 0;
248  }
249  if (strstr(rcv,"N")) { // negative acknowledgement, i.e. controller doesn't accept command
250  sprintf(msg, "%s: '%s' negative acknowledgement, i.e. controller doesn't accept command", who, cmd);
251  w6100_error(info, who, msg);
252  return 0;
253  }
254 
255  // activate command
256  sprintf(str,"L1%sI*", activate_cmd);
257  BD_PUTS(str); // excute command just sent
258  status = BD_GETS(rcv, sizeof(rcv), "*", W6100_TIME_OUT); // get reply
259  if (!strstr(rcv,"L1")) { // something went wrong in the first step of the command transmission
260  sprintf(msg, "%s: 'West 6100' does not respond properly (2nd send, execution '%s').",
261  who, activate_cmd);
262  w6100_error(info, who, msg);
263  return 0;
264  }
265 
266  return 1;
267 }
268 
269 /*----------------------------------------------------------------------------*/
282 int w6100_get_value(W6100_INFO *info, char *who, char *cmd, char *rcv)
283 {
284  int status, i;
285  char str[16], msg[128];
286 
287  // send command and check for errors
288  i = 3;
289  while ( i>0 ){ // try 3 times
290  BD_PUTS(cmd); // send command
291  status = BD_GETS(str, sizeof(str), "*", W6100_TIME_OUT); // get reply
292  if (!strstr(str,"L1")){ // something went wrong in the first step of the command transmission
293  i--;
294  ss_sleep(1000); // wait one second before re-trying
295  }
296  else
297  break;
298  }
299  if ( i == 0 ){ // we got no correct reply in 3 attempts
300  sprintf(msg, "%s: 'West 6100' does not respond properly.", who);
301  w6100_error(info, who, msg);
302  return 0;
303  }
304 
305  if (strstr(str,"N")) { // negative acknowledgement, i.e. controller doesn't accept command
306  sprintf(msg, "%s: '%s' negative acknowledgement, i.e. controller doesn't accept command", who, cmd);
307  w6100_error(info, who, msg);
308  return 0;
309  }
310 
311  strcpy(rcv, str);
312 
313  return 1;
314 }
315 
316 /*----------------------------------------------------------------------------*/
325 void w6100_set_pressure(W6100_INFO *info, float value)
326 {
327  char str[16];
328 
329  // check if value is within the limits
330  if ((value > info->param.high_limit) || (value < info->param.low_limit)) {
331  cm_msg(MERROR, "W6100_set", "set point %f, not within limits (low=%f, high=%f).",
332  value, info->param.low_limit, info->param.high_limit);
333  return;
334  }
335 
336  // set pressure
337  sprintf(str,"L1S#%04d1*", (int)(10.f*value)); // generate command
338  w6100_set_cmd(info, "w6100_set_pressure", str, "S");
339 }
340 
341 /*----------------------------------------------------------------------------*/
348 void w6100_set_gain(W6100_INFO *info, float value)
349 {
350  char str[16];
351 
352  // check if value is within valid range
353  if ((value<0.f) || (value>999.9f)) {
354  cm_msg(MERROR, "W6100_set", "demanded gain (P) out of range [0.0, 999.9]");
355  return;
356  }
357 
358  sprintf(str,"L1P#%04d1*", (int)(10.0*value)); // generate command
359  w6100_set_cmd(info, "w6100_set_gain", str, "P");
360 }
361 
362 /*----------------------------------------------------------------------------*/
370 void w6100_set_reset_or_rate(W6100_INFO *info, float value, int tag)
371 {
372  char cmd[4], str[16];
373  float min, sec;
374 
375  // check if value is within valid range and generate subcommand
376  min = floorf(value);
377  sec = value-min;
378 
379  // generate subcommand
380  switch (tag) {
381  case 0: // reset (I)
382  strcpy(cmd,"I");
383  if ((sec<0.f) || (sec>0.59)) {
384  cm_msg(MERROR, "W6100_set", "value for '%s' out of range [0.0,99.59].", cmd);
385  return;
386  }
387  break;
388  case 1: // rate (D)
389  strcpy(cmd,"D");
390  if ((sec<0.f) || (sec>0.59)) {
391  cm_msg(MERROR, "W6100_set", "value for '%s' out of range [0.0,99.59].", cmd);
392  return;
393  }
394  break;
395  default: // not allowed
396  return;
397  break;
398  } // switch
399 
400  if ((min<0.f) || (min>99)) {
401  cm_msg(MERROR, "W6100_set", "value for '%s' out of range [0.00,99.59].", cmd);
402  return;
403  }
404 
405  // send command
406  sprintf(str,"L1%s#%04d2*", cmd, (int)(100.f*value)); // generate command, see p.4-3
407  w6100_set_cmd(info, "w6100_set_reset_or_rate", str, cmd);
408 }
409 
410 /*----------------------------------------------------------------------------*/
418 void w6100_set_needle_valve_pos(W6100_INFO *info, float value)
419 {
420  char str[16];
421 
422  // check if value is within allowed boundaries
423  if ((value < 0.f) || (value > 100.f)) {
424  cm_msg(MERROR, "W6100_set", "value for the needle valve position is out of range [0,100].");
425  return;
426  }
427 
428  // sets needle valve position
429  sprintf(str,"L1W#%04d0*", (int)value); // generate command
430  w6100_set_cmd(info, "w6100_set_needle_valve_pos", str, "W");
431 }
432 
433 /*----------------------------------------------------------------------------*/
440 {
441  char str[16];
442  int status;
443 
444  // check if self-tuning is on, if yes disable self-tunig
445  if (w6100_get_value(info, "w6100_set_manual", "L1L?*", str)) {
446  // decode status bits
447  sscanf(str, "L1L%dA*", &status);
448  status /= 10;
449  if (status & 4) { // Bit 2, self-tuning enabled=1/disabled=0
450  strcpy(str,"L1Z#00040*"); // disable self-tuning command
451  w6100_set_cmd(info, "w6100_set_manual", str, "Z");
452  }
453  }
454 
455  // set the 'West 6100' controller to the manual control mode, i.e. PID controlled
456  strcpy(str,"L1Z#00010*"); // enable manual control command
457  w6100_set_cmd(info, "w6100_set_manual", str, "Z");
458 
459  // set the needle valve position to its demand value
461 }
462 
463 /*----------------------------------------------------------------------------*/
471 {
472  HNDLE hDB;
473  HNDLE hKeyOut;
474  int size;
475  float value;
476 
477  // get ODB handle
478  cm_get_experiment_database(&hDB, NULL);
479 
480  // find keys
481  if (db_find_key(hDB, 0, info->w6100_in_settings.odb_output, &hKeyOut) != DB_SUCCESS) {
482  cm_msg(MINFO, "w6100_forced_update", "w6100_forced_update: couldn't get variable output handle. Forced update needs to be preformed manually!");
483  return;
484  }
485 
487  cm_msg(MINFO, "w6100_forced_update", "w6100_forced_update: performing forced update...");
488 
489  // get demand set point
490  size = sizeof(value);
491  db_get_data_index(hDB, hKeyOut, &value, &size, W6100_SET_PRESSURE+info->w6100_in_settings.odb_offset, TID_FLOAT);
492  // set demand set point
493  w6100_set_pressure(info, value);
494  // get demand gain (P)
495  size = sizeof(value);
496  db_get_data_index(hDB, hKeyOut, &value, &size, W6100_P+info->w6100_in_settings.odb_offset, TID_FLOAT);
497  // set demand gain (P)
498  w6100_set_gain(info, value);
499  // get demand reset (I)
500  size = sizeof(value);
501  db_get_data_index(hDB, hKeyOut, &value, &size, W6100_I+info->w6100_in_settings.odb_offset, TID_FLOAT);
502  // set demand reset (I)
503  w6100_set_reset_or_rate(info, value, 0);
504  // get demand rate (D)
505  size = sizeof(value);
506  db_get_data_index(hDB, hKeyOut, &value, &size, W6100_D+info->w6100_in_settings.odb_offset, TID_FLOAT);
507  // set demand rate (D)
508  w6100_set_reset_or_rate(info, value, 1);
509 }
510 
511 /*----------------------------------------------------------------------------*/
518 {
519  char str[16];
520  int status;
521 
522  // check if self-tuning is on, if yes disable self-tunig
523  if (w6100_get_value(info, "w6100_set_auto", "L1L?*", str)) {
524  // decode status bits
525  sscanf(str, "L1L%dA*", &status);
526  status /= 10;
527  if (status & 4) { // Bit 2, self-tuning enabled=1/disabled=0
528  strcpy(str,"L1Z#00040*"); // disable self-tuning command
529  w6100_set_cmd(info, "w6100_set_auto", str, "Z");
530  }
531  }
532 
533  if (status & 32) { // Bit 5, 1=Manual/0=Auto
534  // set the 'West 6100' controller to the auto control mode, i.e. PID controlled
535  strcpy(str,"L1Z#00020*"); // enable auto control command
536  w6100_set_cmd(info, "w6100_set_auto", str, "Z");
537  }
538 
539  // forced update of SetPoint and PIDs --------------------------------------
540  w6100_forced_update(info);
541 }
542 
543 /*----------------------------------------------------------------------------*/
550 {
551  char str[16];
552  int status;
553 
554  // check if manual is on, if yes switch to auto
555  if (w6100_get_value(info, "w6100_set_self_tuning", "L1L?*", str)) {
556  // decode status bits
557  sscanf(str, "L1L%dA*", &status);
558  status /= 10;
559  if (status & 32) { // Bit 5, auto=0/manual=1
560  strcpy(str,"L1Z#00020*"); // activate auto control
561  w6100_set_cmd(info, "w6100_set_self_tuning", str, "Z");
562  }
563  }
564 
565  // set the 'West 6100' controller to the self-tuning mode
566  strcpy(str,"L1Z#00030*"); // enable self-tuning control command
567  w6100_set_cmd(info, "w6100_set_self_tuning", str, "Z");
568 }
569 
570 /*----------------------------------------------------------------------------*/
577 void w6100_set_ctrl(W6100_INFO *info, float value)
578 {
579  char str[16];
580  int status, ctrl, self_tune;
581 
582  // check if the controller is already in the required mode
583  if (info->param.ctrl == value)
584  return;
585 
586  // sets ctrl mode
587  ctrl = (int)value;
588  switch (ctrl) {
589  case 0: // manual
590  w6100_set_manual(info);
591  break;
592  case 1: // auto, i.e. PID controlled
593  w6100_set_auto(info);
594  break;
595  case 2: // self-tuning
596  w6100_set_self_tuning(info);
597  break;
598  default:
599  cm_msg(MERROR, "W6100_set", "allowed values are 0=manual, 1=auto i.e. PID, 2=self-tuning.");
600  return;
601  }
602 
603  // get controller state
604  if (w6100_get_value(info, "w6100_set_ctrl", "L1L?*", str)) {
605  sscanf(str, "L1L%dA*", &status);
606  status /= 10;
607 
608  if (status & 32) // Bit 5 set, auto/manual control bit
609  ctrl = 0;
610  else
611  ctrl = 1;
612 
613  if (status & 4) // Bit 2 set, self-tuning enabled/disabled
614  self_tune = 1;
615  else
616  self_tune = 0;
617 
618  if (ctrl && self_tune) // self-tuning auto
619  info->param.ctrl = 2;
620  else
621  info->param.ctrl = ctrl; // since manual=0, auto=1 for our controller
622  }
623 }
624 
625 /*---- device driver routines --------------------------------------*/
639 INT w6100_in_init(HNDLE hKey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
640 {
641 INT status, i, ctrl, self_tune;
642 char str[128];
643 HNDLE hDB, hkeydd;
644 
645  cm_get_experiment_database(&hDB, NULL);
646 
647  // allocate info structure
648  info = calloc(1, sizeof(W6100_INFO));
649  *pinfo = info;
650 
651  // create W6100 settings record
652  status = db_create_record(hDB, hKey, "DD", W6100_IN_SETTINGS_STR);
653  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
654  cm_msg(MERROR, "w6100_in_init", "w6100_in_init: Error creating DD record in ODB, status=%d", status);
655  cm_yield(0);
656  return FE_ERR_ODB;
657  }
658 
659  // open hot-link to DD record
660  db_find_key(hDB, hKey, "DD", &hkeydd);
661  db_open_record(hDB, hkeydd, &info->w6100_in_settings, sizeof(info->w6100_in_settings), MODE_READ, NULL, NULL);
662 
663  // check if the device shall be enabled
664  if (!info->w6100_in_settings.enabled) {
665  cm_msg(MINFO, "w6100_in_init", "West 6100 disabled from within the DD ...");
666  cm_yield(0);
667  return FE_SUCCESS;
668  }
669 
670  // initialize driver
671  info->hkey = hKey;
672  info->num_channels_in = channels;
673  info->bd = bd;
674  info->remote = 0;
675  info->errorcount = 0;
676  info->lasterrtime = ss_time();
677  info->startup_error = 0;
678  info->readback_failure = 0;
679  info->bd_connected = 0;
680  info->last_reconnect = ss_time();
681  info->first_bd_error = 1;
682 
683  if ( info->num_channels_in > W6100_IN_CHANNELS ) {
684  cm_msg(MERROR,"w6100_in_init", "Error, max. number of W6100 input channels is 3, not %d.", info->num_channels_in);
685  cm_yield(0);
686  info->startup_error = 1;
687  return FE_SUCCESS;
688  }
689 
690  if (!bd)
691  return FE_ERR_ODB;
692 
693  // initialize bus driver
694  status = info->bd(CMD_INIT, hKey, &info->bd_info);
695  if (status != FE_SUCCESS) {
696  cm_msg(MERROR,"W6100_in_init", "Couldn't init bus driver of 'West 6100'");
697  cm_yield(0);
698  info->startup_error = 1;
699  return FE_SUCCESS;
700  }
701  info->bd_connected = 1;
702 
703  // initialize W6100
704  i=0;
705  do { // check if west6100 is alive
706  if (w6100_get_value(info, "W6100_in_init", "L1??*", str)) // got something
707  break;
708  i++;
709  ss_sleep(300);
710  } while (i<5);
711  if (i==5) { // maximal attempts to read vaild
712  cm_msg(MERROR,"W6100_in_init", "Error getting device query from 'West 6100'");
713  cm_yield(0);
714  info->startup_error = 1;
715  return FE_SUCCESS;
716  }
717  if (strstr(str,"L1?A*")) {
718  cm_msg(MINFO,"W6100_in_init", "'West 6100' is alive and ready.");
719  cm_yield(0);
720  } else {
721  cm_msg(MINFO,"W6100_in_init", "'West 6100' is not responding properly -> %s", str);
722  cm_yield(0);
723  info->startup_error = 1;
724  }
725 
726  // get low limit set point
727  if (w6100_get_value(info, "W6100_in_init", "L1T?*", str)) {
728  info->param.low_limit = w6100_decode_data(str);
729  }
730 
731  // get high limit set point
732  if (w6100_get_value(info, "W6100_in_init", "L1A?*", str)) {
733  info->param.high_limit = w6100_decode_data(str);
734  }
735 
736  // get controller state
737  if (w6100_get_value(info, "W6100_in_init", "L1L?*", str)) {
738  sscanf(str, "L1L%dA*", &status);
739  status /= 10;
740 
741  if (status & 32) // Bit 5 set, auto/manual control bit
742  ctrl = 1;
743  else
744  ctrl = 0;
745 
746  if (status & 4) // Bit 2 set, self-tuning enabled/disabled
747  self_tune = 1;
748  else
749  self_tune = 0;
750 
751  if (ctrl && self_tune) // self-tuning auto
752  info->param.ctrl = 2;
753  else
754  info->param.ctrl = !ctrl; // since 0=manual, 1=auto for our controller!!
755  }
756 
757  cm_msg(MINFO, "west6100_in_init", "west6100_in_init: west 6100 initialized.");
758  cm_yield(0);
759 
760  return FE_SUCCESS;
761 }
762 
763 /*----------------------------------------------------------------------------*/
777 INT w6100_out_init(HNDLE hKey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...))
778 {
779 INT status;
780 HNDLE hDB, hkeydd;
781 
782  cm_get_experiment_database(&hDB, NULL);
783 
784  *pinfo = info;
785 
786  // create W6100 settings record
787  status = db_create_record(hDB, hKey, "DD", W6100_OUT_SETTINGS_STR);
788  if ((status != DB_SUCCESS) && (status != DB_OPEN_RECORD)) {
789  cm_msg(MERROR, "w6100_out_init", "w6100_out_init: Error creating DD record in ODB, status=%d", status);
790  return FE_ERR_ODB;
791  }
792 
793  // open hot-link to DD record
794  db_find_key(hDB, hKey, "DD", &hkeydd);
795  db_open_record(hDB, hkeydd, &info->w6100_out_settings, sizeof(info->w6100_out_settings), MODE_READ, NULL, NULL);
796 
797  // initialize driver
798  info->num_channels_out = channels;
799 
800  if ( info->num_channels_out != W6100_OUT_CHANNELS ) {
801  cm_msg(MERROR,"w6100_out_init", "Error, allowed number of W6100 output channels is 8, not %d.", info->num_channels_out);
802  info->startup_error = 1;
803  return FE_ERR_HW;
804  }
805 
806  return FE_SUCCESS;
807 }
808 
809 /*----------------------------------------------------------------------------*/
819 {
820  if (info->w6100_in_settings.enabled) {
821  // call EXIT function of bus driver, usually closes device
822  info->bd(CMD_EXIT, info->bd_info);
823  }
824 
825  free(info);
826 
827  return FE_SUCCESS;
828 }
829 
830 /*----------------------------------------------------------------------------*/
840 INT w6100_set(W6100_INFO *info, INT channel, float value)
841 {
842 char str[128];
843 
844  if (!info->w6100_in_settings.enabled) {
845  ss_sleep(10); // in order to keep the CPU load low
846  return FE_SUCCESS;
847  }
848 
849  if ( channel == 0 )
850  info->remote = (int) value;
851  if (info->remote == 0 || info->startup_error == 1)
852  return FE_SUCCESS;
853 
854  if (!info->bd_connected) {
855  if (info->first_bd_error) {
856  info->first_bd_error = 0;
857  cm_msg(MINFO, "W6100_set",
858  "set values not possible at the moment, since the bus driver is not available!");
859  }
860  }
861 
862  switch (channel) {
863  case 1: // set point pressure
864  w6100_set_pressure(info, value);
865  break;
866  case 2: // gain (P)
867  w6100_set_gain(info, value);
868  break;
869  case 3: // reset (I)
870  w6100_set_reset_or_rate(info, value, 0);
871  break;
872  case 4: // rate (D)
873  w6100_set_reset_or_rate(info, value, 1);
874  break;
875  case 5: // Ctrl Modes
876  w6100_set_ctrl(info, value);
877  break;
878  case 6: // needle valve position
879  info->param.needle_valve_pos = value; // store needle valve demand position
880  if (info->param.ctrl) // ctrl mode auto, self-tuning
881  break;
882  w6100_set_needle_valve_pos(info, value);
883  break;
884  case 7: // Upper output limit
885  sprintf(str, "L1B#%04d0*", (int)value);
886  w6100_set_cmd(info, "W6100_set", str, "B");
887  break;
888  default:
889  break;
890  }
891 
892  return FE_SUCCESS;
893 }
894 
895 /*----------------------------------------------------------------------------*/
905 INT w6100_get(W6100_INFO *info, INT channel, float *pvalue)
906 {
907 char str[128], cmd[128];
908 int status;
909 DWORD nowtime, difftime;
910 
911 
912  if (!info->w6100_in_settings.enabled) {
913  ss_sleep(10); // in order to keep the CPU load low
914  return FE_SUCCESS;
915  }
916 
917  // error handling
918  nowtime = ss_time();
919  difftime = nowtime - info->lasterrtime;
920 
921  if ( difftime > W6100_DELTA_TIME_ERROR ) {
922  info->errorcount = 0;
923  info->lasterrtime = nowtime;
924  }
925 
926  if ( info->startup_error == 1 ) { // error during CMD_INIT, return -2
927  *pvalue = (float) W6100_INIT_ERROR;
928  ss_sleep(10); // to keep CPU load low when Run active
929  return FE_SUCCESS;
930  }
931 
932  // if disconnected, try to reconnect after a timeout of 10 sec
933  if (!info->bd_connected) {
934  if (ss_time()-info->last_reconnect > 10) { // timeout expired
936  cm_msg(MINFO, "W6100_get", "West 6100: reconnection trial ...");
937  status = info->bd(CMD_INIT, info->hkey, &info->bd_info);
938  if (status != FE_SUCCESS) {
939  *pvalue = (float) W6100_READ_ERROR;
941  cm_msg(MINFO, "W6100_get", "West 6100: reconnection attempted failed");
942  return FE_ERR_HW;
943  } else {
944  info->bd_connected = 1; // bus driver is connected again
945  info->last_reconnect = ss_time();
946  info->first_bd_error = 1;
948  cm_msg(MINFO, "W6100_get", "West 6100: successfully reconnected");
949  }
950  } else { // timeout still running
951  *pvalue = (float) W6100_READ_ERROR;
952  return FE_SUCCESS;
953  }
954  }
955 
956  // command according to the channel
957  switch(channel) {
958  case 0: // pressure (mbar)
959  strcpy(cmd,"L1M?*");
960  break;
961  case 1: // set point (mbar) read back
962  strcpy(cmd,"L1S?*");
963  break;
964  case 2: // needle valve position
965  strcpy(cmd,"L1W?*");
966  break;
967  case 3: // gain (P) read back
968  strcpy(cmd,"L1P?*");
969  break;
970  case 4: // reset (I) read back
971  strcpy(cmd,"L1I?*");
972  break;
973  case 5: // rate (D) read back
974  strcpy(cmd,"L1D?*");
975  break;
976  case 6: // get controller status
977  strcpy(cmd,"L1L?*");
978  break;
979  default:
980  *pvalue = (float) W6100_READ_ERROR;
981  return FE_SUCCESS;
982  }
983 
984  if (w6100_get_value(info, "W6100_get", cmd, str)) { // get reply
985  if (strstr(str,"<??>")) { // data out of range
986  *pvalue = W6100_OUT_OF_RANGE;
987  } else { // real data
988  if (channel != 6)
989  *pvalue = w6100_decode_data(str);
990  else { // controller status
991  sscanf(str, "L1L%fA*", pvalue);
992  *pvalue /= 10;
993  }
994  info->readback_failure = 0;
995  }
996  } else { // no response
997  *pvalue = (float) W6100_READ_ERROR;
998  if (info->errorcount < W6100_MAX_ERROR) {
999  cm_msg(MERROR, "W6100_get", "'West 6100' does not respond.");
1000  info->errorcount++;
1001  }
1002 
1003  info->readback_failure++;
1004 
1006  info->readback_failure = 0;
1007  // try to disconnect and reconnect the bus driver
1008  if ((ss_time()-info->last_reconnect > 10) && info->bd_connected) { // disconnect bus driver
1009  info->bd(CMD_EXIT, info->bd_info);
1010  if (info->w6100_in_settings.detailed_msg)
1011  cm_msg(MINFO, "W6100_get", "West 6100: try to disconnect and reconnect the bus driver");
1012  info->last_reconnect = ss_time();
1013  info->bd_connected = 0;
1014  if (info->w6100_in_settings.ets_in_use)
1016  }
1017  }
1018  }
1019 
1020  return FE_SUCCESS;
1021 }
1022 
1023 /*----------------------------------------------------------------------------*/
1034 INT w6100_in_get_label(W6100_INFO *info, INT channel, char *name)
1035 {
1036  strcpy(name, info->w6100_in_settings.name[channel]);
1037  return FE_SUCCESS;
1038 }
1039 
1040 /*----------------------------------------------------------------------------*/
1051 INT w6100_out_get_label(W6100_INFO *info, INT channel, char *name)
1052 {
1053  strcpy(name, info->w6100_out_settings.name[channel]);
1054  return FE_SUCCESS;
1055 }
1056 
1057 /*---- device driver entry point -----------------------------------*/
1058 INT w6100_in(INT cmd, ...)
1059 {
1060 va_list argptr;
1061 HNDLE hKey;
1062 INT channel, status;
1063 float *pvalue;
1064 void *info, *bd;
1065 char *name;
1066 DWORD flags;
1067 
1068  va_start(argptr, cmd);
1069  status = FE_SUCCESS;
1070 
1071  switch (cmd) {
1072  case CMD_INIT:
1073  hKey = va_arg(argptr, HNDLE);
1074  info = va_arg(argptr, void *);
1075  channel = va_arg(argptr, INT);
1076  flags = va_arg(argptr, DWORD);
1077  bd = va_arg(argptr, void *);
1078  status = w6100_in_init(hKey, info, channel, bd);
1079  break;
1080 
1081  case CMD_EXIT:
1082  info = va_arg(argptr, void *);
1083  status = w6100_exit(info);
1084  break;
1085 
1086  case CMD_GET:
1087  info = va_arg(argptr, void *);
1088  channel = va_arg(argptr, INT);
1089  pvalue = va_arg(argptr, float*);
1090  status = w6100_get(info, channel, pvalue);
1091  break;
1092 
1093  case CMD_GET_LABEL:
1094  info = va_arg(argptr, void *);
1095  channel = va_arg(argptr, INT);
1096  name = va_arg(argptr, char *);
1097  status = w6100_in_get_label(info, channel, name);
1098  break;
1099 
1100  default:
1101  break;
1102  } // switch
1103 
1104  va_end(argptr);
1105  return status;
1106 }
1107 
1108 INT w6100_out(INT cmd, ...)
1109 {
1110 va_list argptr;
1111 HNDLE hKey;
1112 INT channel, status;
1113 float value;
1114 void *info, *bd;
1115 char *name;
1116 DWORD flags;
1117 
1118  va_start(argptr, cmd);
1119  status = FE_SUCCESS;
1120 
1121  switch (cmd) {
1122  case CMD_INIT:
1123  hKey = va_arg(argptr, HNDLE);
1124  info = va_arg(argptr, void *);
1125  channel = va_arg(argptr, INT);
1126  flags = va_arg(argptr, DWORD);
1127  bd = va_arg(argptr, void *);
1128  status = w6100_out_init(hKey, info, channel, bd);
1129  break;
1130 
1131  case CMD_SET:
1132  info = va_arg(argptr, void *);
1133  channel = va_arg(argptr, INT);
1134  value = (float) va_arg(argptr, double);
1135  status = w6100_set(info, channel, value);
1136  break;
1137 
1138  case CMD_GET_LABEL:
1139  info = va_arg(argptr, void *);
1140  channel = va_arg(argptr, INT);
1141  name = va_arg(argptr, char *);
1142  status = w6100_out_get_label(info, channel, name);
1143  break;
1144 
1145  default:
1146  break;
1147  } // switch
1148 
1149  va_end(argptr);
1150 
1151  return status;
1152 }
1153 
1154 /*------------------------------------------------------------------*/
void w6100_set_manual(W6100_INFO *info)
Definition: west6100.c:439
char odb_output[2 *NAME_LENGTH]
odb output variable path. Needed by the forced update routine
Definition: west6100.c:59
INT w6100_get(W6100_INFO *info, INT channel, float *pvalue)
Definition: west6100.c:905
#define W6100_OUT_CHANNELS
number of output channels
Definition: west6100.c:51
#define W6100_READ_ERROR
read error tag
Definition: west6100.c:46
W6100_param param
stores internal parameter of the controller
Definition: west6100.c:113
INFO info
Definition: vme_fe.c:206
void w6100_set_gain(W6100_INFO *info, float value)
Definition: west6100.c:348
#define W6100_IN_SETTINGS_STR
initializing string for W6100_IN_SETTINGS
Definition: west6100.c:69
INT w6100_set(W6100_INFO *info, INT channel, float value)
Definition: west6100.c:840
#define W6100_P
Definition: west6100.c:34
INT w6100_in_init(HNDLE hKey, void **pinfo, INT channels, INT(*bd)(INT cmd,...))
Definition: west6100.c:639
#define W6100_IN_CHANNELS
number of input channels
Definition: west6100.c:50
INT w6100_exit(W6100_INFO *info)
Definition: west6100.c:818
INT w6100_in_get_label(W6100_INFO *info, INT channel, char *name)
Definition: west6100.c:1034
INT w6100_in(INT cmd,...)
Definition: west6100.c:1058
INT num_channels_out
number of out-channels
Definition: west6100.c:112
int ets_logout(void *info, int wait, int detailed_msg)
Definition: ets_logout.c:113
INT detailed_msg
flag indicating if detailed status/error messages are wanted
Definition: west6100.c:56
HNDLE hKey
Definition: write_summary.c:97
char name[W6100_IN_CHANNELS][64]
name of the in-channels
Definition: west6100.c:60
void w6100_set_pressure(W6100_INFO *info, float value)
Definition: west6100.c:325
void w6100_set_ctrl(W6100_INFO *info, float value)
Definition: west6100.c:577
void * bd_info
private info of bus driver
Definition: west6100.c:115
int first_bd_error
flag showing if the bus driver error message is already given
Definition: west6100.c:122
void w6100_set_reset_or_rate(W6100_INFO *info, float value, int tag)
Definition: west6100.c:370
INT readback_failure
counts the number of readback failures
Definition: west6100.c:120
#define W6100_DELTA_TIME_ERROR
reset error counter after W6100_DELTA_TIME_ERROR seconds
Definition: west6100.c:44
int w6100_set_cmd(W6100_INFO *info, char *who, char *cmd, char *activate_cmd)
Definition: west6100.c:235
#define W6100_INIT_ERROR
initialize error tag
Definition: west6100.c:47
HNDLE hDB
Definition: write_summary.c:97
void w6100_set_auto(W6100_INFO *info)
Definition: west6100.c:517
void w6100_error(W6100_INFO *info, char *who, char *msg)
Definition: west6100.c:139
float low_limit
low limit of the &#39;West 6100&#39; set point
Definition: west6100.c:100
int ctrl
&#39;West 6100&#39; controller state (0=Manual, 1=Auto, i.e. PID controlled, 2=Self-Tuning) ...
Definition: west6100.c:102
INT ets_in_use
flag indicating if the rs232 terminal server is in use
Definition: west6100.c:57
W6100_IN_SETTINGS w6100_in_settings
ODB hot-link data for the DD.
Definition: west6100.c:108
INT odb_offset
odb offset for the output variables. Needed by the forced update routine
Definition: west6100.c:58
HNDLE hkey
holds the ODB key to the DD
Definition: west6100.c:110
#define W6100_D
Definition: west6100.c:36
#define W6100_MAX_ERROR
maximum number of error messages
Definition: west6100.c:43
#define W6100_TIME_OUT
time out in msecs for read (rs232)
Definition: west6100.c:30
#define W6100_SET_PRESSURE
Definition: west6100.c:33
#define W6100_OUT_OF_RANGE
read back pressure out of range tag
Definition: west6100.c:48
float w6100_decode_data(char *code)
Definition: west6100.c:162
This structure contains private variables for the device driver.
Definition: west6100.c:107
#define W6100_I
Definition: west6100.c:35
void w6100_set_self_tuning(W6100_INFO *info)
Definition: west6100.c:549
int w6100_get_value(W6100_INFO *info, char *who, char *cmd, char *rcv)
Definition: west6100.c:282
char name[W6100_OUT_CHANNELS][64]
name of the out-channels
Definition: west6100.c:65
void w6100_set_needle_valve_pos(W6100_INFO *info, float value)
Definition: west6100.c:418
W6100_OUT_SETTINGS w6100_out_settings
ODB hot-link data for the DD.
Definition: west6100.c:109
INT enabled
flag showing if the device is enabled
Definition: west6100.c:55
INT errorcount
error counter
Definition: west6100.c:117
int bd_connected
flag showing if bus driver is connected
Definition: west6100.c:121
stores internal informations within the DD.
Definition: west6100.c:54
INT w6100_out_init(HNDLE hKey, void **pinfo, INT channels, INT(*bd)(INT cmd,...))
Definition: west6100.c:777
stores internal informations within the DD.
Definition: west6100.c:64
float high_limit
high limit of the &#39;West 6100&#39; set point
Definition: west6100.c:101
stores internal settings of the running &#39;West 6100&#39; controller
Definition: west6100.c:99
INT(* bd)(INT cmd,...)
bus driver entry function
Definition: west6100.c:114
#define W6100_ETS_LOGOUT_SLEEP
sleep time (us) between the telnet commands of the ets_logout
Definition: west6100.c:24
#define W6100_MAX_READBACK_FAILURE
maximum number of readback failures before a reconnect will take place
Definition: west6100.c:27
INT w6100_out_get_label(W6100_INFO *info, INT channel, char *name)
Definition: west6100.c:1051
DWORD last_reconnect
timer for bus driver reconnect error handling
Definition: west6100.c:123
void w6100_forced_update(W6100_INFO *info)
Definition: west6100.c:470
INT w6100_out(INT cmd,...)
Definition: west6100.c:1108
#define W6100_OUT_SETTINGS_STR
initializing string for W6100_OUT_SETTINGS
Definition: west6100.c:86
INT startup_error
startup error tag
Definition: west6100.c:118
float needle_valve_pos
actual needle valve position
Definition: west6100.c:103
INT num_channels_in
number of in-channels
Definition: west6100.c:111
DWORD lasterrtime
timer for error handling
Definition: west6100.c:119
INT remote
remote tag, 1=remote, 0=local
Definition: west6100.c:116