LCOV - code coverage report
Current view: top level - drivers/class - multi.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 448 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 13 0

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

Generated by: LCOV version 2.0-1