//******************************************************************************************** // // Name: meter.c // Created by: Razvan Stefan Gornea // // Contents: Device driver for a portable multimeter // // Log: 2004-01-15 14:22 // Writing down initial code. // //******************************************************************************************** #include #include #include #include "midas.h" // globals variables #define DEFAULT_TIMEOUT 10000 // 10 secondes typedef struct { int address; } METERDEV_SETTINGS; #define METERDEV_SETTINGS_STR "\ Address = INT : 1\n\ " typedef struct { METERDEV_SETTINGS meterdev_settings; // device settings float *array; // data array INT num_channels; // number of channels associated with this device INT (*bd)(INT cmd, ...); // bus driver entry function void *bd_info; // private settings and data related to the bus driver HNDLE hkey; // ODB key for bd_info structure } METERDEV_INFO; // routines // initialization function: access the ODB to creates the settings, initializes the variables // and calls the initialization function of the bus driver INT meterdev_init(HNDLE hkey, void **pinfo, INT channels, INT (*bd)(INT cmd, ...)) { int status, size; HNDLE hDB, hkeydd; METERDEV_INFO *info; // allocate info structure info = calloc(1, sizeof(METERDEV_INFO)); *pinfo = info; // get handle on current experiment ODB cm_get_experiment_database(&hDB, NULL); // create METERDEV settings record status = db_create_record(hDB, hkey, "DD", METERDEV_SETTINGS_STR); // force the ODB structure to match the METERDEV_SETTINGS C structure if (status != DB_SUCCESS) { return FE_ERR_ODB; } db_find_key(hDB, hkey, "DD", &hkeydd); // get handle on the DD key in the ODB associated with a certain equipment and device as pointed by the "hkey" handle size = sizeof(info->meterdev_settings); // get the size of the device settings structure db_get_record(hDB, hkeydd, &info->meterdev_settings, &size, 0); // load the device settings for the ODB, i.e. ontent of DD key // initialize the driver info->num_channels = channels; // define the nmber of channels info->array = calloc(channels, sizeof(float)); // allocate space for data info->bd = bd; // set handle on bus driver info->hkey = hkey; // set handle on the ODB key for the evice driver if (!bd) { // if handle invalid return error return FE_ERR_ODB; } // call the bus driver initialization routine status = info->bd(CMD_INIT, info->hkey, &info->bd_info); if (status != SUCCESS) { return status; } // initialization of device, something like ... //BD_PUTS("init"); // for this device no initialization string is needed ... return FE_SUCCESS; } // decomission function: free memory allocation(s) and close device(s) INT meterdev_exit(METERDEV_INFO *info) { // call EXIT function of bus driver, usually closes device info->bd(CMD_EXIT, info->bd_info); // free local variables if (info->array) { free(info->array); } free(info); return FE_SUCCESS; } // set channel value INT meterdev_set(METERDEV_INFO *info, INT channel, float value) { char str[80]; // set channel to a specific value, something like ... sprintf(str, "SET %d %lf", channel, value); BD_PUTS(str); BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT); // simulate writing by storing value in local array, has to be removed in a real driver if (channel < info->num_channels) { info->array[channel] = value; } return FE_SUCCESS; } // set all channels values INT meterdev_set_all(METERDEV_INFO *info, INT channels, float *value) { int i; char str[1000]; // put here some optimized form of setting all channels simultaneously like ... strcpy(str, "SETALL "); for (i=0 ; inum_channels, channels) ; i++) { sprintf(str+strlen(str), "%lf ", value[i]); } BD_PUTS(str); BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT); // simulate writing by storing values in local array for (i=0 ; inum_channels, channels) ; i++) { info->array[i] = value[i]; } return FE_SUCCESS; } // get channel value INT meterdev_get(METERDEV_INFO *info, INT channel, float *pvalue) { int status, i; char str[80]; char ascii_number[5]; // read value from channel, something like ... //sprintf(str, "GET %d", channel); sprintf(str, "D"); // request data BD_PUTS(str); status = BD_GETS(str, sizeof(str), "\n", DEFAULT_TIMEOUT); // read until getting a cariage return or exit on timeout for (i = 0; i < 4; i++) { // transfer the number ascii_number[i] = str[i+4]; } ascii_number[4] = '\0'; // end of string *pvalue = (float) atof(ascii_number); // convert from ASCII to float // simulate reading by copying set data from local array //if (channel < info->num_channels) { // *pvalue = info->array[channel]; //} //else { // *pvalue = 0.f; //} return FE_SUCCESS; } // get all channels values INT meterdev_get_all(METERDEV_INFO *info, INT channels, float *pvalue) { // int i; /* put here some optimized form of reading all channels. If the deviced does not support such a function, one can call nulldev_get() in a loop strcpy(str, "GETALL"); BD_PUTS(str); BD_GETS(str, sizeof(str), ">", DEFAULT_TIMEOUT); for (i=0 ; inum_channels, channels) ; i++) pvalue[i] = atof(str+i*5); // extract individual values from reply */ /* simulate reading by copying set data from local array */ //for (i=0 ; inum_channels, channels) ; i++) // pvalue[i] = info->array[i]; return FE_SUCCESS; } // device driver entry point INT meterdev(INT cmd, ...) { va_list argptr; HNDLE hKey; INT channel, status; DWORD flags; float value, *pvalue; void *info, *bd; va_start(argptr, cmd); status = FE_SUCCESS; switch (cmd) { case CMD_INIT: hKey = va_arg(argptr, HNDLE); info = va_arg(argptr, void *); channel = va_arg(argptr, INT); flags = va_arg(argptr, DWORD); bd = va_arg(argptr, void *); status = meterdev_init(hKey, info, channel, bd); break; case CMD_EXIT: info = va_arg(argptr, void *); status = meterdev_exit(info); break; case CMD_SET: info = va_arg(argptr, void *); channel = va_arg(argptr, INT); value = (float) va_arg(argptr, double); // floats are passed as double status = meterdev_set(info, channel, value); break; case CMD_SET_ALL: info = va_arg(argptr, void *); channel = va_arg(argptr, INT); pvalue = (float *) va_arg(argptr, float *); status = meterdev_set_all(info, channel, pvalue); break; case CMD_GET: info = va_arg(argptr, void *); channel = va_arg(argptr, INT); pvalue = va_arg(argptr, float*); status = meterdev_get(info, channel, pvalue); break; case CMD_GET_ALL: info = va_arg(argptr, void *); channel = va_arg(argptr, INT); pvalue = va_arg(argptr, float*); status = meterdev_get_all(info, channel, pvalue); break; default: break; } va_end(argptr); return status; }