Back Midas Rome Roody Rootana
  Midas DAQ System, Page 7 of 138  Not logged in ELOG logo
ID Date Author Topic Subjectdown
  1334   04 Dec 2017 Stefan RittBug Reportsmall bug in mfe.c init
> Thanks, I misunderstood the loop then. If poll_event(equipment[idx].info.source, (INT)count, TRUE); doesn`t do anything with "count", the loop becomes infinite except for the overflow 
> check. 

Well, the function poll_event() is _supposed_ to use "count" in a for loop as written in the example frontend:

   for (i = 0; i < count; i++) {
      /* poll hardware and set flag to TRUE if new event is available */
      flag = TRUE;

      if (flag)
         if (!test)
            return TRUE;
   }

where "flag = TRUE" must be replaced with the proper hardware check. This can be a VME access, a network TCP exchange with some Ethernet based hardware, or even a mutex check if the events are collected by a 
separate thread in the frontend.

The idea of having the for (i=0 ; i<count ; i++) loop _inside_ the poll_event() function and not outside is the fact that each function call to poll_event() takes time, and we want the minimal possible response time to new 
events. It might be just a micro-second, but having an experiment running at 100 Hz for one year (like Mu3e), this adds up to about one hour per year, which is a considerable amount of precious beam time.

Stefan
  1942   10 Jun 2020 Ivo SchulthessForumslow-control equipment crashes when running multi-threaded on a remote machine
Dear all

To reduce the time needed by Midas between runs, we want to change some of our periodic equipment to multi-threaded slow-control equipment. To do that I wanted to start from 
the slowcont with the multi/hv class driver and the nulldev device driver and null bus driver. The example runs fine as it is on the local midas machine and also on remote 
machines. When adding the DF_MULTITHREAD flag to the device driver list, it does not run anymore on remote machines but aborts with the following assertion:

scfe: /home/neutron/packages/midas/src/midas.cxx:1569: INT cm_get_path(char*, int): Assertion `_path_name.length() > 0' failed.

Running the frontend with GDB and set a breakpoint at the exit leads to the following: 

(gdb) where
#0  0x00007ffff68d599f in raise () from /lib64/libc.so.6
#1  0x00007ffff68bfcf5 in abort () from /lib64/libc.so.6
#2  0x00007ffff68bfbc9 in __assert_fail_base.cold.0 () from /lib64/libc.so.6
#3  0x00007ffff68cde56 in __assert_fail () from /lib64/libc.so.6
#4  0x000000000041efbf in cm_get_path (path=0x7fffffffd060 "P\373g", path_size=256)
    at /home/neutron/packages/midas/src/midas.cxx:1563
#5  cm_get_path (path=path@entry=0x7fffffffd060 "P\373g", path_size=path_size@entry=256)
    at /home/neutron/packages/midas/src/midas.cxx:1563
#6  0x0000000000453dd8 in ss_semaphore_create (name=name@entry=0x7fffffffd2c0 "DD_Input", 
    semaphore_handle=semaphore_handle@entry=0x67f700 <multi_driver+96>)
    at /home/neutron/packages/midas/src/system.cxx:2340
#7  0x0000000000451d25 in device_driver (device_drv=0x67f6a0 <multi_driver>, cmd=<optimized out>)
    at /home/neutron/packages/midas/src/device_driver.cxx:155
#8  0x00000000004175f8 in multi_init(eqpmnt*) ()
#9  0x00000000004185c8 in cd_multi(int, eqpmnt*) ()
#10 0x000000000041c20c in initialize_equipment () at /home/neutron/packages/midas/src/mfe.cxx:827
#11 0x000000000040da60 in main (argc=1, argv=0x7fffffffda48)
    at /home/neutron/packages/midas/src/mfe.cxx:2757

I also tried to use the generic class driver which results in the same. I am not sure if this is a problem of the multi-threaded frontend running on a remote machine or is it 
something of our system which is not properly set up. Anyway I am running out of ideas how to solve this and would appreciate any input. 

Thanks in advance,
Ivo
  1944   10 Jun 2020 Konstantin OlchanskiForumslow-control equipment crashes when running multi-threaded on a remote machine
Yes, it is supposed to crash. On a remote frontend, cm_get_path() cannot be used
(we are on a different computer, all filesystems maybe no the same!) and is actually not set and
triggers a trap if something tries to use it. (this is the crash you see).

The caller to cm_get_path() is a MIDAS semaphore function.

And I think there is a mistake here. It is unusual for the driver framework to use a semaphore. For multithreaded
protection inside the frontend, a mutex would normally be used. (and mutexes do not use cm_get_path(), so
all is good). But if a semaphore is used, than all frontends running on the same computer become
serialized across the locked section. This is the right thing to do if you have multiple frontends
sharing the same hardware, i.e. a /dev/ttyUSB serial line, but why would a generic framework function
do this. I am not sure, I will have to take a look at why there is a semaphore and what it is locking/protecting.

(In midas, semaphores are normally used to protect global memory, such as ODB, or global resources, such as alarms,
against concurrent access by multiple programs, but of course that does not work for remote frontends,
they are on a different computer! semaphores only work locally, do not work across the network!)

K.O.

> 
> scfe: /home/neutron/packages/midas/src/midas.cxx:1569: INT cm_get_path(char*, int): Assertion `_path_name.length() > 0' failed.
> 
> Running the frontend with GDB and set a breakpoint at the exit leads to the following: 
> 
> (gdb) where
> #0  0x00007ffff68d599f in raise () from /lib64/libc.so.6
> #1  0x00007ffff68bfcf5 in abort () from /lib64/libc.so.6
> #2  0x00007ffff68bfbc9 in __assert_fail_base.cold.0 () from /lib64/libc.so.6
> #3  0x00007ffff68cde56 in __assert_fail () from /lib64/libc.so.6
> #4  0x000000000041efbf in cm_get_path (path=0x7fffffffd060 "P\373g", path_size=256)
>     at /home/neutron/packages/midas/src/midas.cxx:1563
> #5  cm_get_path (path=path@entry=0x7fffffffd060 "P\373g", path_size=path_size@entry=256)
>     at /home/neutron/packages/midas/src/midas.cxx:1563
> #6  0x0000000000453dd8 in ss_semaphore_create (name=name@entry=0x7fffffffd2c0 "DD_Input", 
>     semaphore_handle=semaphore_handle@entry=0x67f700 <multi_driver+96>)
>     at /home/neutron/packages/midas/src/system.cxx:2340
> #7  0x0000000000451d25 in device_driver (device_drv=0x67f6a0 <multi_driver>, cmd=<optimized out>)
>     at /home/neutron/packages/midas/src/device_driver.cxx:155
> #8  0x00000000004175f8 in multi_init(eqpmnt*) ()
> #9  0x00000000004185c8 in cd_multi(int, eqpmnt*) ()
> #10 0x000000000041c20c in initialize_equipment () at /home/neutron/packages/midas/src/mfe.cxx:827
> #11 0x000000000040da60 in main (argc=1, argv=0x7fffffffda48)
>     at /home/neutron/packages/midas/src/mfe.cxx:2757
> 
> I also tried to use the generic class driver which results in the same. I am not sure if this is a problem of the multi-threaded frontend running on a remote machine or is it 
> something of our system which is not properly set up. Anyway I am running out of ideas how to solve this and would appreciate any input. 
> 
> Thanks in advance,
> Ivo
  1945   10 Jun 2020 Stefan RittForumslow-control equipment crashes when running multi-threaded on a remote machine
Few comments:

- As KO write, we might need semaphores also on a remote front-end, in case several programs share the same hardware. So it should work and cm_get_path() should not just exit

- When I wrote the multi-threaded device drivers, I did use semaphores instead of mutexes, but I forgot why. Might be that midas semaphores have a timeout and mutexes not, or 
something along those lines.

- I do need either semaphores or mutexes since in a multi-threaded slow-control font-end (too many dashes...) several threads have to access an internal data exchange buffer, which 
needs protection for multi-threaded environments.

So we can how either fix cm_get_path() or replace all semaphores in with mutexes in midas/src/device_driver.cxx. I have kind of a feeling that we should do both. And what about 
switching to c++ std::mutex instead of pthread mutexes?

Stefan
  1946   12 Jun 2020 Ivo SchulthessForumslow-control equipment crashes when running multi-threaded on a remote machine
Thanks you two once again for the very fast answers. I tested the example on the local machine and it works perfectly fine. In the meantime I also created two new drivers for our devices 
and everything works with them, the improvement in time is significant and I will create drivers for all our devices where possible. If they are in a working state I can also provide 
them to add to the Midas drivers. Of course if it would be possible to run the front-end also on our remote machines this would be even better. I am not experienced in any multi-threaded 
programming but if I can provide any help or input, please let me know. 

Have a great weekend,
Ivo
  2667   10 Jan 2024 Pavel MuratForumslow control frontends - how much do they sleep and how often their drivers are called?
Dear all,

I have implemented a number of slow control frontends which are directed to update the 
history once in every 10 sec, and they do just that. 

I expected that such frontends would be spending most of the time sleeping and waking up 
once in ten seconds to call their respective drivers and send the data to the server. 

However I observe that each frontend process consumes almost 100% of a single core CPU time 
and the frontend driver is called many times per second. 

Is that the expected behavior ?

So far, I couldn't find the place in the system part of the frontend code (is that the right 
place to look for?) which regulates the frequency of the frontend driver calls, so I'd greatly 
appreciate if someone could point me to that place.

I'm using the following commit:

commit 30a03c4c develop origin/develop Make sure line numbers and sequence lines are aligned.

-- many thanks, regards, Pasha
  2668   11 Jan 2024 Stefan RittForumslow control frontends - how much do they sleep and how often their drivers are called?
Put a 

  ss_sleep(10);

into your frontend_loop(), then you should be fine.

The event loop runs as fast as possible in order not to miss any (triggered) event, so no seep in the 
event loop, because this would limit the (triggered) event rate to 100 Hz (minimum sleep is 10 ms). 
Therefore, you have to slow down the event loop manually with the method described above.

Best,
Stefan
  2669   11 Jan 2024 Pavel MuratForumslow control frontends - how much do they sleep and how often their drivers are called?
Hi Stefan, thanks a lot !

I just thought that for the EQ_SLOW type equipment calls to sleep() could be hidden in mfe.cxx 
and handled based on the requested frequency of the history updates.

Doing the same in the user side is straighforward - the important part is to know where the 
responsibility line goes (: smile :) 

-- regards, Pasha
  2670   12 Jan 2024 Stefan RittForumslow control frontends - how much do they sleep and how often their drivers are called?
> Hi Stefan, thanks a lot !
> 
> I just thought that for the EQ_SLOW type equipment calls to sleep() could be hidden in mfe.cxx 
> and handled based on the requested frequency of the history updates.

Most people combine EQ_SLOW with EQ_POLLED, so they want to read out as quickly as possible. Since 
the framework cannot "guess" what the users want there, I removed all sleep() in the framework.



> Doing the same in the user side is straighforward - the important part is to know where the 
> responsibility line goes (: smile :) 


Pushing this to the user gives you more freedom. Like you can add sleep() for some frontends, but not 
for others, only when the run is stopped and more.

Stefan
  2692   28 Jan 2024 Konstantin OlchanskiForumslow control frontends - how much do they sleep and how often their drivers are called?
> I have implemented a number of slow control frontends which are directed to update the 
> history once in every 10 sec, and they do just that. 

I suggest that you switch from the old mfe.c frontend framework to the new tmfe framework that was 
designed to solve exactly this type of problems.

Look at .../midas/progs/tmfe_example*.cxx

You have a choice of:
- single threaded frontend, most robust, no race conditions, but readout is interrupted during 
begin/end of run.
- two-threaded frontend, your periodic equipments run in one thread, midas loop and rpc run in a 
different thread, you have to handle locking yourself.
- you can run each of your equipments in it's own thread without help from the framework, it is 
obvious how to do it if you can program c++ threads, "new std::thread" to create/start a thread, 
stop threads using a binary flag, thread->join() to reap them at the end (or thread sanitizer will 
complain).

K.O.
  758   10 May 2011 Jianglai LiuForumsimple example frontend for V1720
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai
  759   10 May 2011 Stefan RittForumsimple example frontend for V1720

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


During "Calibrating", the framework calls your poll_event() routine. You code there accesses for the first time the VME crate and probably gets stuck.
  760   10 May 2011 Pierre-Andre AmaudruzForumsimple example frontend for V1720

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


Under the drivers/vme you can find code for the v1720.c (VME access) and ov1720.c
(A2818/A3818 PCIe optical link access). For testing the hardware, we use this code compiled and linked
with MAIN_ENABLE to confirm its functionality. You may want to do the same for your USB. Once this
is under control, the Midas frontend implementation using the same driver shouldn't give you trouble.
  761   18 May 2011 Jimmy NgaiForumsimple example frontend for V1720

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


Hi Jianglai,

I don't have an exmaple of using V1718 with V1720, but I have been using V1718 with V792N for a long time.

You may find in the attachment an example frontend program and my drivers for V1718 and V792N written in MVMESTD format. They have to be linked with the CAENVMELib library and other essential MIDAS stuffs.

Regards,
Jimmy
Attachment 1: frontend.c
/********************************************************************\

  Name:         frontend.c
  Created by:   Jimmy Ngai

  Date:         May 9, 2010

  Contents:     Experiment specific readout code (user part) of
                Midas frontend.
		Supported VME modules:
		CAEN V1718 VME-USB Bridge
		CAEN V792N 16 CH QDC

  $Id: $

\********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "midas.h"
#include "mcstd.h"
#include "mvmestd.h"
#include "experim.h"
#include "vme/v792n.h"

/* make frontend functions callable from the C framework */
#ifdef __cplusplus
extern "C" {
#endif

/*-- Globals -------------------------------------------------------*/

/* The frontend name (client name) as seen by other MIDAS clients   */
char *frontend_name = "Frontend";
/* The frontend file name, don't change it */
char *frontend_file_name = __FILE__;

/* frontend_loop is called periodically if this variable is TRUE    */
BOOL frontend_call_loop = FALSE;

/* a frontend status page is displayed with this frequency in ms */
INT display_period = 3000;

/* maximum event size produced by this frontend */
INT max_event_size = 10000;

/* maximum event size for fragmented events (EQ_FRAGMENTED) */
INT max_event_size_frag = 5 * 1024 * 1024;

/* buffer size to hold events */
INT event_buffer_size = 10 * 10000;

/* number of channels */
#define N_ADC      16

/* VME hardware */
MVME_INTERFACE *myvme;

/* VME base address */
DWORD V1718_BASE  = 0x12000000;
DWORD V792N_BASE  = 0x32100000;

/*-- Function declarations -----------------------------------------*/

INT frontend_init();
INT frontend_exit();
INT begin_of_run(INT run_number, char *error);
INT end_of_run(INT run_number, char *error);
INT pause_run(INT run_number, char *error);
INT resume_run(INT run_number, char *error);
INT frontend_loop();

INT read_trigger_event(char *pevent, INT off);

/*-- Equipment list ------------------------------------------------*/

#undef USE_INT

EQUIPMENT equipment[] = {

   {"Trigger",               /* equipment name */
    {1, 0,                   /* event ID, trigger mask */
     "SYSTEM",               /* event buffer */
#ifdef USE_INT
     EQ_INTERRUPT,           /* equipment type */
#else
     EQ_POLLED,              /* equipment type */
#endif
     LAM_SOURCE(CRATE, LAM_STATION(SLOT_ADC)), /* event source */
     "MIDAS",                /* format */
     TRUE,                   /* enabled */
     RO_RUNNING |            /* read only when running */
     RO_ODB,                 /* and update ODB */
     500,                    /* poll for 500ms */
     0,                      /* stop run after this event limit */
     0,                      /* number of sub events */
     0,                      /* don't log history */
     "", "", "",},
    read_trigger_event,      /* readout routine */
    },

   {""}
};

#ifdef __cplusplus
}
#endif

/********************************************************************\
              Callback routines for system transitions

  These routines are called whenever a system transition like start/
  stop of a run occurs. The routines are called on the following
  occations:

  frontend_init:  When the frontend program is started. This routine
                  should initialize the hardware.

  frontend_exit:  When the frontend program is shut down. Can be used
                  to releas any locked resources like memory, commu-
                  nications ports etc.

  begin_of_run:   When a new run is started. Clear scalers, open
                  rungates, etc.

  end_of_run:     Called on a request to stop a run. Can send
                  end-of-run event and close run gates.

  pause_run:      When a run is paused. Should disable trigger events.

  resume_run:     When a run is resumed. Should enable trigger events.

\********************************************************************/

INT init_vme_modules()
{
   /* default settings */

   v792n_SoftReset(myvme, V792N_BASE);
   v792n_Setup(myvme, V792N_BASE, 2);
//   v792n_Status(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Frontend Init -------------------------------------------------*/

INT frontend_init()
{
   INT status;

   /* open VME interface */
   status = mvme_open(&myvme, 0);

   /* set am to A32 non-privileged Data */
   mvme_set_am(myvme, MVME_AM_A32_ND);

   /* initialize all VME modules */
   init_vme_modules();

   v792n_OfflineSet(myvme, V792N_BASE);
   v792n_DataClear(myvme, V792N_BASE);

   /* print message and return FE_ERR_HW if frontend should not be started */
   if (status != MVME_SUCCESS) {
      cm_msg(MERROR, "frontend_init", "VME interface could not be opened.");
      return FE_ERR_HW;
   }

   return SUCCESS;
}

/*-- Frontend Exit -------------------------------------------------*/

INT frontend_exit()
{
   /* close VME interface */
   mvme_close(myvme);

   return SUCCESS;
}

/*-- Begin of Run --------------------------------------------------*/

INT begin_of_run(INT run_number, char *error)
{
   /* Initialize all VME modules */
//   init_vme_modules();

   v792n_DataClear(myvme, V792N_BASE);
   v792n_OnlineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- End of Run ----------------------------------------------------*/

INT end_of_run(INT run_number, char *error)
{
   v792n_OfflineSet(myvme, V792N_BASE);
   v792n_DataClear(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Pause Run -----------------------------------------------------*/

INT pause_run(INT run_number, char *error)
{
   v792n_OfflineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Resuem Run ----------------------------------------------------*/

INT resume_run(INT run_number, char *error)
{
   v792n_OnlineSet(myvme, V792N_BASE);

   return SUCCESS;
}

/*-- Frontend Loop -------------------------------------------------*/

INT frontend_loop()
{
   /* if frontend_call_loop is true, this routine gets called when
      the frontend is idle or once between every event */

   return SUCCESS;
}

/*------------------------------------------------------------------*/

/********************************************************************\

  Readout routines for different events

\********************************************************************/

/*-- Trigger event routines ----------------------------------------*/

INT poll_event(INT source, INT count, BOOL test)
/* Polling routine for events. Returns TRUE if event
   is available. If test equals TRUE, don't return. The test
   flag is used to time the polling */
{
   INT i;
   DWORD lam = 0;

   for (i = 0; i < count; i++) {
      lam = v792n_DataReady(myvme, V792N_BASE);

      if (lam)
         if (!test)
            return lam;
   }

   return 0;
}

/*-- Interrupt configuration ---------------------------------------*/

INT interrupt_configure(INT cmd, INT source, POINTER_T adr)
{
   switch (cmd) {
   case CMD_INTERRUPT_ENABLE:
      break;
   case CMD_INTERRUPT_DISABLE:
      break;
   case CMD_INTERRUPT_ATTACH:
      break;
   case CMD_INTERRUPT_DETACH:
      break;
   }
   return SUCCESS;
}

/*-- Event readout -------------------------------------------------*/

INT read_v792n(INT base, const char *bk_name, char *pevent, INT n_chn)
{
   INT i;
   INT nentry = 0, counter;
   DWORD data[V792N_MAX_CHANNELS+2];
   WORD *pdata;

   /* event counter */
//   v792n_EvtCntRead(myvme, base, &counter);

   /* read event */
   v792n_EventRead(myvme, base, data, &nentry);

   /* clear ADC */
//   v792n_DataClear(myvme, base);

   /* create ADC bank */
   bk_create(pevent, bk_name, TID_WORD, &pdata);

... 29 more lines ...
Attachment 2: v1718.h
/*********************************************************************

  Name:         v1718.h
  Created by:   Jimmy Ngai

  Contents:     V1718 VME-USB2.0 bridge include

  $Id: $
*********************************************************************/
#ifndef  V1718_INCLUDE_H
#define  V1718_INCLUDE_H

#include <stdio.h>
#include <string.h>
#include "mvmestd.h"

#ifdef __cplusplus
extern "C" {
#endif

#define  V1718_STATUS_RO          (DWORD) (0x0000)
#define  V1718_VME_CTRL_RW        (DWORD) (0x0001)
#define  V1718_FW_REV_RO          (DWORD) (0x0002)
#define  V1718_FW_DWNLD_RW        (DWORD) (0x0003)
#define  V1718_FL_ENA_RW          (DWORD) (0x0004)
#define  V1718_IRQ_STAT_RO        (DWORD) (0x0005)
#define  V1718_IN_REG_RW          (DWORD) (0x0008)
#define  V1718_OUT_REG_S_RW       (DWORD) (0x000A)
#define  V1718_IN_MUX_S_RW        (DWORD) (0x000B)
#define  V1718_OUT_MUX_S_RW       (DWORD) (0x000C)
#define  V1718_LED_POL_S_RW       (DWORD) (0x000D)
#define  V1718_OUT_REG_C_WO       (DWORD) (0x0010)
#define  V1718_IN_MUX_C_WO        (DWORD) (0x0011)
#define  V1718_OUT_MAX_C_WO       (DWORD) (0x0012)
#define  V1718_LED_POL_C_WO       (DWORD) (0x0013)
#define  V1718_PULSEA_0_RW        (DWORD) (0x0016)
#define  V1718_PULSEA_1_RW        (DWORD) (0x0017)
#define  V1718_PULSEB_0_RW        (DWORD) (0x0019)
#define  V1718_PULSEB_1_RW        (DWORD) (0x001A)
#define  V1718_SCALER0_RW         (DWORD) (0x001C)
#define  V1718_SCALER1_RO         (DWORD) (0x001D)
#define  V1718_DISP_ADL_RO        (DWORD) (0x0020)
#define  V1718_DISP_ADH_RO        (DWORD) (0x0021)
#define  V1718_DISP_DTL_RO        (DWORD) (0x0022)
#define  V1718_DISP_DTH_RO        (DWORD) (0x0023)
#define  V1718_DISP_PC1_RO        (DWORD) (0x0024)
#define  V1718_DISP_PC2_RO        (DWORD) (0x0025)
#define  V1718_LM_ADL_RW          (DWORD) (0x0028)
#define  V1718_LM_ADH_RW          (DWORD) (0x0029)
#define  V1718_LM_C_RW            (DWORD) (0x002C)

WORD v1718_Read16(MVME_INTERFACE *mvme, DWORD base, int offset);
void v1718_Write16(MVME_INTERFACE *mvme, DWORD base, int offset, WORD value);
DWORD v1718_Read32(MVME_INTERFACE *mvme, DWORD base, int offset);
void v1718_Write32(MVME_INTERFACE *mvme, DWORD base, int offset, DWORD value);

void v1718_MultiRead(MVME_INTERFACE *mvme, DWORD *addrs, DWORD *value, int ncycle, int *am, int *dmode);
void v1718_MultiWrite(MVME_INTERFACE *mvme, DWORD *addrs, DWORD *value, int ncycle, int *am, int *dmode);
void v1718_MultiRead16(MVME_INTERFACE *mvme, DWORD *addrs, WORD *value, int ncycle);
void v1718_MultiWrite16(MVME_INTERFACE *mvme, DWORD *addrs, WORD *value, int ncycle);
void v1718_MultiRead32(MVME_INTERFACE *mvme, DWORD *addrs, DWORD *value, int ncycle);
void v1718_MultiWrite32(MVME_INTERFACE *mvme, DWORD *addrs, DWORD *value, int ncycle);

void v1718_PulserConfSet(MVME_INTERFACE *mvme, WORD pulser, DWORD period, DWORD width, WORD pulseNo);
void v1718_PulserStart(MVME_INTERFACE *mvme, WORD pulser);
void v1718_PulserStop(MVME_INTERFACE *mvme, WORD pulser);

  enum v1718_PulserSelect {
    v1718_pulserA=0x0,
    v1718_pulserB=0x1,
  };

#ifdef __cplusplus
}
#endif

#endif // V1718_INCLUDE_H

/* emacs
 * Local Variables:
 * mode:C
 * mode:font-lock
 * tab-width: 8
 * c-basic-offset: 2
 * End:
 */
Attachment 3: v1718.c
/********************************************************************

  Name:         v1718.c
  Created by:   Jimmy Ngai

  Contents:     Midas VME standard (MVMESTD) layer for CAEN V1718
                VME-USB2.0 Bridge using CAENVMElib Linux library

  $Id: $

\********************************************************************/

#ifdef __linux__
#ifndef OS_LINUX
#define OS_LINUX
#endif
#endif

#ifdef OS_LINUX

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "CAENVMElib.h"

#endif // OS_LINUX

#include "v1718.h"

/*------------------------------------------------------------------*/

/********************************************************************\

  MIDAS VME standard (MVMESTD) functions

\********************************************************************/

int mvme_open(MVME_INTERFACE **vme, int idx)
{
   *vme = (MVME_INTERFACE *) malloc(sizeof(MVME_INTERFACE));
   if (*vme == NULL)
      return MVME_NO_MEM;

   memset(*vme, 0, sizeof(MVME_INTERFACE));

   /* open VME */
   if (CAENVME_Init(cvV1718, 0, idx, &(*vme)->handle) != cvSuccess)
      return MVME_NO_INTERFACE;

   /* default values */
   (*vme)->am        = MVME_AM_DEFAULT;
   (*vme)->dmode     = MVME_DMODE_D32;
   (*vme)->blt_mode  = MVME_BLT_NONE;
   (*vme)->table     = NULL; // not used

   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_close(MVME_INTERFACE *vme)
{
   CAENVME_End(vme->handle);

   free(vme);

   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_sysreset(MVME_INTERFACE *vme)
{
   CAENVME_SystemReset(vme->handle);

   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_write(MVME_INTERFACE *vme, mvme_addr_t vme_addr, void *src, mvme_size_t n_bytes)
{
   mvme_size_t i;
   int status=0, n;
   int hvme;
   hvme = vme->handle;

   n = 0;

   /* D8 */
   if (vme->dmode == MVME_DMODE_D8) {
      for (i=0 ; i<n_bytes ; i++)
         status = CAENVME_WriteCycle(hvme, vme_addr, src+i, vme->am, cvD8);
      n = n_bytes;
   /* D16 */
   } else if (vme->dmode == MVME_DMODE_D16) {
      /* normal I/O */
      if (vme->blt_mode == MVME_BLT_NONE) {
         for (i=0 ; i<(n_bytes>>1) ; i++)
            status = CAENVME_WriteCycle(hvme, vme_addr, src+(i<<1), vme->am, cvD16);
         n = n_bytes;
      /* FIFO BLT */
      } else if ((vme->blt_mode == MVME_BLT_BLT32FIFO) || (vme->blt_mode == MVME_BLT_MBLT64FIFO))
         status = CAENVME_FIFOBLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, cvD16, &n);
      /* BLT */
      else
         status = CAENVME_BLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, cvD16, &n);
   /* D32 */
   } else if (vme->dmode == MVME_DMODE_D32) {
      /* normal I/O */
      if (vme->blt_mode == MVME_BLT_NONE) {
         for (i=0 ; i<(n_bytes>>2) ; i++)
            status = CAENVME_WriteCycle(hvme, vme_addr, src+(i<<2), vme->am, cvD32);
         n = n_bytes;
      /* FIFO BLT */
      } else if (vme->blt_mode == MVME_BLT_BLT32FIFO)
         status = CAENVME_FIFOBLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, cvD32, &n);
      /* BLT */
      else
         status = CAENVME_BLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, cvD32, &n);
   /* D64 */
   } else if (vme->dmode == MVME_DMODE_D64) {
      /* FIFO MBLT */
      if (vme->blt_mode == MVME_BLT_MBLT64FIFO) 
         status = CAENVME_FIFOMBLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, &n);
      /* MBLT */
      else
         status = CAENVME_MBLTWriteCycle(hvme, vme_addr, src, n_bytes, vme->am, &n);
   }

   if (status != cvSuccess)
      n = 0;

   return n;
}

/*------------------------------------------------------------------*/

int mvme_write_value(MVME_INTERFACE *vme, mvme_addr_t vme_addr, unsigned int value)
{
   int status=0, n;
   int hvme;
   hvme = vme->handle;

   if (vme->dmode == MVME_DMODE_D8)
      n = 1;
   else if (vme->dmode == MVME_DMODE_D16)
      n = 2;
   else
      n = 4;

   /* D8 */
   if (vme->dmode == MVME_DMODE_D8)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD8);
   /* D16 */
   else if (vme->dmode == MVME_DMODE_D16)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD16);
   /* D32 */
   else if (vme->dmode == MVME_DMODE_D32)
      status = CAENVME_WriteCycle(hvme, vme_addr, &value, vme->am, cvD32);

   if (status != cvSuccess)
      n = 0;

   return n;
}

/*------------------------------------------------------------------*/

int mvme_read(MVME_INTERFACE *vme, void *dst, mvme_addr_t vme_addr, mvme_size_t n_bytes)
{
   mvme_size_t i;
   int status=0, n;
   int hvme;
   hvme = vme->handle;

   n = 0;

   /* D8 */
   if ((vme->dmode == MVME_DMODE_D8) || (vme->blt_mode == MVME_BLT_NONE)) {
      for (i=0 ; i<n_bytes ; i++)
         status = CAENVME_ReadCycle(hvme, vme_addr, dst+i, vme->am, cvD8);
      n = n_bytes;
   /* D16 */
   } else if (vme->dmode == MVME_DMODE_D16) {
      /* normal I/O */
      if (vme->blt_mode == MVME_BLT_NONE) {
         for (i=0 ; i<(n_bytes>>1) ; i++)
            status = CAENVME_ReadCycle(hvme, vme_addr, dst+(i<<1), vme->am, cvD16);
         n = n_bytes;
      /* FIFO BLT */
      } else if ((vme->blt_mode == MVME_BLT_BLT32FIFO) || (vme->blt_mode == MVME_BLT_MBLT64FIFO))
         status = CAENVME_FIFOBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD16, &n);
      /* BLT */
      else
         status = CAENVME_BLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD16, &n);
   /* D32 */
   } else if (vme->dmode == MVME_DMODE_D32) {
      /* normal I/O */
      if (vme->blt_mode == MVME_BLT_NONE) {
         for (i=0 ; i<(n_bytes>>2) ; i++)
            status = CAENVME_ReadCycle(hvme, vme_addr, dst+(i<<2), vme->am, cvD32);
         n = n_bytes;
      /* FIFO BLT */
      } else if (vme->blt_mode == MVME_BLT_BLT32FIFO)
         status = CAENVME_FIFOBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD32, &n);
      /* BLT */
      else
         status = CAENVME_BLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, cvD32, &n);
   /* D64 */
   } else if (vme->dmode == MVME_DMODE_D64) {
      /* FIFO MBLT */
      if (vme->blt_mode == MVME_BLT_MBLT64FIFO)
         status = CAENVME_FIFOMBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, &n);
      /* MBLT */
      else
         status = CAENVME_MBLTReadCycle(hvme, vme_addr, dst, n_bytes, vme->am, &n);
   }

   if ((status != cvSuccess) && (status != cvBusError))
      n = 0;

   return n;
}

/*------------------------------------------------------------------*/

unsigned int mvme_read_value(MVME_INTERFACE *vme, mvme_addr_t vme_addr)
{
   unsigned int data;
   int status=0;
   int hvme;
   hvme = vme->handle;

   data = 0;

   /* D8 */
   if (vme->dmode == MVME_DMODE_D8)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD8);
   /* D16 */
   else if (vme->dmode == MVME_DMODE_D16)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD16);
   /* D32 */
   else if (vme->dmode == MVME_DMODE_D32)
      status = CAENVME_ReadCycle(hvme, vme_addr, &data, vme->am, cvD32);

   return data;
}

/*------------------------------------------------------------------*/

int mvme_set_am(MVME_INTERFACE *vme, int am)
{
   vme->am = am;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_get_am(MVME_INTERFACE *vme, int *am)
{
   *am = vme->am;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_set_dmode(MVME_INTERFACE *vme, int dmode)
{
   vme->dmode = dmode;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_get_dmode(MVME_INTERFACE *vme, int *dmode)
{
   *dmode = vme->dmode;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_set_blt(MVME_INTERFACE *vme, int mode)
{
   vme->blt_mode = mode;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/

int mvme_get_blt(MVME_INTERFACE *vme, int *mode)
{
   *mode = vme->blt_mode;
   return MVME_SUCCESS;
}

/*------------------------------------------------------------------*/
... 326 more lines ...
Attachment 4: v792n.h
/*********************************************************************

  Name:         v792n.h
  Created by:   Jimmy Ngai

  Contents:     V792N 16ch. QDC include

  Based on v792.h by Pierre-Andre Amaudruz

  $Id: $
*********************************************************************/
#ifndef  V792N_INCLUDE_H
#define  V792N_INCLUDE_H

#include <stdio.h>
#include <string.h>
#include "mvmestd.h"

#ifdef __cplusplus
extern "C" {
#endif

#define  V792N_MAX_CHANNELS       (DWORD) 16
#define  V792N_REG_BASE           (DWORD) (0x1000)
#define  V792N_FIRM_REV           (DWORD) (0x1000)
#define  V792N_GEO_ADDR_RW        (DWORD) (0x1002)
#define  V792N_MCST_CBLT_RW       (DWORD) (0x1004)
#define  V792N_BIT_SET1_RW        (DWORD) (0x1006)
#define  V792N_BIT_CLEAR1_WO      (DWORD) (0x1008)
#define  V792N_SOFT_RESET         (DWORD) (0x1<<7)
#define  V792N_INT_LEVEL_WO       (DWORD) (0x100A)
#define  V792N_INT_VECTOR_WO      (DWORD) (0x100C)
#define  V792N_CSR1_RO            (DWORD) (0x100E)
#define  V792N_CR1_RW             (DWORD) (0x1010)
#define  V792N_ADER_H_RW          (DWORD) (0x1012)
#define  V792N_ADER_L_RW          (DWORD) (0x1014)
#define  V792N_SINGLE_RST_WO      (DWORD) (0x1016)
#define  V792N_MCST_CBLT_CTRL_RW  (DWORD) (0x101A)
#define  V792N_EVTRIG_REG_RW      (DWORD) (0x1020)
#define  V792N_CSR2_RO            (DWORD) (0x1022)
#define  V792N_EVT_CNT_L_RO       (DWORD) (0x1024)
#define  V792N_EVT_CNT_H_RO       (DWORD) (0x1026)
#define  V792N_INCR_EVT_WO        (DWORD) (0x1028)
#define  V792N_INCR_OFFSET_WO     (DWORD) (0x102A)
#define  V792N_LD_TEST_RW         (DWORD) (0x102C)
#define  V792N_DELAY_CLEAR_RW     (DWORD) (0x102E)
#define  V792N_FCLR_WIN_RW        (DWORD) (0x102E)
#define  V792N_BIT_SET2_RW        (DWORD) (0x1032)
#define  V792N_BIT_CLEAR2_WO      (DWORD) (0x1034)
#define  V792N_W_MEM_TEST_WO      (DWORD) (0x1036)
#define  V792N_MEM_TEST_WORD_H_WO (DWORD) (0x1038)
#define  V792N_MEM_TEST_WORD_L_WO (DWORD) (0x103A)
#define  V792N_CRATE_SEL_RW       (DWORD) (0x103C)
#define  V792N_TEST_EVENT_WO      (DWORD) (0x103E)
#define  V792N_EVT_CNT_RST_WO     (DWORD) (0x1040)
#define  V792N_IPED_RW            (DWORD) (0x1060)
#define  V792N_R_MEM_TEST_WO      (DWORD) (0x1064)
#define  V792N_SWCOMM_WO          (DWORD) (0x1068)
#define  V792N_SLIDECONST_RW      (DWORD) (0x106A)
#define  V792N_AAD_RO             (DWORD) (0x1070)
#define  V792N_BAD_RO             (DWORD) (0x1072)
#define  V792N_THRES_BASE         (DWORD) (0x1080)

WORD v792n_Read16(MVME_INTERFACE *mvme, DWORD base, int offset);
void v792n_Write16(MVME_INTERFACE *mvme, DWORD base, int offset, WORD value);
DWORD v792n_Read32(MVME_INTERFACE *mvme, DWORD base, int offset);
void v792n_Write32(MVME_INTERFACE *mvme, DWORD base, int offset, DWORD value);

int  v792n_DataReady(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isEvtReady(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isBusy(MVME_INTERFACE *mvme, DWORD base);
int  v792n_EventRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry);
int  v792n_DataRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int nentry);
void v792n_DataClear(MVME_INTERFACE *mvme, DWORD base);
void v792n_EvtCntRead(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt);
void v792n_EvtCntReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_IntSet(MVME_INTERFACE *mvme, DWORD base, int level, int vector);
void v792n_IntEnable(MVME_INTERFACE *mvme, DWORD base, int level);
void v792n_IntDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_EvtTriggerSet(MVME_INTERFACE *mvme, DWORD base, int count);
void v792n_SingleShotReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_SoftReset(MVME_INTERFACE *mvme, DWORD base);
void v792n_Trigger(MVME_INTERFACE *mvme, DWORD base);
int  v792n_ThresholdRead(MVME_INTERFACE *mvme, DWORD base, WORD *threshold);
int  v792n_ThresholdWrite(MVME_INTERFACE *mvme, DWORD base, WORD *threshold);
int  v792n_CSR1Read(MVME_INTERFACE *mvme, DWORD base);
int  v792n_CSR2Read(MVME_INTERFACE *mvme, DWORD base);
int  v792n_BitSet2Read(MVME_INTERFACE *mvme, DWORD base);
void v792n_BitSet2Set(MVME_INTERFACE *mvme, DWORD base, WORD pat);
void v792n_BitSet2Clear(MVME_INTERFACE *mvme, DWORD base, WORD pat);
WORD v792n_ControlRegister1Read(MVME_INTERFACE *mvme, DWORD base);
void v792n_ControlRegister1Write(MVME_INTERFACE *mvme, DWORD base, WORD pat);
void v792n_OnlineSet(MVME_INTERFACE *mvme, DWORD base);
void v792n_OfflineSet(MVME_INTERFACE *mvme, DWORD base);
void v792n_BlkEndEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_OverRangeEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_OverRangeDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_LowThEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_LowThDisable(MVME_INTERFACE *mvme, DWORD base);
void v792n_EmptyEnable(MVME_INTERFACE *mvme, DWORD base);
void v792n_CrateSet(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt);
void v792n_DelayClearSet(MVME_INTERFACE *mvme, DWORD base, int delay);
int  v792n_Setup(MVME_INTERFACE *mvme, DWORD base, int mode);
void v792n_Status(MVME_INTERFACE *mvme, DWORD base);
int  v792n_isPresent(MVME_INTERFACE *mvme, DWORD base);

  enum v792n_DataType {
    v792n_typeMeasurement=0,
    v792n_typeHeader     =2,
    v792n_typeFooter     =4,
    v792n_typeFiller     =6
  };

  typedef union {
    DWORD raw;
    struct v792n_Entry {
      unsigned adc:12; // bit0 here
      unsigned ov:1;
      unsigned un:1;
      unsigned _pad_1:3;
      unsigned channel:4;
      unsigned _pad_2:3;
      unsigned type:3;
      unsigned geo:5;
    } data ;
    struct v792n_Header {
      unsigned _pad_1:8; // bit0 here
      unsigned cnt:6;
      unsigned _pad_2:2;
      unsigned crate:8;
      unsigned type:3;
      unsigned geo:5;
    } header;
    struct v792n_Footer {
      unsigned evtCnt:24; // bit0 here
      unsigned type:3;
      unsigned geo:5;
    } footer;
  } v792n_Data;

  typedef union {
    DWORD raw;
    struct {
      unsigned DataReady:1; // bit0 here
      unsigned GlobalDataReady:1;
      unsigned Busy:1;
      unsigned GlobalBusy:1;
      unsigned Amnesia:1;
      unsigned Purge:1;
      unsigned TermOn:1;
      unsigned TermOff:1;
      unsigned EventReady:1; //bit 8 here
    };
  } v792n_StatusRegister1;
  typedef union {
    DWORD raw;
    struct {
      unsigned _pad_1:1; // bit0 here
      unsigned BufferEmpty:1;
      unsigned BufferFull:1;
      unsigned _pad_2:1;
      unsigned PB:4;
      //unsigned DSEL0:1;
      //unsigned DSEL1:1;
      //unsigned CSEL0:1;
      //unsigned CSEL1:1;
    };
  } v792n_StatusRegister2;
  typedef union {
    DWORD raw;
    struct {
      unsigned _pad_1:2;
      unsigned BlkEnd:1;
      unsigned _pad_2:1;
      unsigned ProgReset:1;
      unsigned BErr:1;
      unsigned Align64:1;
    };
  } v792n_ControlRegister1;
  typedef union {
    DWORD raw;
    struct {
      unsigned MemTest:1;
      unsigned OffLine:1;
      unsigned ClearData:1;
      unsigned OverRange:1;
      unsigned LowThresh:1;
      unsigned _pad_1:1;//bit5
      unsigned TestAcq:1;
      unsigned SLDEnable:1;
      unsigned StepTH:1;
      unsigned _pad_2:2;//bits 9-10
      unsigned AutoIncr:1;
      unsigned EmptyProg:1;
      unsigned SlideSubEnable:1;
      unsigned AllTrg:1;
    };
  } v792n_BitSet2Register;

  void v792n_printEntry(const v792n_Data* v);

#ifdef __cplusplus
}
#endif

#endif // V792N_INCLUDE_H

/* emacs
 * Local Variables:
 * mode:C
 * mode:font-lock
 * tab-width: 8
 * c-basic-offset: 2
 * End:
 */
Attachment 5: v792n.c
/*********************************************************************

  Name:         v792n.c
  Created by:   Jimmy Ngai

  Contents:     V792N 16ch. QDC

  Based on v792.c by Pierre-Andre Amaudruz
                
  $Id: $
*********************************************************************/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#if defined(OS_LINUX)
#include <unistd.h>
#endif
#include "v792n.h"

WORD v792n_Read16(MVME_INTERFACE *mvme, DWORD base, int offset)
{
  int cmode;
  WORD data;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  data = mvme_read_value(mvme, base+offset);
  mvme_set_dmode(mvme, cmode);
  return data;
}

void v792n_Write16(MVME_INTERFACE *mvme, DWORD base, int offset, WORD value)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+offset, value);
  mvme_set_dmode(mvme, cmode);
}

DWORD v792n_Read32(MVME_INTERFACE *mvme, DWORD base, int offset)
{
  int cmode;
  DWORD data;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  data = mvme_read_value(mvme, base+offset);
  mvme_set_dmode(mvme, cmode);
  return data;
}

void v792n_Write32(MVME_INTERFACE *mvme, DWORD base, int offset, DWORD value)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  mvme_write_value(mvme, base+offset, value);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
int v792n_DataReady(MVME_INTERFACE *mvme, DWORD base)
{
  int data_ready, cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  data_ready = mvme_read_value(mvme, base+V792N_CSR1_RO) & 0x1;
  mvme_set_dmode(mvme, cmode);
  return data_ready;
}

/*****************************************************************/
int v792n_isEvtReady(MVME_INTERFACE *mvme, DWORD base)
{
  int csr;
  csr = v792n_CSR1Read(mvme, base);
  return (csr & 0x100);
}

/*****************************************************************/
int v792n_isBusy(MVME_INTERFACE *mvme, DWORD base)
{
  int status, busy, timeout, cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  timeout = 1000;
  do {
    status = mvme_read_value(mvme, base+V792N_CSR1_RO);
    busy = status & 0x4;
    timeout--;
  } while (busy || timeout);
  mvme_set_dmode(mvme, cmode);
  return (busy != 0 ? 1 : 0);
}

/*****************************************************************/
/*
Read single event, return event length (number of entries)
*/
int v792n_EventRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int *nentry)
{
#define USE_BLT_READ_2

#ifdef USE_SINGLE_READ
  DWORD hdata;
  int   cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);

  *nentry = 0;
  if (v792n_DataReady(mvme, base)) {
    do {
      hdata = mvme_read_value(mvme, base);
    } while (!(hdata & 0x02000000)); // skip up to the header

    pdest[*nentry] = hdata;
    *nentry += 1;
    do {
      pdest[*nentry] = mvme_read_value(mvme, base);
      *nentry += 1;
    } while (!(pdest[*nentry-1] & 0x04000000)); // copy until the trailer

    nentry--;
  }

  mvme_set_dmode(mvme, cmode);
#endif // USE_SINGLE_READ

#ifdef USE_BLT_READ_1
  DWORD hdata, data[V792N_MAX_CHANNELS+2];
  int   cam, cmode, cblt, cnt, i;

  mvme_get_am(mvme, &cam);
  mvme_get_dmode(mvme, &cmode);
  mvme_get_blt(mvme, &cblt);
  mvme_set_dmode(mvme, MVME_DMODE_D32);

  *nentry = 0;
  if (v792n_DataReady(mvme, base)) {
    do {
      hdata = mvme_read_value(mvme, base);
    } while (!(hdata & 0x02000000)); // skip up to the header

    mvme_set_am(mvme, MVME_AM_A32_SB);
    mvme_set_blt(mvme, MVME_BLT_BLT32);
    cnt = (hdata >> 8) & 0x3F;

    mvme_read(mvme, data, base, (cnt+1)*4);
    pdest[0] = hdata;
    for (i=1;i<=cnt+1;i++)
      pdest[i] = data[i-1];

    *nentry = cnt + 2;
  }

  mvme_set_am(mvme, cam);
  mvme_set_dmode(mvme, cmode);
  mvme_set_blt(mvme, cblt);
#endif // USE_BLT_READ_1

#ifdef USE_BLT_READ_2
  int   cam, cmode, cblt, cnt;

  mvme_get_am(mvme, &cam);
  mvme_get_dmode(mvme, &cmode);
  mvme_get_blt(mvme, &cblt);
  mvme_set_dmode(mvme, MVME_DMODE_D32);

  *nentry = 0;
//  if (v792n_DataReady(mvme, base)) {
    mvme_set_am(mvme, MVME_AM_A32_SB);
    mvme_set_blt(mvme, MVME_BLT_BLT32);
    mvme_read(mvme, pdest, base, (V792N_MAX_CHANNELS+2)*4);
    cnt = (pdest[0] >> 8) & 0x3F;
    *nentry = cnt + 2;
//  }

  mvme_set_am(mvme, cam);
  mvme_set_dmode(mvme, cmode);
  mvme_set_blt(mvme, cblt);
#endif //USE_BLT_READ_2

  return *nentry;
}

/*****************************************************************/
/*
Read nentry of data from the data buffer
*/
int v792n_DataRead(MVME_INTERFACE *mvme, DWORD base, DWORD *pdest, int nentry)
{
  int  cmode, status;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
//  nentry = 128;
  if (v792n_DataReady(mvme, base)) {
    status = mvme_read(mvme, pdest, base, nentry*4);
  }
  mvme_set_dmode(mvme, cmode);
  return status;
}

/*****************************************************************/
void v792n_DataClear(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_BIT_SET2_RW, 0x4);
  mvme_write_value(mvme, base+V792N_BIT_CLEAR2_WO, 0x4);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtCntRead(MVME_INTERFACE *mvme, DWORD base, DWORD *evtcnt)
{
  int cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  *evtcnt  = mvme_read_value(mvme, base+V792N_EVT_CNT_L_RO);
  *evtcnt += (mvme_read_value(mvme, base+V792N_EVT_CNT_H_RO) << 16);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtCntReset(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVT_CNT_RST_WO, 1);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntSet(MVME_INTERFACE *mvme, DWORD base, int level, int vector)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_INT_VECTOR_WO, (vector & 0xFF));
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, (level & 0x7));
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntEnable(MVME_INTERFACE *mvme, DWORD base, int level)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, (level & 0x1F));
  /* Use the trigger buffer for int enable/disable
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, (level & 0x7));
  */
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_IntDisable(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, 0);
  /* Use the trigger buffer for int enable/disable
     Setting a level 0 reboot the VMIC !
  mvme_write_value(mvme, base+V792N_INT_LEVEL_WO, 0);
  */
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_EvtTriggerSet(MVME_INTERFACE *mvme, DWORD base, int count)
{
  int cmode;

  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_EVTRIG_REG_RW, (count & 0x1F));
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
void v792n_SingleShotReset(MVME_INTERFACE *mvme, DWORD base)
{
  int cmode;
  mvme_get_dmode(mvme, &cmode);
  mvme_set_dmode(mvme, MVME_DMODE_D16);
  mvme_write_value(mvme, base+V792N_SINGLE_RST_WO, 1);
  mvme_set_dmode(mvme, cmode);
}

/*****************************************************************/
... 409 more lines ...
  762   24 May 2011 Jianglai LiuForumsimple example frontend for V1720
Thanks all for the kind help. This did point me to the right direction. I was now able to make v1720.c as well as my MIDAS frontend (thanks to
Jimmy's example) talking to V1720, and read out the waveform bank.

However the readout values did not seem quite right. I fed in a PMT-like pulse of about 0.1 V and 50 ns wide, with an external trigger just in time.
However, the readout by both v1720.c stand-alone code, and my midas frontend seemed to be flat noise.

I tried to play with the post trigger value, as well as the DAC setting of V1720. None seemed to help.

BTW I tested my V1720 board functionality by using the CAEN windows software (CAENScope and WaveDump). They worked just fine.

Any suggestions? Attached is my modified v1720.c code.


Pierre-Andre Amaudruz wrote:

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


Under the drivers/vme you can find code for the v1720.c (VME access) and ov1720.c
(A2818/A3818 PCIe optical link access). For testing the hardware, we use this code compiled and linked
with MAIN_ENABLE to confirm its functionality. You may want to do the same for your USB. Once this
is under control, the Midas frontend implementation using the same driver shouldn't give you trouble.
Attachment 1: v1720.c
/*********************************************************************

  Name:         v1720.c
  Created by:   Pierre-A. Amaudruz / K.Olchanski

  Contents:     V1720 8 ch. 12bit 250Msps
 
  $Id: v1720.c 4728 2010-05-12 05:34:44Z svn $
*********************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
//#include "midas.h"
#include "v1720drv.h"
#include "mvmestd.h"


// Buffer organization map for number of samples
uint32_t V1720_NSAMPLES_MODE[11] = { (1<<20), (1<<19), (1<<18), (1<<17), (1<<16), (1<<15)
			       ,(1<<14), (1<<13), (1<<12), (1<<11), (1<<10)};

/*****************************************************************/
/*
Read V1720 register value
*/
static uint32_t regRead(MVME_INTERFACE *mvme, uint32_t base, int offset)
{
  mvme_set_am(mvme, MVME_AM_A32);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  return mvme_read_value(mvme, base + offset);
}

/*****************************************************************/
/*
Write V1720 register value
*/
static void regWrite(MVME_INTERFACE *mvme, uint32_t base, int offset, uint32_t value)
{
  mvme_set_am(mvme, MVME_AM_A32);
  mvme_set_dmode(mvme, MVME_DMODE_D32);
  mvme_write_value(mvme, base + offset, value);
}

/*****************************************************************/
uint32_t v1720_RegisterRead(MVME_INTERFACE *mvme, uint32_t base, int offset)
{
  return regRead(mvme, base, offset);
}

/*****************************************************************/
void v1720_RegisterWrite(MVME_INTERFACE *mvme, uint32_t base, int offset, uint32_t value)
{
  regWrite(mvme, base, offset, value);
}

/*****************************************************************/
void v1720_Reset(MVME_INTERFACE *mvme, uint32_t base)
{
  regWrite(mvme, base, V1720_SW_RESET, 0);
}

/*****************************************************************/
void v1720_TrgCtl(MVME_INTERFACE *mvme, uint32_t base, uint32_t reg, uint32_t mask)
{
  regWrite(mvme, base, reg, mask);
}

/*****************************************************************/
void v1720_ChannelCtl(MVME_INTERFACE *mvme, uint32_t base, uint32_t reg, uint32_t mask)
{
  regWrite(mvme, base, reg, mask);
}

/*****************************************************************/
void v1720_ChannelSet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t what, uint32_t that)
{
  uint32_t reg, mask;

  if (what == V1720_CHANNEL_THRESHOLD)   mask = 0x0FFF;
  if (what == V1720_CHANNEL_OUTHRESHOLD) mask = 0x0FFF;
  if (what == V1720_CHANNEL_DAC)         mask = 0xFFFF;
  reg = what | (channel << 8);
  printf("base:0x%x reg:0x%x, this:%x\n", base, reg, that);
  regWrite(mvme, base, reg, (that & 0xFFF));
}

/*****************************************************************/
uint32_t v1720_ChannelGet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t what)
{
  uint32_t reg, mask;

  if (what == V1720_CHANNEL_THRESHOLD)   mask = 0x0FFF;
  if (what == V1720_CHANNEL_OUTHRESHOLD) mask = 0x0FFF;
  if (what == V1720_CHANNEL_DAC)         mask = 0xFFFF;
  reg = what | (channel << 8);
  return regRead(mvme, base, reg);
}

/*****************************************************************/
void v1720_ChannelThresholdSet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t threshold)
{
  uint32_t reg;
  reg = V1720_CHANNEL_THRESHOLD | (channel << 8);
  printf("base:0x%x reg:0x%x, threshold:%x\n", base, reg, threshold);
  regWrite(mvme, base, reg, (threshold & 0xFFF));
}

/*****************************************************************/
void v1720_ChannelOUThresholdSet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t threshold)
{
  uint32_t reg;
  reg = V1720_CHANNEL_OUTHRESHOLD | (channel << 8);
  printf("base:0x%x reg:0x%x, outhreshold:%x\n", base, reg, threshold);
  regWrite(mvme, base, reg, (threshold & 0xFFF));
}

/*****************************************************************/
void v1720_ChannelDACSet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t dac)
{
  uint32_t reg;

  reg = V1720_CHANNEL_DAC | (channel << 8);
  printf("base:0x%x reg:0x%x, DAC:%x\n", base, reg, dac);
  regWrite(mvme, base, reg, (dac & 0xFFFF));
}

/*****************************************************************/
int v1720_ChannelDACGet(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel, uint32_t *dac)
{
  uint32_t reg;
  int   status;

  reg = V1720_CHANNEL_DAC | (channel << 8);
  *dac = regRead(mvme, base, reg);
  reg = V1720_CHANNEL_STATUS | (channel << 8);
  status = regRead(mvme, base, reg);
  return status;
}

/*****************************************************************/
void v1720_Align64Set(MVME_INTERFACE *mvme, uint32_t base)
{
  regWrite(mvme, base, V1720_VME_CONTROL, V1720_ALIGN64);
}

/*****************************************************************/
void v1720_AcqCtl(MVME_INTERFACE *mvme, uint32_t base, uint32_t operation)
{
  uint32_t reg;
  
  reg = regRead(mvme, base, V1720_ACQUISITION_CONTROL);  
  switch (operation) {
  case V1720_RUN_START:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg | 0x4));
    break;
  case V1720_RUN_STOP:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg & ~(0x4)));
    break;
  case V1720_REGISTER_RUN_MODE:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg & ~(0x3)));
    break;
  case V1720_SIN_RUN_MODE:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg | 0x01));
    break;
  case V1720_SIN_GATE_RUN_MODE:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg | 0x02));
    break;
  case V1720_MULTI_BOARD_SYNC_MODE:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg | 0x03));
    break;
  case V1720_COUNT_ACCEPTED_TRIGGER:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg | 0x08));
    break;
  case V1720_COUNT_ALL_TRIGGER:
    regWrite(mvme, base, V1720_ACQUISITION_CONTROL, (reg & ~(0x08)));
    break;
  default:
    break;
  }
}

/*****************************************************************/
void v1720_info(MVME_INTERFACE *mvme, uint32_t base, int *nchannels, uint32_t *n32word)
{
  int i, chanmask;

  // Evaluate the event size
  // Number of samples per channels
  *n32word = V1720_NSAMPLES_MODE[regRead(mvme, base, V1720_BUFFER_ORGANIZATION)];

  // times the number of active channels
  chanmask = 0xff & regRead(mvme, base, V1720_CHANNEL_EN_MASK); 
  *nchannels = 0;
  for (i=0;i<8;i++) {
    if (chanmask & (1<<i))
      *nchannels += 1;
  }

  *n32word *= *nchannels;
  *n32word /= 2;   // 2 samples per 32bit word
  *n32word += 4;   // Headers
}

/*****************************************************************/
uint32_t v1720_BufferOccupancy(MVME_INTERFACE *mvme, uint32_t base, uint32_t channel)
{
  uint32_t reg;
  reg = V1720_BUFFER_OCCUPANCY + (channel<<16);
  return regRead(mvme, base, reg);
}


/*****************************************************************/
uint32_t v1720_BufferFree(MVME_INTERFACE *mvme, uint32_t base, int nbuffer)
{
  int mode;

  mode = regRead(mvme, base, V1720_BUFFER_ORGANIZATION);
  if (nbuffer <= (1<< mode) ) {
    regWrite(mvme, base, V1720_BUFFER_FREE, nbuffer);
    return mode;
  } else
    return mode;
}

/*****************************************************************/
uint32_t v1720_BufferFreeRead(MVME_INTERFACE *mvme, uint32_t base)
{
  return regRead(mvme, base, V1720_BUFFER_FREE);
}

/*****************************************************************/
uint32_t v1720_DataRead(MVME_INTERFACE *mvme, uint32_t base, uint32_t *pdata, uint32_t n32w)
{
  uint32_t i;

  for (i=0;i<n32w;i++) {
    *pdata = regRead(mvme, base, V1720_EVENT_READOUT_BUFFER);
    if (*pdata != 0xffffffff)
      pdata++;
    else
      break;
  }
  return i;
}

/********************************************************************/
/** v1720_DataBlockRead
Read N entries (32bit) 
@param mvme vme structure
@param base  base address
@param pdest Destination pointer
@return nentry
*/
uint32_t v1720_DataBlockRead(MVME_INTERFACE *mvme, uint32_t base, uint32_t *pdest, uint32_t *nentry)
{
  int status;

  mvme_set_am(  mvme, MVME_AM_A32);
  mvme_set_dmode(  mvme, MVME_DMODE_D32);
  //mvme_set_blt(  mvme, MVME_BLT_MBLT64);
  //mvme_set_blt(  mvme, MVME_BLT_NONE);
  mvme_set_blt(mvme, MVME_BLT_BLT32);
  //mvme_set_blt(  mvme, 0);

  // Transfer in MBLT64 (8bytes), nentry is in 32bits(VF48)
  // *nentry * 8 / 2
  status = mvme_read(mvme, pdest, base+V1720_EVENT_READOUT_BUFFER, 4);
  //printf("status = %d\n",status);
  if (status != MVME_SUCCESS)
    return 0;

  return (*nentry);
}


/*****************************************************************/
void  v1720_Status(MVME_INTERFACE *mvme, uint32_t base)
{
  printf("================================================\n");
  printf("V1720 at A32 0x%x\n", (int)base);
  printf("Board ID             : 0x%x\n", regRead(mvme, base, V1720_BOARD_ID));
  printf("Board Info           : 0x%x\n", regRead(mvme, base, V1720_BOARD_INFO));
  printf("Acquisition status   : 0x%8.8x\n", regRead(mvme, base, V1720_ACQUISITION_STATUS));
  printf("================================================\n");
}

/*****************************************************************/
/**
Sets all the necessary paramters for a given configuration.
The configuration is provided by the mode argument.
Add your own configuration in the case statement. Let me know
your setting if you want to include it in the distribution.
- <b>Mode 1</b> : 

@param *mvme VME structure
@param  base Module base address
@param mode  Configuration mode number
@return 0: OK. -1: Bad
*/
... 169 more lines ...
  825   10 Aug 2012 Carl BlaksleyForumsimple example frontend for V1720

Jimmy Ngai wrote:

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


Hi Jianglai,

I don't have an exmaple of using V1718 with V1720, but I have been using V1718 with V792N for a long time.

You may find in the attachment an example frontend program and my drivers for V1718 and V792N written in MVMESTD format. They have to be linked with the CAENVMELib library and other essential MIDAS stuffs.

Regards,
Jimmy


Jimmy,

How exactly did you link the CAENVMElib with your frontend? That is the part which I can not seem to replicate using your example frontend!

Thanks,
-Carl
  826   12 Aug 2012 Jimmy NgaiForumsimple example frontend for V1720

Carl Blaksley wrote:

Jimmy Ngai wrote:

Jianglai Liu wrote:
Hi,

Who has a good example of a frontend program using CAEN V1718 VME-USB bridge and
V1720 FADC? I am trying to set up the DAQ for such a simple system.

I put together a frontend which talks to the VME. However it gets stuck at
"Calibrating" in initialize_equipment().

I'd appreciate some help!

Thanks,
Jianglai


Hi Jianglai,

I don't have an exmaple of using V1718 with V1720, but I have been using V1718 with V792N for a long time.

You may find in the attachment an example frontend program and my drivers for V1718 and V792N written in MVMESTD format. They have to be linked with the CAENVMELib library and other essential MIDAS stuffs.

Regards,
Jimmy


Jimmy,

How exactly did you link the CAENVMElib with your frontend? That is the part which I can not seem to replicate using your example frontend!

Thanks,
-Carl


Hi Carl,

Attached is a cut-down version of my original Makefile just for demonstrating how to link the CAENVMElib. I didn't test it for bugs. Please make sure the libCAENVME.so is in your library path.

Jimmy
Attachment 1: Makefile
#####################################################################
#
#  Name:         Makefile
#  Created by:   Stefan Ritt
#  Modified by:  Jimmy Ngai
#
#  Date:         July 20, 2012
#
#  Contents:     Makefile for MIDAS example frontend and analyzer
#
#  $Id: Makefile 3203 2006-07-31 21:39:02Z ritt $
#
#####################################################################
#
#--------------------------------------------------------------------
# The MIDASSYS should be defined prior the use of this Makefile
ifndef MIDASSYS
missmidas::
	@echo "...";
	@echo "Missing definition of environment variable 'MIDASSYS' !";
	@echo "...";
endif

# get OS type from shell
OSTYPE = $(shell uname)

#--------------------------------------------------------------------
# The following lines contain specific switches for different UNIX
# systems. Find the one which matches your OS and outcomment the 
# lines below.

#-----------------------------------------
# This is for Linux
ifeq ($(OSTYPE),Linux)
OSTYPE = linux
endif

ifeq ($(OSTYPE),linux)

OS_DIR = linux
OSFLAGS = -DOS_LINUX -DLINUX -DUNIX -Dextname
CFLAGS = -g -O2 -Wall -Wno-write-strings
# add to compile in 32-bit mode
# OSFLAGS += -m32
LIBS = -lm -lz -lutil -lnsl -lpthread
endif

#-----------------------
# MacOSX/Darwin is just a funny Linux
#
ifeq ($(OSTYPE),Darwin)
OSTYPE = darwin
endif

ifeq ($(OSTYPE),darwin)
OS_DIR = darwin
FF = cc
OSFLAGS = -DOS_LINUX -DLINUX -DOS_DARWIN -DUNIX -DHAVE_STRLCPY -DAbsoftUNIXFortran -fPIC -Wno-unused-function
LIBS = -lpthread
SPECIFIC_OS_PRG = $(BIN_DIR)/mlxspeaker
NEED_STRLCPY=
NEED_RANLIB=1
NEED_SHLIB=
NEED_RPATH=

endif

#-----------------------------------------
# ROOT flags and libs
#
ifdef ROOTSYS
ROOTCFLAGS := $(shell  $(ROOTSYS)/bin/root-config --cflags)
ROOTCFLAGS += -DHAVE_ROOT -DUSE_ROOT
ROOTLIBS   := $(shell  $(ROOTSYS)/bin/root-config --libs) -Wl,-rpath,$(ROOTSYS)/lib
ROOTLIBS   += -lThread
else
missroot:
	@echo "...";
	@echo "Missing definition of environment variable 'ROOTSYS' !";
	@echo "...";
endif

#-------------------------------------------------------------------
# The following lines define directories. Adjust if necessary
#                 
INC_DIR    = $(MIDASSYS)/include
LIB_DIR    = $(MIDASSYS)/$(OS_DIR)/lib
SRC_DIR    = $(MIDASSYS)/src
DRV_DIR    = ./drivers
MOD_DIR    = ./modules

#-------------------------------------------------------------------
# List of analyzer modules
#
MODULES    = adccalib.o adcsum.o scaler.o

#-------------------------------------------------------------------
# Drivers needed by the frontend program
#
TRFE_DRIVERS  = v1718.o v792n.o
TRFE_LIBS     = -lCAENVME

#-------------------------------------------------------------------
# Frontend code name defaulted to frontend in this example.
# comment out the line and run your own frontend as follow:
# gmake UFE=my_frontend
#
TRFE  = trfrontend

####################################################################
# Lines below here should not be edited
####################################################################

# MIDAS library
LIB = $(LIB_DIR)/libmidas.a

# compiler
CC = gcc
CXX = g++
CFLAGS += -g -I. -I$(INC_DIR) -I$(DRV_DIR)
CFLAGS += -I$(DRV_DIR)/vme
CFLAGS += -I$(DRV_DIR)/vme/CAENVMElib/include
LDFLAGS +=

all: $(TRFE) analyzer

noenv: all

$(TRFE): $(LIB) $(LIB_DIR)/mfe.o $(TRFE_DRIVERS) $(TRFE).c $(SRC_DIR)/cnaf_callback.c
	$(CC) $(CFLAGS) $(OSFLAGS) -o $(TRFE) $(TRFE).c \
	$(SRC_DIR)/cnaf_callback.c $(TRFE_DRIVERS) $(LIB_DIR)/mfe.o $(LIB) \
	$(LDFEFLAGS) $(LIBS) $(TRFE_LIBS)

%.o: $(DRV_DIR)/vme/%.c
	$(CC) $(CFLAGS) $(OSFLAGS) -o $@ -c $<

analyzer: $(LIB) $(LIB_DIR)/rmana.o analyzer.o $(MODULES)
	$(CXX) $(CFLAGS) -o $@ $(LIB_DIR)/rmana.o analyzer.o $(MODULES) \
	$(LIB) $(LDFLAGS) $(ROOTLIBS) $(LIBS) $(ANA_LIBS)

%.o: %.c experim.h
	$(CXX) $(USERFLAGS) $(ROOTCFLAGS) $(CFLAGS) $(OSFLAGS) -o $@ -c $<

%.o: $(MOD_DIR)/%.c experim.h
	$(CXX) $(USERFLAGS) $(ROOTCFLAGS) $(CFLAGS) $(OSFLAGS) -o $@ -c $<

clean::
	rm -rf *.o *~ \#*

#end file
  158   13 Oct 2004 Konstantin OlchanskiBug Reportsilly odbedit "rename Display xxx/yyy"
odbedit command "rename Display xxx/yyy" creates a key named "xxx/yyy" (yes,
with a slash in the name) and this key cannot be deleted or renamed...
K.O.
  159   13 Oct 2004 Stefan RittBug Reportsilly odbedit "rename Display xxx/yyy"
> odbedit command "rename Display xxx/yyy" creates a key named "xxx/yyy" (yes,
> with a slash in the name) and this key cannot be deleted or renamed...
> K.O.

"rename" is "rename", not "mv" under Unix. If you want this functionality, put it
in and don't complain!
  2115   02 Mar 2021 Konstantin OlchanskiInfoshortest possible sleep
since I am implementing a polled equipment, I was curious what is the smallest possible sleep time on current computers.

in current UNIX, there are 2 system calls available for sleeping: select() (with microsecond granularity) and nanosleep() (with nanosecond granularity).

So I wrote a little test program to check it out (progs/test_sleep).

First, Linux result using select(). Typical run on AMD 3700X CPU (4.1 GHz turbo boost) with Ubuntu LTS 20, linux kernel 5.8:

daq13:midas$ ./bin/test_sleep 
sleep      10 loops, 0.100000 sec per loop, 1.000000 sec total,  1003368.855 usec actual, 100336.885 usec actual per loop, oversleep 336.885 usec, 0.3%
sleep     100 loops, 0.010000 sec per loop, 1.000000 sec total,  1008512.020 usec actual, 10085.120 usec actual per loop, oversleep 85.120 usec, 0.9%
sleep    1000 loops, 0.001000 sec per loop, 1.000000 sec total,  1062137.842 usec actual, 1062.138 usec actual per loop, oversleep 62.138 usec, 6.2%
sleep   10000 loops, 0.000100 sec per loop, 1.000000 sec total,  1528650.999 usec actual, 152.865 usec actual per loop, oversleep 52.865 usec, 52.9%
sleep   99999 loops, 0.000010 sec per loop, 0.999990 sec total,  6250898.123 usec actual, 62.510 usec actual per loop, oversleep 52.510 usec, 525.1%
sleep 1000000 loops, 0.000001 sec per loop, 1.000000 sec total, 54056918.144 usec actual, 54.057 usec actual per loop, oversleep 53.057 usec, 5305.7%
sleep 1000000 loops, 0.000000 sec per loop, 0.100000 sec total,   210875.988 usec actual, 0.211 usec actual per loop, oversleep 0.111 usec, 110.9%
sleep 1000000 loops, 0.000000 sec per loop, 0.010000 sec total,   204804.897 usec actual, 0.205 usec actual per loop, oversleep 0.195 usec, 1948.0%
daq13:midas$ 

How to read this:

First line is 10 sleeps of 100 ms, for a total of 1 sec. this actually sleeps for a bit longer,
average over-sleep is 300 usec out of 100 ms is 0.3%.

Next few lines use progressively shorter sleep, 10 ms, 1 ms and 0.1 ms. over-sleep is consistently around 50-60 usec,
which I conclude to be this linux sleep granularity.

Last two lines try sleep for 0.1 usec and 0.01 usec, resulting in a zero-time sleep of select(),
so we just measure the average time cost of a linux syscall, around 200 ns in this machine.

Going to different machines:

Intel E-2236 (4.8 GHz tutboboost), Ubuntu LTS 20, linux kernel 5.8: over-sleep is 60 usec, zero-sleep is 400 ns.
Intel E-2226G (same, see arc.intel.com), CentOS-7, linux kernel 3.10: over-sleep is 60 usec, zero-sleep is 600 ns.
VME processor (2 GHz Intel T7400), Ubuntu 20, linux kernel 5.8: over-sleep is 60 usec, zero-sleep is 1700 ns.

This is pretty consistent, select() over-sleep is 60 usec on all hardware, zero-sleep tracks CPU GHz ratings.

Next, MacOS result, MacBookAir2020, MacOS 10.15.7, CPU 1.2 GHz i7-1060G7:

4ed0:midas olchansk$ ./bin/test_sleep 
sleep      10 loops, 0.100000 sec per loop, 1.000000 sec total,  1031108.856 usec actual, 103110.886 usec actual per loop, oversleep 3110.886 usec, 3.1%
sleep     100 loops, 0.010000 sec per loop, 1.000000 sec total,  1091104.984 usec actual, 10911.050 usec actual per loop, oversleep 911.050 usec, 9.1%
sleep    1000 loops, 0.001000 sec per loop, 1.000000 sec total,  1270800.829 usec actual, 1270.801 usec actual per loop, oversleep 270.801 usec, 27.1%
sleep   10000 loops, 0.000100 sec per loop, 1.000000 sec total,  1370345.116 usec actual, 137.035 usec actual per loop, oversleep 37.035 usec, 37.0%
sleep   99999 loops, 0.000010 sec per loop, 0.999990 sec total,  1706473.112 usec actual, 17.065 usec actual per loop, oversleep 7.065 usec, 70.6%
sleep 1000000 loops, 0.000001 sec per loop, 1.000000 sec total,  5150341.034 usec actual, 5.150 usec actual per loop, oversleep 4.150 usec, 415.0%
sleep 1000000 loops, 0.000000 sec per loop, 0.100000 sec total,   595654.011 usec actual, 0.596 usec actual per loop, oversleep 0.496 usec, 495.7%
sleep 1000000 loops, 0.000000 sec per loop, 0.010000 sec total,   591560.125 usec actual, 0.592 usec actual per loop, oversleep 0.582 usec, 5815.6%
4ed0:midas olchansk$ 

things are quite different here, OS is Mach microkernel with an oldish FreeBSD UNIX single-server (from NextSTEP),
so the sleep granularity is different, better than linux. zero-sleep still measures the syscall time, 600 ns on this machine.

Next we measure the same using the nansleep() syscall.

daq13:midas$ ./bin/test_sleep 
sleep      10 loops, 0.100000 sec per loop, 1.000000 sec total,  1004133.940 usec actual, 100413.394 usec actual per loop, oversleep 413.394 usec, 0.4%
sleep     100 loops, 0.010000 sec per loop, 1.000000 sec total,  1046117.067 usec actual, 10461.171 usec actual per loop, oversleep 461.171 usec, 4.6%
sleep    1000 loops, 0.001000 sec per loop, 1.000000 sec total,  1096894.979 usec actual, 1096.895 usec actual per loop, oversleep 96.895 usec, 9.7%
sleep   10000 loops, 0.000100 sec per loop, 1.000000 sec total,  1526744.843 usec actual, 152.674 usec actual per loop, oversleep 52.674 usec, 52.7%
sleep   99999 loops, 0.000010 sec per loop, 0.999990 sec total,  6250154.018 usec actual, 62.502 usec actual per loop, oversleep 52.502 usec, 525.0%
sleep 1000000 loops, 0.000001 sec per loop, 1.000000 sec total, 53344123.125 usec actual, 53.344 usec actual per loop, oversleep 52.344 usec, 5234.4%
sleep 1000000 loops, 0.000000 sec per loop, 0.100000 sec total, 52641665.936 usec actual, 52.642 usec actual per loop, oversleep 52.542 usec, 52541.7%
sleep 1000000 loops, 0.000000 sec per loop, 0.010000 sec total, 52637501.001 usec actual, 52.638 usec actual per loop, oversleep 52.628 usec, 526275.0%
daq13:midas$ 

Here everything is simple. sleep longer than 1000 usec works the same as select(), sleep for shorter than 100 usec sleeps for 52 usec, regardless of what 
we ask for.

MacOS does no better, long sleeps are same as select(), sleeps is 1 usec or less sleep for too long. no improvement over select().

4ed0:midas olchansk$ ./bin/test_sleep 
sleep      10 loops, 0.100000 sec per loop, 1.000000 sec total,  1023327.827 usec actual, 102332.783 usec actual per loop, oversleep 2332.783 usec, 2.3%
sleep     100 loops, 0.010000 sec per loop, 1.000000 sec total,  1130330.086 usec actual, 11303.301 usec actual per loop, oversleep 1303.301 usec, 13.0%
sleep    1000 loops, 0.001000 sec per loop, 1.000000 sec total,  1333846.807 usec actual, 1333.847 usec actual per loop, oversleep 333.847 usec, 33.4%
sleep   10000 loops, 0.000100 sec per loop, 1.000000 sec total,  1402330.160 usec actual, 140.233 usec actual per loop, oversleep 40.233 usec, 40.2%
sleep   99999 loops, 0.000010 sec per loop, 0.999990 sec total,  2034706.831 usec actual, 20.347 usec actual per loop, oversleep 10.347 usec, 103.5%
sleep 1000000 loops, 0.000001 sec per loop, 1.000000 sec total,  6646192.074 usec actual, 6.646 usec actual per loop, oversleep 5.646 usec, 564.6%
sleep 1000000 loops, 0.000000 sec per loop, 0.100000 sec total,  7556284.189 usec actual, 7.556 usec actual per loop, oversleep 7.456 usec, 7456.3%
sleep 1000000 loops, 0.000000 sec per loop, 0.010000 sec total, 15720005.035 usec actual, 15.720 usec actual per loop, oversleep 15.710 usec, 157100.1%
4ed0:midas olchansk$ 

On Linux, strace tells us that the actual syscall behind nanosleep() is this:
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=10000}, 0x7fffc159e200) = 0

Let's try it directly... result is the same.
Let's try it with CLOCK_MONOTONIC... result is the same.

The man page of clock_nanosleep() specifies that this syscall always suspends the calling thread,
so what we see here is the Linux scheduler tick size.

Bottom line.

On current linux, shortest sleep is around 100 usec both select() and nanosleep().
On MacOS, shortest sleep is down to 5 usec using select(), but I cannot tell if CPU sleeps or busy-loops.

select() is still the best syscall for sleeping.

K.O.
ELOG V3.1.4-2e1708b5