Back Midas Rome Roody Rootana
  Midas DAQ System, Page 48 of 142  Not logged in ELOG logo
ID Date Authordown Topic Subject
  1990   02 Sep 2020 Ruslan PodviianiukForumTransition status message
Hello,

I got an error after start of run and it would be good to show this error (or 
errors) in UI that I am developing. I see this error in the Transition 
directory (please see the attached file). Is it possible to read the status 
message and error messages from the Transition directory using jsonrpc? If yes, 
could you please explain me how to do this.

Thank you.
Ruslan  
Attachment 1: issue.png
issue.png
  1992   02 Sep 2020 Ruslan PodviianiukForumTransition status message
> The information you want is in the ODB:
> * "/System/Transition/status" is the overall integer status code.
> * "/System/Transition/error" is the overall error message string.
> 
> There is also per-client status information in the ODB:
> * "/System/Transition/Clients/<client_name>/status"
> * "/System/Transition/Clients/<client_name>/error"


Thank you so much, Ben!
  1996   08 Sep 2020 Ruslan PodviianiukForumTransition status message
> > > The information you want is in the ODB:
> > > * "/System/Transition/status" is the overall integer status code.
> > > * "/System/Transition/error" is the overall error message string.
> > > 
> > > There is also per-client status information in the ODB:
> > > * "/System/Transition/Clients/<client_name>/status"
> > > * "/System/Transition/Clients/<client_name>/error"
> 
> You can also use web page .../resources/transition.html as an example of how
> to read transition (and other) data from ODB into your own web page. example.html
> may also be helpful.
> 
> K.O.

Thank you Konstantin!

Ruslan
  2092   16 Feb 2021 Ruslan PodviianiukForumm is not defined error
Hello,

I see this mhttpd error starting MSL-script: 
Uncaught (in promise) ReferenceError: m is not defined
at mhttpd_message (VM2848 mhttpd.js:2304)
at VM2848 mhttpd.js:2122

As I can see it does not affect work of MSL script but shows ReferenceError in 
Midas sequencer (see picture).

Could please point me how to fix this error?

Thanks.
Ruslan
Attachment 1: m_is_not_defined.png
m_is_not_defined.png
  420   04 Feb 2008 Robert PattieForumanalyzer crashes at high rates
I'm using midas to read data from a waveform digitizer at event rates of
10-30kHz. To accomplish this the digitizer is read via Block transfers and the
raw data put into a single MIDAS event.  Thus a MIDAS event could contain upto
250 physical events and at maximum 350kBytes.  In the analyzer modules I had
been analyzing the first physics event contained in a MIDAS event with no
problem.  Recently I tried to analyze all the physical events.  At low rates,
100hz-1khz, this was no problem, 1-5 physical events in a MIDAS event.  At
higher rates 10-20kHz, where there are about 40physical events per MIDAS event,
 the analyzer keeps up for a  few seconds then seg faults with " 'shared object
read from target memory' has disappear; keeping it symbols".  Any suggestions as
to why the analyzer is crashing would be very helpful.

Thanks,

Robert     
  855   28 Jan 2013 Robert PattieForumanalyzer cannot connect to the statistics database
I've managed to put the analyzer into state where it cannot connect to the 
statistics database.  The error message suggests another analyzer is connected.  
I've recompiled MIDAS and the user code, restarted the computer etc..., and the 
analyzer cannot connect.  If I run "odbedit -c clean", I can start the analyzer, 
but get the same error when exiting or starting a run.  I've commented out all the
user code in the analyzer.c and its associated analyzer module's, and read event
code in the frontend and nothing resolves this issue.  Any suggestion?

The output from attempting to run the analyzer is:

Connect to experiment nnbarxwnr...[odb.c:1013:db_open_database,ERROR] Removed ODB
client 'Analyzer', index 0 because process pid 31982 does not exists
Deleted entry '/System/Clients/31982' for client 'Analyzer' because it is not
connected to ODB
OK
Root server listening on port 9090...
Loading previous online histos from ./data/last.root
ss_mutex_wait_for: pthread_mutex_lock() returned errno 22 (Invalid argument),
aborting...


When attempting to clean up the Analyzer tree in the ODB I receive the message
:"deletion of key not allowed."  

It appears that running the analyzer sets the permissions of the Statistics tree of
my analyzer module into RWDE.  

Adding the following lines to my start up script eliminate the above problem:
odbedit -c clean
odbedit -c "chmod 7 Analyzer/"
odbedit -c "rm /Analyzer/fADCs/Statistics"

Now when starting a run the analyzer crashes with this error:analyzer:
src/midas.c:11443: rpc_execute: Assertion `return_buffer' failed.
Aborted (core dumped)

and the messages in the odb are :

[system.c:4295:recv_tcp,ERROR] header: recv returned 0, n_received = 0, unexpected
connection closure
[midas.c:10042:rpc_client_call,ERROR] recv_tcp() failed, routine = "rc_transition",
host = "LANL-FADC-DAQ"
[midas.c:4130:cm_transition,ERROR] Could not start a run: cm_transition() status 503,
message 'Unknown error 503 from client 'Analyzer' on host LANL-FADC-DAQ'
Deleted entry '/System/Clients/1001' for client 'Analyzer' because process pid 1001
does not exists
[midas.c:8893:rpc_client_check,ERROR] Connection broken to "Analyzer" on host
LANL-FADC-DAQ
Run #180 start aborted
Error: Unknown error 503 from client 'Analyzer' on host LANL-FADC-DAQ

20:05:02 [Logger,INFO] Deleting previous file "./data/run00180.mid"

20:05:02 [ODBEdit,ERROR] [system.c:4295:recv_tcp,ERROR] header: recv returned 0,
n_received = 0, unexpected connection closure

20:05:02 [ODBEdit,ERROR] [midas.c:10042:rpc_client_call,ERROR] recv_tcp() failed,
routine = "rc_transition", host = "LANL-FADC-DAQ"

20:05:02 [ODBEdit,ERROR] [midas.c:4130:cm_transition,ERROR] Could not start a run:
cm_transition() status 503, message 'Unknown error 503 from client 'Analyzer' on host
LANL-FADC-DAQ'

20:05:02 [ODBEdit,INFO] Deleted entry '/System/Clients/1001' for client 'Analyzer'
because process pid 1001 does not exists

20:05:02 [ODBEdit,ERROR] [midas.c:8893:rpc_client_check,ERROR] Connection broken to
"Analyzer" on host LANL-FADC-DAQ

20:05:02 [ODBEdit,INFO] Run #180 start aborted
20:05:03 [mdump,INFO] Client 'Analyzer' on buffer 'SYSTEM' removed by cm_watchdog
because process pid 1001 does not exist
20:05:11 [mhttpd,INFO] Client 'Analyzer' (PID 1001) on database 'ODB' removed by
cm_watchdog (idle 10.1s,TO 10s)


Thanks,
Robert Pattie
  1038   12 Nov 2014 Robert PattieForumstruct mismatch
Hi all,
  I've started receiving the following error that I can't track down.  Does
anyone have a suggestion for where to start looking for the cause of this?

[Analyzer,ERROR] [odb.c:9460:db_open_record,ERROR] struct size mismatch for "/"
(expected size: 576, size in ODB: 0)

This error prevents me from running two runs in a row.  I have to close the DAQ
and restart to take multiple runs.  Also it prevents me from running the analyzer
in offline mode. 

I also noticed that several for the ODB directories no longer have the same html
format when viewed through the browser.  I've attached a screen print of the
"/Logger/Channels" page.

Thanks,
Robert
Attachment 1: logger_channels.pdf
logger_channels.pdf
  1143   24 Nov 2015 Robert PattieForumrpc_client_dispatch error
I'm trying to set up an experiment with 2 frontends for the first time.  When I
start the remote frontend I get the following errors:

first time (odd attempt):

[MCS_Frontend_203,ERROR] [midas.c:9678:rpc_server_connect,ERROR] mserver
subprocess could not be started (check path)
[MCS_Frontend_203,ERROR] [mfe.c:2696:mainFE,ERROR] Cannot connect to experiment
'Default' on host 'ucntau-daq.lanl.gov', status 503

second time (even attempt):

MCS6A_frontend: src/midas.c:9085: rpc_client_dispatch: Assertion `n ==
sizeof(NET_COMMAND_HEADER) + 4 * sizeof(INT)' failed.

On the local host I'm running : mlogger, a frontend, an analzer, mhttp, and
mserver.  I followed the instructions for adding the remote computer to the
RPC_ALLOWED list and I do see that the remote frontend was able to edit the
local odb equipment list.  At present I'm not running an event builder I just
wanted to get the frontends connected to start.  Do I need to have the mserver
running on both computers?  Any suggestions on where to start troubleshooting this?

Thanks 
  845   14 Dec 2012 Robert CaspersonBug ReportMIDAS does not function correctly on F17
When building MIDAS on Fedora 17 64-bit, the default zlib 1.2.5 shared library
is linked to.  When recording data, the "/Logger/Channels/*/Statistics/Bytes
written" value does not get set correctly beyond the first few seconds of the
run.  Occasionally, it appears to not get set at all, and mlogger aborts the run.

Installing zlib 1.2.3 in static form to /usr/local/lib (the default location),
and changing the NEED_ZLIB section of the MIDAS Makefile to the following seems
to function as a workaround:

ifdef NEED_ZLIB
CFLAGS   += -DHAVE-ZLIB
LIBS     += /usr/local/lib/libz.a
endif

Several Fedora 17 libraries expect zlib 1.2.5 specifically, so it seems safest
to not replace the default zlib shared library.

Some extra details are that the VME CPU is an XVB602, and the most recent GE-IP
drivers are being used for VME communication.  Fedora 17 was chosen to avoid a
bug with the VGA output in Fedora 13-16.
  Draft   20 Jun 2017 Richard LonglandForumHigh Rate
  1697   17 Sep 2019 Richard LonglandForummhttpd start and stop redirect to Transition page
I recently upgraded to MIDAS version midas-2019-06-b. I had to make a few changes 
to get our custom page running again, but am a little confused on starting and 
stopping runs. When I click on my "Start" button, it now redirects to a 
Transition page rather than reloading the status page. The standard MIDAS status 
page does the same. Could someone explain the reasoning for the current behavior?

Furthermore my "Stop" button is now broken with the following error:
Error: Invalid URL "CS/EngeRun&" or query "cmd=Stop&redir=EngeRun%26" or command 
"Stop"

I looked through the mhttpd.js code and managed to get the start button to load 
the status page, at least, but the stop button seems to be written differently. 
For example, start calls:
location.search = "cmd=Transition";
whereas stop does:
mhttpd_goto_page("Transition"); // DOES NOT RETURN

Can anyone offer any insights or advice? I can change the former to "cmd=Status", but 
the latter doesn't allow it.
  2278   28 Sep 2021 Richard LonglandBug ReportInstall clash between MIDAS 2020-08 and mscb
All,

I am performing a fresh install of MIDAS on an Ubuntu linux box. I follow the 
usual installation procedure:

1) git clone https://bitbucket.org/tmidas/midas --recursive
2) cd midas
3) git checkout release/midas-2020-08
4) mkdir build
5) cd build
6) cmake ..
7) make

Step 3 warns me that 
"warning: unable to rmdir 'manalyzer': Directory not empty" and 
"warning: unable to rmdir 'midasio': Directory not empty"

Step 7 fails.
Compilation fails with an mhttp error related to mscb:
mhttpd.cxx:8224:59: error: too few arguments to function 'int mscb_ping(int, 
short unsigned int, int, int)'
 8224 |             status = mscb_ping(fd, (unsigned short) ind, 1);


I was able to get around this by rolling mscb back to some old version (commit 
74468dd), but am extremely nervous about mix-and-matching the code this way.

Any advice would be greatly appreciated.

Cheers,
Richard 
  2280   29 Sep 2021 Richard LonglandBug Reportnstall clash between MIDAS 2020-08 and mscb
Thank you, Stefan.

I found these instructions under
1) The changelog: https://midas.triumf.ca/MidasWiki/index.php/Changelog#2020-12
2) Konstantin's elog announcements (e.g. https://midas.triumf.ca/elog/Midas/2089)

I do see reference to updating the submodules under the TRIUMF install 
instructions 
(https://midas.triumf.ca/MidasWiki/index.php/Setup_MIDAS_experiment_at_TRIUMF#Inst
all_MIDAS) although perhaps it can be clarified.

Cheers,
Richard
  96   20 Nov 2003 Renee Poutissou cannot shutdown defunct clients
Indeed the ODB command "cleanup" really works. I have used it several
times with the TWIST DAQ and regularly with the BNMR/MUSR setups where
we have these stubborn clients (ie feepics) that do not want to shutdown
cleanly.  
But there is one problem with "cleanup". It has a hardwired timeout of
2 seconds.  This is a problem for tasks like lazylogger which set a timeout
of 60 seconds when moving the tape. So BEWARE, if you issue the "cleanup"
command, it might kill some clients who have setup their timeout to longer
than 2 seconds. 

I have asked Stefan to change this before. He said that, to be effective,
the timeout value used for "cleanup" has to be rather short. 
One possibility, would be to allow for a user entered "cleanup" timeout.
The default could stay at 2 seconds. 




> > Have you tried a "cleanup" in ODBEdit?
> 
> Nope. Will try next time...
> 
  11   11 Mar 2004 Renee Poutissou Creation of secondary Midas output file.
Jan , 

Do you need to log this stage 1 output?  If not, you would use the 
eventbuilder mechanism to create your stage 2 events.  
I use the eventbuilder mechanism with success for my TWIST experiment.

Renee
  171   02 Nov 2004 Renee PoutissouInfoEvent Builder info in mhttpd Status page
Information about the Event Builder statistics has been removed from the 
Status page in mhttpd.  I heard from Pierre that this information might 
be redundant when using the new Event Builder format??? 
For the TWIST experiment, we are running and cannot change on the fly
to a new format Event Builder.  It is very important for us to show the users
the rates and statistics coming out of the EventBuilder.  I had  to put this
piece of code back in mhttpd.  
Can I put it back in the distribution? or do I have to put a special TWIST flag? 
or do I have to keep reinserting this every time there is an update to mhttpd.c? 
At the moment, TWIST is generating a couple of updates/week to mhttpd.c
  543   17 Dec 2008 Renee PoutissouBug ReportOverflow on "cm_msg" command generates segfault
The following error has been reported to me by T2K colleagues:

When using  "odbedit -c "msg my_message", the following behavior 
has been observed depending on the length "n" of the message. 

1)  n < 100        All is well
2)  100 <= n < 245 Log not written but exit code = 0
3)  245 <= n < 280 Error: "Experiment not defined" and exit code = 1
4)  280 <= n       Error: "Cannot connect to remote host" and exit code = 1

Also, when logging from compiled C code - when messages reach some magic length
the MIDAS client sending them segfaults.

Please fix
  558   23 Jan 2009 Renee PoutissouInfoSubrun scheme implemented
Hi Stefan,
My colleague Tobi Raufer (tobi.raufer@stfc.ac.uk) has tested this new implementation and
sent me the following questions:
-------- Original Message --------
Subject: Re: [Fwd: [Midas] Subrun scheme implemented]
Date: Fri, 23 Jan 2009 01:52:37 +0000
From: Tobias Raufer <tobi.raufer@stfc.ac.uk>
To: Renee Poutissou <renee@triumf.ca>
Hi Renee

I have tested the new subrun functionality a bit more and I have two observations. First, it seems to work on a basic level, i.e. subruns are created, which are equal in size. However, I can't relate their size to the byte limit set in the ODB.

Here is an example. The settings in the ODB are the following:
[local:testExp:S]/>ls /Logger/Channels/0/Settings/
Active y
Type Disk
Filename run%05d_%02d.mid
Format MIDAS
Compression 0
ODB dump n
Log messages 0
Buffer SYSTEM
Event ID -1
Trigger mask -1
Event limit 0
Byte limit 0
Subrun Byte limit 10000
Tape capacity 0
Subdir format
Current filename run00005_07.mid

As you can see, I set the subrun byte limit to 10000. Here are the subrun files which were created:

-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_00.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_01.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_02.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_03.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_04.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_05.mid
-rw-r--r-- 1 raufer 32800 Jan 23 01:36 run00005_06.mid
-rw-r--r-- 1 raufer 4960 Jan 23 01:36 run00005_07.mid

The file size seems to be 32800 bytes. Any idea what's going on? I first thought this might have to do with the ODB dump not being accounted for but as you can see from the configuration above, I turned it off for this run.

When I run with the ODB dump on but with the same byte limit, things become even more strange. I get the following sizes:

bash-3.2$ ls -l run00006_*.mid
-rw-r--r-- 1 raufer 53798 Jan 23 01:46 run00006_00.mid
-rw-r--r-- 1 raufer 53804 Jan 23 01:46 run00006_01.mid
-rw-r--r-- 1 raufer 53793 Jan 23 01:46 run00006_02.mid
-rw-r--r-- 1 raufer 53781 Jan 23 01:46 run00006_03.mid
-rw-r--r-- 1 raufer 53781 Jan 23 01:46 run00006_04.mid
-rw-r--r-- 1 raufer 53781 Jan 23 01:46 run00006_05.mid
-rw-r--r-- 1 raufer 53802 Jan 23 01:46 run00006_06.mid
-rw-r--r-- 1 raufer 53833 Jan 23 01:46 run00006_07.mid
-rw-r--r-- 1 raufer 71557 Jan 23 01:46 run00006_08.mid
-rw-r--r-- 1 raufer 20999 Jan 23 01:46 run00006_09.mid

As you can see, now the sizes are larger and they don't even seem to be consistent between the different subruns. Renee, could you forward this to the MIDAS developers?

Thanks much,

Tobi



Quote:

The code has been tested in two test environments, but not yet in a real experiment. So please test it before going into production. The modification in mlogger requires SVN revision 4440 of mlogger.c and 4441 of odb.c.

Please note that the lazylogger cannot be used with this scheme at the moment since it does not recognize the subruns. That will be fixed in a future version and announced in this forum.

- Stefan
  5   14 Jan 2004 Razvan Stefan Gornea Access to hardware in the MIDAS framework
I am just starting to explore MIDAS, i.e. reading the manual and trying 
some examples. For the moment I would like to make a simple frontend that 
access a portable multimeter through RS-232 port. I think this could help 
me understand how to access hardare inside MIDAS framework. Initially I've 
started from the MiniFE.c example and tried to initialize the serial port 
on run start transition and build a readout loop in the main function. I 
know that this is not a full frontend but I was just interested in getting 
some experience with the drivers available in the distribution, in this 
case RS-232. The portable multimeter is very simple in principle, one just 
has to configure the port settings and then send character 'R' and read 14 
ASCII characters from the device. Unfortunately I could not understand how 
to invoke the driver services so I changed and started again with the 
slowcont/frontend.c example. From this example and after reading the "Slow 
Control System" section in the MIDAS manual I think that all I need to do 
is to define my own equipment structure based on the multi.c class driver 
with a single input channel (and replace the null driver with the RS-232).

Here I got stuck. I see from the code source that there is a relationship 
between drivers at all levels (even bus) and the ODB but I don't yet fully 
understand how they work. Actually for a couple of days now I am in a loop 
going from class to device to bus and then back again to class drivers 
trying to see how to create my own device driver and especially how to call 
the bus driver. It could be that the framework is invoking the drivers and 
the user just has to configure things ... up to now I didn't dare to look 
at the mfe.c.

Is there a more detailed documentation about slow control and drivers then 
the MIDAS manual? What is the data flow through the three layers system for 
drivers? What is the role of the framework and what is left to the user 
choice?

Thanks
  7   16 Jan 2004 Razvan Stefan Gornea Access to hardware in the MIDAS framework
The multimeter device is indeed to simple to use MIDAS but I am just trying 
it as a learning experience. The DAQ system to develop involves VME crates 
and general purpose I/O boards. The slow control part, especially accessing 
the I/O boards seem to me more complex then the VME access. I want to 
understand very well the "correct" way of using the MIDAS slow control 
framework before starting the project.

I chose the second method and created a meterdev.c driver (essentially a 
copy of the nulldev.c) where I changed the init. function and the get 
function. I am not sending a "INIT ..." string because for this device it 
is useless. In the get function I send a "D" and read my string. I changed 
the frontend of the example to have a new driver list (in the first try I 
eliminated the Output device but the ODB got corrupted, I guess the class 
multi needs to have defined output channels). The output channel is linked 
with nulldev and null (I guess this is like if they would not be present).

The result is strange because the get function is called all the time very 
fast (much faster then the 9 seconds as set in the equipment) and even 
before starting the run (I just put the flag RO_RUNNING).

Thanks for any help
Attachment 1: frontend.c
//********************************************************************************************
//
// Name:		frontend.c
// Created by:	Razvan Stefan Gornea
//
// Contents:	Slow Control frontend for a portable multimeter
//
// Log:			2004-01-15 14:22
//				Writing down initial code.
//
//********************************************************************************************

#include <stdio.h>
#include "midas.h"
#include "class/multi.h"
#include "device/nulldev.h"
#include "meterdev.h"
#include "bus/null.h"
#include "bus/rs232.h"

// globals variables

// frontend name
char *frontend_name = "Slow Control";
// frontend file name
char *frontend_file_name = __FILE__;
// frontend loop
BOOL frontend_call_loop = FALSE;
// frontend display refresh
INT display_period = 1000;
// maximum event size in bytes
INT max_event_size = 10000;
// maximum event size for fragments in bytes
INT max_event_size_frag = 5*1024*1024;
// buffer size in bytes
INT event_buffer_size = 10*10000;

// equipment list

// device drivers
DEVICE_DRIVER multi_driver[] = {
	{"Input", meterdev, 1, rs232, DF_INPUT},
	{"Output", nulldev, 1, null, DF_OUTPUT},
	{""}
};
// equipment list
EQUIPMENT equipment[] = {
  { "Multimeter",         /* equipment name */
    11, 0,                /* event ID, trigger mask */
    "SYSTEM",             /* event buffer */
    EQ_SLOW,              /* equipment type */
    0,                    /* event source */
    "FIXED",              /* format */
    TRUE,                 /* enabled */
    RO_RUNNING,           /* read when running */
    9000,                 /* read every 9 sec */
    0,                    /* stop run after this event limit */
    0,                    /* number of sub events */
    1,                    /* log history every event */
    "", "", "",
    cd_multi_read,        /* readout routine */
    cd_multi,             /* class driver main routine */
    multi_driver,         /* device driver list */
    NULL,                 /* init string */
  },
  { "" }
};

// routines

INT  poll_event(INT source[], INT count, BOOL test) {return 1;};
INT  interrupt_configure(INT cmd, INT source[], PTYPE adr) {return 1;};
// frontend initialization
INT frontend_init()
{
  return CM_SUCCESS;
}
// frontend exit
INT frontend_exit()
{
  return CM_SUCCESS;
}
// frontend loop
INT frontend_loop()
{
  return CM_SUCCESS;
}
// begin of run
INT begin_of_run(INT run_number, char *error)
{
  return CM_SUCCESS;
}
// end of run
INT end_of_run(INT run_number, char *error)
{
  return CM_SUCCESS;
}
// pause run
INT pause_run(INT run_number, char *error)
{
  return CM_SUCCESS;
}
// resume run
INT resume_run(INT run_number, char *error)
{
  return CM_SUCCESS;
}
Attachment 2: meterdev.c
//********************************************************************************************
//
// 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#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 ; i<min(info->num_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 ; i<min(info->num_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 ; i<min(info->num_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 ; i<min(info->num_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;
}
ELOG V3.1.4-2e1708b5