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

            Line data    Source code
       1              : /********************************************************************\
       2              : 
       3              :   Name:         mscbdev.c
       4              :   Created by:   Stefan Ritt
       5              : 
       6              :   Contents:     MSCB Device Driver.
       7              : 
       8              :   $Id$
       9              : 
      10              : \********************************************************************/
      11              : 
      12              : #include <stdio.h>
      13              : #include <stdlib.h>
      14              : #include <stdarg.h>
      15              : #include <string.h>
      16              : #include "midas.h"
      17              : #include "mscb.h"
      18              : #include "mstrlcpy.h"
      19              : 
      20              : extern void mfe_error(const char *error);
      21              : 
      22              : /*---- globals -----------------------------------------------------*/
      23              : 
      24              : /* MSCB node address / channel mapping */
      25              : 
      26              : typedef struct {
      27              :    char mscb_device[256];
      28              :    char pwd[32];
      29              :    int debug;
      30              :    int retries;
      31              :    int pause;
      32              :    int *mscb_address;
      33              :    unsigned char *mscb_index;
      34              :    int *var_size;
      35              :    float *var_cache;
      36              :    char *label;
      37              : } MSCBDEV_SETTINGS;
      38              : 
      39              : typedef struct {
      40              :    MSCBDEV_SETTINGS mscbdev_settings;
      41              :    INT fd;
      42              :    INT num_channels;
      43              : } MSCBDEV_INFO;
      44              : 
      45              : /*---- device driver routines --------------------------------------*/
      46              : 
      47            0 : void addr_changed(HNDLE, HNDLE, void *arg)
      48              : {
      49              :    INT i, status;
      50              :    MSCB_INFO_VAR var_info;
      51              :    MSCBDEV_INFO *info;
      52              : 
      53            0 :    info = (MSCBDEV_INFO *) arg;
      54              : 
      55              :    /* get info about MSCB channels */
      56            0 :    if (info->num_channels > 20)
      57            0 :       printf("\n");
      58            0 :    for (i = 0; i < info->num_channels; i++) {
      59            0 :       if (info->num_channels > 20) {
      60            0 :          printf("Channel %d\r", i);
      61            0 :          fflush(stdout);
      62              :       }
      63            0 :       status = mscb_info_variable(info->fd, info->mscbdev_settings.mscb_address[i],
      64            0 :                                   info->mscbdev_settings.mscb_index[i], &var_info);
      65            0 :       if (status == MSCB_SUCCESS) {
      66            0 :          if (var_info.flags & MSCBF_FLOAT)
      67            0 :             info->mscbdev_settings.var_size[i] = -1;
      68              :          else
      69            0 :             info->mscbdev_settings.var_size[i] = var_info.width;
      70            0 :          mstrlcpy(info->mscbdev_settings.label+i*16, var_info.name, 16);
      71              :       } else {
      72            0 :          info->mscbdev_settings.var_size[i] = 0;
      73            0 :          cm_msg(MERROR, "addr_changed", "Cannot read from address %d at submaster %s", 
      74            0 :             info->mscbdev_settings.mscb_address[i], info->mscbdev_settings.mscb_device);
      75            0 :          return;
      76              :       }
      77              :    }
      78            0 :    if (info->num_channels > 20)
      79            0 :       printf("\n");
      80              : }
      81              : 
      82              : /*----------------------------------------------------------------------------*/
      83              : 
      84              : /* the init function creates a ODB record which contains the
      85              :    settings and initialized it variables as well as the bus driver */
      86              : 
      87              : typedef INT(func_t) (INT cmd, ...);
      88              : 
      89            0 : INT mscbdev_init(HNDLE hkey, MSCBDEV_INFO **pinfo, INT channels, func_t *)
      90              : {
      91              :    int i, status, size;
      92              :    HNDLE hDB, hsubkey;
      93              :    MSCBDEV_INFO *info;
      94              : 
      95              :    /* allocate info structure */
      96            0 :    info = (MSCBDEV_INFO*) calloc(1, sizeof(MSCBDEV_INFO));
      97            0 :    *pinfo = info;
      98            0 :    info->mscbdev_settings.mscb_address = (int*) calloc(channels, sizeof(INT));
      99            0 :    info->mscbdev_settings.mscb_index = (unsigned char*) calloc(channels, sizeof(INT));
     100            0 :    info->mscbdev_settings.var_size = (int*) calloc(channels, sizeof(INT));
     101            0 :    info->mscbdev_settings.var_cache = (float*) calloc(channels, sizeof(float));
     102            0 :    info->mscbdev_settings.label = (char*) calloc(channels, 16);
     103            0 :    for (i = 0; i < channels; i++)
     104            0 :       info->mscbdev_settings.var_cache[i] = (float) ss_nan();
     105              : 
     106            0 :    cm_get_experiment_database(&hDB, NULL);
     107              : 
     108              :    /* create settings record */
     109            0 :    size = sizeof(info->mscbdev_settings.mscb_device);
     110            0 :    strcpy(info->mscbdev_settings.mscb_device, "usb0");
     111            0 :    status = db_get_value(hDB, hkey, "MSCB Device", &info->mscbdev_settings.mscb_device, &size, TID_STRING, TRUE);
     112            0 :    if (status != DB_SUCCESS)
     113            0 :       return FE_ERR_ODB;
     114              : 
     115            0 :    size = sizeof(info->mscbdev_settings.pwd);
     116            0 :    info->mscbdev_settings.pwd[0] = 0;
     117            0 :    status = db_get_value(hDB, hkey, "MSCB Pwd", &info->mscbdev_settings.pwd, &size, TID_STRING, TRUE);
     118            0 :    if (status != DB_SUCCESS)
     119            0 :       return FE_ERR_ODB;
     120              : 
     121            0 :    size = sizeof(info->mscbdev_settings.debug);
     122            0 :    info->mscbdev_settings.debug = 0;
     123            0 :    status = db_get_value(hDB, hkey, "MSCB Debug", &info->mscbdev_settings.debug, &size, TID_INT32, TRUE);
     124            0 :    if (status != DB_SUCCESS)
     125            0 :       return FE_ERR_ODB;
     126              : 
     127            0 :    size = sizeof(info->mscbdev_settings.pause);
     128            0 :    info->mscbdev_settings.pause = 0;
     129            0 :    status = db_get_value(hDB, hkey, "MSCB Pause", &info->mscbdev_settings.pause, &size, TID_INT32, TRUE);
     130            0 :    if (status != DB_SUCCESS)
     131            0 :       return FE_ERR_ODB;
     132              : 
     133            0 :    size = sizeof(info->mscbdev_settings.retries);
     134            0 :    info->mscbdev_settings.retries = 10;
     135            0 :    status = db_get_value(hDB, hkey, "MSCB Retries", &info->mscbdev_settings.retries, &size, TID_INT, TRUE);
     136            0 :    if (status != DB_SUCCESS)
     137            0 :       return FE_ERR_ODB;
     138              : 
     139            0 :    size = sizeof(INT) * channels;
     140            0 :    db_get_value(hDB, hkey, "MSCB Address", info->mscbdev_settings.mscb_address, &size, TID_INT, TRUE);
     141            0 :    db_find_key(hDB, hkey, "MSCB Address", &hsubkey);
     142            0 :    size = sizeof(INT) * channels;
     143            0 :    db_set_data(hDB, hsubkey, info->mscbdev_settings.mscb_address, size, channels, TID_INT);
     144            0 :    db_open_record(hDB, hsubkey, info->mscbdev_settings.mscb_address, size, MODE_READ, addr_changed, info);
     145              : 
     146            0 :    size = sizeof(BYTE) * channels;
     147            0 :    db_get_value(hDB, hkey, "MSCB Index", info->mscbdev_settings.mscb_index, &size, TID_BYTE, TRUE);
     148            0 :    db_find_key(hDB, hkey, "MSCB Index", &hsubkey);
     149            0 :    size = sizeof(BYTE) * channels;
     150            0 :    db_set_data(hDB, hsubkey, info->mscbdev_settings.mscb_index, size, channels, TID_BYTE);
     151            0 :    db_open_record(hDB, hsubkey, info->mscbdev_settings.mscb_index, size, MODE_READ, addr_changed, info);
     152              : 
     153              :    // execute periodic tasks since mscb_init can take a while
     154            0 :    cm_periodic_tasks();
     155              :    
     156              :    /* initialize info structure */
     157            0 :    info->num_channels = channels;
     158              : 
     159            0 :    info->fd = mscb_init(info->mscbdev_settings.mscb_device, sizeof(info->mscbdev_settings.mscb_device),
     160            0 :                         info->mscbdev_settings.pwd, info->mscbdev_settings.debug);
     161            0 :    if (info->fd < 0) {
     162            0 :       cm_msg(MERROR, "mscbdev_init", "Cannot connect to MSCB device \"%s\"", info->mscbdev_settings.mscb_device);
     163            0 :       return FE_ERR_HW;
     164              :    }
     165              : 
     166              :    /* set number of retries */
     167            0 :    mscb_set_eth_max_retry(info->fd, info->mscbdev_settings.retries);
     168              : 
     169              :    /* set communication pause */
     170            0 :    mscb_set_eth_pause(info->fd, info->mscbdev_settings.pause);
     171              : 
     172              :    /* write back device */
     173            0 :    status = db_set_value(hDB, hkey, "Device", &info->mscbdev_settings.mscb_device,
     174              :                          sizeof(info->mscbdev_settings.mscb_device), 1, TID_STRING);
     175            0 :    if (status != DB_SUCCESS)
     176            0 :       return FE_ERR_ODB;
     177              : 
     178              :    /* read initial variable sizes */
     179            0 :    addr_changed(0, 0, info);
     180              : 
     181            0 :    return FE_SUCCESS;
     182              : }
     183              : 
     184              : /*----------------------------------------------------------------------------*/
     185              : 
     186            0 : INT mscbdev_exit(MSCBDEV_INFO * info)
     187              : {
     188              :    /* close MSCB bus */
     189            0 :    if (info) {
     190            0 :       mscb_exit(info->fd);
     191            0 :       free(info->mscbdev_settings.mscb_address);
     192            0 :       free(info->mscbdev_settings.mscb_index);
     193            0 :       free(info->mscbdev_settings.var_size);
     194            0 :       free(info);
     195              :    }
     196              : 
     197            0 :    return FE_SUCCESS;
     198              : }
     199              : 
     200              : /*----------------------------------------------------------------------------*/
     201              : 
     202            0 : INT mscbdev_set(MSCBDEV_INFO * info, INT channel, float value)
     203              : {
     204              :    INT value_int;
     205              : 
     206            0 :    if (info->mscbdev_settings.var_size[channel] == -1) {
     207              :       /* channel is "float" */
     208            0 :       mscb_write(info->fd, info->mscbdev_settings.mscb_address[channel],
     209            0 :                  info->mscbdev_settings.mscb_index[channel], &value, sizeof(float));
     210              :    } else {
     211              :       /* channel is int */
     212            0 :       value_int = (INT) value;
     213            0 :       mscb_write(info->fd, info->mscbdev_settings.mscb_address[channel],
     214            0 :                  info->mscbdev_settings.mscb_index[channel], &value_int,
     215            0 :                  info->mscbdev_settings.var_size[channel]);
     216              :    }
     217              : 
     218            0 :    return FE_SUCCESS;
     219              : }
     220              : 
     221              : /*----------------------------------------------------------------------------*/
     222              : 
     223            0 : INT mscbdev_read_all(MSCBDEV_INFO * info)
     224              : {
     225              :    int i, j, status, i_start, i_stop, v_start, v_stop, addr, size;
     226              :    unsigned char buffer[256], *pbuf;
     227              :    static DWORD last_error = 0;
     228              : 
     229              :    /* find consecutive ranges in variables */
     230            0 :    v_start = v_stop = 0;
     231            0 :    i_start = i_stop = info->mscbdev_settings.mscb_index[0];
     232            0 :    addr = info->mscbdev_settings.mscb_address[0];
     233              : 
     234            0 :    for (i = 1; i <= info->num_channels; i++) {
     235            0 :       if (i == info->num_channels ||                            // read last chunk
     236            0 :           i_stop - i_start >= 60 ||                             // not more than 60 vars (->240 bytes)
     237            0 :           info->mscbdev_settings.mscb_address[i] != addr ||     // if at different address
     238            0 :           info->mscbdev_settings.mscb_index[i] != i_stop + 1) { // if non-consecutive index
     239              : 
     240              :          /* complete range found, so read it */
     241            0 :          size = sizeof(buffer);
     242            0 :          if (i_start == i_stop) {
     243              :             /* read single value (bug in old mscbmain.c) */
     244            0 :             status = mscb_read(info->fd, addr, i_start, buffer, &size);
     245            0 :             if (info->mscbdev_settings.var_size[v_start] == -1)
     246            0 :                DWORD_SWAP(buffer);
     247              :          } else {
     248            0 :             status = mscb_read_range(info->fd, addr, i_start, i_stop, buffer, &size);
     249              :          }
     250              : 
     251            0 :          if (status != MSCB_SUCCESS) {
     252              :             /* only produce error once every minute */
     253            0 :             if (ss_time() - last_error >= 60) {
     254            0 :                last_error = ss_time();
     255              :                char str[512];
     256            0 :                sprintf(str, "Read error submaster %s address %d", info->mscbdev_settings.mscb_device, addr);
     257            0 :                mfe_error(str);
     258              :             }
     259            0 :             for (j = v_start; j <= v_stop; j++)
     260            0 :                info->mscbdev_settings.var_cache[j] = (float) ss_nan();
     261            0 :             return FE_ERR_HW;
     262              :          }
     263              : 
     264              :          /* interprete buffer */
     265            0 :          pbuf = buffer;
     266            0 :          for (j = v_start; j <= v_stop; j++) {
     267            0 :             if (info->mscbdev_settings.var_size[j] == -1) {
     268            0 :                DWORD_SWAP(pbuf);
     269            0 :                info->mscbdev_settings.var_cache[j] = *((float *) pbuf);
     270            0 :                pbuf += sizeof(float);
     271            0 :             } else if (info->mscbdev_settings.var_size[j] == 4) {
     272            0 :                DWORD_SWAP(pbuf);
     273            0 :                info->mscbdev_settings.var_cache[j] = (float) *((unsigned int *) pbuf);
     274            0 :                pbuf += sizeof(unsigned int);
     275            0 :             } else if (info->mscbdev_settings.var_size[j] == 2) {
     276            0 :                WORD_SWAP(pbuf);
     277            0 :                info->mscbdev_settings.var_cache[j] = (float) *((unsigned short *) pbuf);
     278            0 :                pbuf += sizeof(unsigned short);
     279              :             } else {
     280            0 :                info->mscbdev_settings.var_cache[j] = (float) *((unsigned char *) pbuf);
     281            0 :                pbuf += sizeof(unsigned char);
     282              :             }
     283              :          }
     284              : 
     285            0 :          if (i < info->num_channels) {
     286            0 :             v_start = v_stop = i;
     287            0 :             i_start = i_stop = info->mscbdev_settings.mscb_index[i];
     288            0 :             addr = info->mscbdev_settings.mscb_address[i];
     289              :          }
     290            0 :       } else {
     291            0 :          i_stop++;
     292            0 :          v_stop++;
     293              :       }
     294              : 
     295              :    }
     296              : 
     297            0 :    return FE_SUCCESS;
     298              : }
     299              : 
     300              : /*----------------------------------------------------------------------------*/
     301              : 
     302            0 : INT mscbdev_get(MSCBDEV_INFO * info, INT channel, float *pvalue)
     303              : {
     304              :    INT status;
     305              : 
     306              :    /* check if value was previously read by mscbhvr_read_all() */
     307            0 :    if (!ss_isnan(info->mscbdev_settings.var_cache[channel])) {
     308            0 :       *pvalue = info->mscbdev_settings.var_cache[channel];
     309            0 :       info->mscbdev_settings.var_cache[channel] = (float) ss_nan();
     310            0 :       return FE_SUCCESS;
     311              :    }
     312              : 
     313            0 :    status = mscbdev_read_all(info);
     314            0 :    *pvalue = info->mscbdev_settings.var_cache[channel];
     315            0 :    info->mscbdev_settings.var_cache[channel] = (float) ss_nan();
     316              : 
     317            0 :    return status;
     318              : }
     319              : 
     320              : /*----------------------------------------------------------------------------*/
     321              : 
     322            0 : INT mscbdev_get_label(MSCBDEV_INFO * info, INT channel, char *name)
     323              : {
     324              : 
     325            0 :    mstrlcpy(name, info->mscbdev_settings.label+channel*16, NAME_LENGTH);
     326            0 :    name[8] = 0;
     327            0 :    return MSCB_SUCCESS;
     328              : 
     329              :    /*
     330              :    int status;
     331              :    MSCB_INFO_VAR var_info;
     332              : 
     333              :    status = mscb_info_variable(info->fd, info->mscbdev_settings.mscb_address[channel],
     334              :                                info->mscbdev_settings.mscb_index[channel], &var_info);
     335              :    if (status == MSCB_SUCCESS) {
     336              :       mstrlcpy(name, var_info.name, NAME_LENGTH);
     337              :       name[8] = 0;
     338              :    }
     339              : 
     340              :    return status;
     341              :    */
     342              : }
     343              : 
     344              : /*---- device driver entry point -----------------------------------*/
     345              : 
     346            0 : INT mscbdev(INT cmd, ...)
     347              : {
     348              :    va_list argptr;
     349              :    HNDLE hKey;
     350              :    INT channel, status;
     351              :    float value, *pvalue;
     352              :    MSCBDEV_INFO *info;
     353              :    char *name;
     354              : 
     355            0 :    va_start(argptr, cmd);
     356            0 :    status = FE_SUCCESS;
     357              : 
     358            0 :    switch (cmd) {
     359            0 :    case CMD_INIT: {
     360            0 :       hKey = va_arg(argptr, HNDLE);
     361            0 :       MSCBDEV_INFO **pinfo = va_arg(argptr, MSCBDEV_INFO**);
     362            0 :       channel = va_arg(argptr, INT);
     363            0 :       va_arg(argptr, DWORD);
     364            0 :       func_t* bd = va_arg(argptr, func_t *);
     365            0 :       status = mscbdev_init(hKey, pinfo, channel, bd);
     366            0 :       break;
     367              :    }
     368            0 :    case CMD_EXIT:
     369            0 :       info = va_arg(argptr, MSCBDEV_INFO *);
     370            0 :       status = mscbdev_exit(info);
     371            0 :       break;
     372              : 
     373            0 :    case CMD_SET:
     374            0 :       info = va_arg(argptr, MSCBDEV_INFO *);
     375            0 :       channel = va_arg(argptr, INT);
     376            0 :       value = (float) va_arg(argptr, double);   // floats are passed as double
     377            0 :       status = mscbdev_set(info, channel, value);
     378            0 :       break;
     379              : 
     380            0 :    case CMD_GET:
     381              :    case CMD_GET_DIRECT:
     382            0 :       info = va_arg(argptr, MSCBDEV_INFO *);
     383            0 :       channel = va_arg(argptr, INT);
     384            0 :       pvalue = va_arg(argptr, float *);
     385            0 :       status = mscbdev_get(info, channel, pvalue);
     386            0 :       break;
     387              : 
     388            0 :    case CMD_GET_LABEL:
     389            0 :       info = va_arg(argptr, MSCBDEV_INFO *);
     390            0 :       channel = va_arg(argptr, INT);
     391            0 :       name = va_arg(argptr, char *);
     392            0 :       status = mscbdev_get_label(info, channel, name);
     393            0 :       break;
     394              : 
     395            0 :    case CMD_GET_DEMAND_DIRECT:
     396            0 :       info = va_arg(argptr, MSCBDEV_INFO *);
     397            0 :       channel = va_arg(argptr, INT);
     398            0 :       pvalue = va_arg(argptr, float *);
     399            0 :       status = mscbdev_get(info, channel, pvalue);
     400            0 :       break;
     401              : 
     402            0 :       default:
     403            0 :       break;
     404              :    }
     405              : 
     406            0 :    va_end(argptr);
     407              : 
     408            0 :    return status;
     409              : }
     410              : 
     411              : /*------------------------------------------------------------------*/
        

Generated by: LCOV version 2.0-1