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

  Name:         drscl.cpp
  Created by:   Stefan Ritt

  Contents:     Command line interface to DRS chip via USB and VME

  $Id: drscl.cpp 21435 2014-07-30 13:02:31Z ritt $

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

#include <math.h>

#ifdef _MSC_VER

#include <windows.h>
#include <conio.h>
#include <io.h>
#include <direct.h>

#define DIR_SEPARATOR '\\'

#elif defined(OS_LINUX) || defined(OS_DARWIN)

#define O_BINARY 0

#include <unistd.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <errno.h>

#define DIR_SEPARATOR '/'

#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <assert.h>

#include "strlcpy.h"
#include "DRS.h"
#ifdef HAVE_VME
#include "ace.h"
#endif

const char *drscl_svn_revision = "$Id: drscl.cpp 21435 2014-07-30 13:02:31Z ritt $";

void lusb(void);
void print_help();
void clear_screen();
int match(const char *str, const char *cmd);
void cmd_loop();

#if defined(OS_LINUX) || defined(OS_DARWIN)
#define getch() getchar()
#define Sleep(x) usleep(x*1000)
#endif

#ifdef _MSC_VER
#include <conio.h>
#define drs_kbhit() kbhit()
#endif

void print_help()
{
   puts("Available commands:\n");
   puts("active <0|1>                Set domino active mode on (1) or off (0)");
   puts("board <i>|<i1> <i2>|all     Address individual board/range/all boards");
   puts("calib [dir]                 Response Calibration. Use dir=\"area\" for MEG");
   puts("chn [n]                     Set number of channels: 8, 4, 2, 1");
   puts("ct [histo]                  Chip Test [show histo]");
   puts("del <0|1>                   Switch delayed start on/off");
   puts("dir                         Show CF directory");
   puts("dmode <0|1>                 Set Domino mode 0=single, 1=cont.");
   puts("et                          EEPROM test");
   puts("exit                        Exit program");
   puts("freq <ghz> [0|1]            Set frequency of board [without/with] regulation");
   puts("info                        Show information about board");
   puts("init                        Initialize board");
   puts("led <0|1>                   Turn LED on (1) or off (0)");
   puts("lock [0|1]                  Display lock status [without/with] restart");
   puts("multi [0|1]                 Turn multi-buffer mode on/off");
   puts("offset <voltage>            Set offset voltage");
   puts("phase <value> [0|1]         Set ADC clock phase and inversion");
   puts("quit                        Exit program");
   puts("ram                         Test speed to FPGA RAM");
   puts("range <center>              Change input range to <center>+=0.5V");
   puts("read <chn> [0|1] [file]     Read waveform to [file], chn=0..19 [with] calibration");
   puts("refclk [0|1]                Use FPGA ref. clk (0) or ext. P2 ref. clk (1)");
   puts("reg                         Register test");
   puts("serial <number>             Set serial number of board");
   puts("scan                        Scan for boards");
   puts("standby <0|1>               Turn standby mode on (1) or off (0)");
   puts("start                       Start domino wave");
   puts("stop                        Issue soft trigger");
   puts("tcout [file] [idx_offset]   Print time calibration of DRS4, or write it onto [file]");
   puts("tcs <0|1>                   Timing calibration signal on (1) or off (0)");
   puts("tcalib [freq]               Timing Calibration");
   puts("tlevel <voltage>            Set trigger level in Volts");
   puts("trans <0|1>                 Set transparent mode on (1) or off (0)");
   puts("trig <0|1>                  Hardware trigger on (1) or off (0)");
   puts("upload <file>               Upload ACE file to CF");
   puts("volt off|<voltage>          Turn calibration voltage on/off");

   puts("");
}

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

void clear_screen()
{
#ifdef _MSC_VER

   HANDLE hConsole;
   COORD coordScreen = { 0, 0 };        /* here's where we'll home the cursor */
   BOOL bSuccess;
   DWORD cCharsWritten;
   CONSOLE_SCREEN_BUFFER_INFO csbi;     /* to get buffer info */
   DWORD dwConSize;             /* number of character cells in the current buffer */

   hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

   /* get the number of character cells in the current buffer */
   bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi);
   dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

   /* fill the entire screen with blanks */
   bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten);

   /* put the cursor at (0, 0) */
   bSuccess = SetConsoleCursorPosition(hConsole, coordScreen);
   return;

#else
   printf("\033[2J");
#endif
}

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

int match(const char *str, const char *cmd)
{
   int i;

   if (str[0] == '\r' || str[0] == '\n')
      return 0;

   for (i = 0; i < (int) strlen(str); i++) {
      if (toupper(str[i]) != toupper(cmd[i]) && str[i] != '\r' && str[i] != '\n')
         return 0;
   }

   return 1;
}

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

class ProgressBar : public DRSCallback
{
public:
   void Progress(int prog);
};

void ProgressBar::Progress(int prog)
{
   if (prog == 0)
      printf("[--------------------------------------------------]\r");
   printf("[");
   for (int i=0 ; i<prog/2 ; i++)
      printf("=");
   printf("\r");
   fflush(stdout);
}

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

void lusb(void)
{
#ifdef HAVE_USB
   MUSB_INTERFACE *usb_interface;
   
   musb_open(&usb_interface, 0x04B4, 0x1175, 0, 1, 0, 1);
   musb_close(usb_interface);
   
#endif // HAVE_USB
}

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

void cmd_loop()
{
   int i, j, idx, i_start, i_end, nparam, calib, status, debug, cascading,
      ext_refclk;
   char str[256], dir[256], line[256], file_name[256], param[10][100], *pc;
   double freq, triggerfreq, range;
   FILE *f = NULL;
   DRS *drs;
   DRSBoard *b;
#ifdef HAVE_VME
   ACE ace;
#endif
   static char bar[] = {'\\', '|', '/', '-'};

   /* do initial scan */
   drs = new DRS();
   if (drs->GetError(str, sizeof(str)))
      printf("%s", str);

   for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
      b = drs->GetBoard(i);
#ifdef HAVE_VME
      if (b->GetTransport() != 1)
         printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", 
            b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion());
#else
      printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", 
         b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion());
#endif
   }

   if (drs->GetNumberOfBoards()) {
      i_start = 0;
      i_end = 1;
      b = drs->GetBoard(0);
   } 
   else {
      printf("No DRS Boards found\n");
      i_start = i_end = 0;
      b = NULL;
   }

   puts("");

   do {
      /* print prompt */
      if (i_start == i_end-1)
         printf("B%d> ", i_start);
      else if (i_start == 0 && i_end == 0)
         printf("> ");
      else
         printf("B%d-%d> ", i_start, i_end-1);
      memset(line, 0, sizeof(line));
      fgets(line, sizeof(line), stdin);
      /* strip \r\n */
      while (strpbrk(line,"\n\r"))
         *strpbrk(line,"\n\r") = 0;

      /* analyze line */
      nparam = 0;
      pc = line;
      while (*pc == ' ')
         pc++;

      memset(param, 0, sizeof(param));
      do {
         if (*pc == '"') {
            pc++;
            for (i = 0; *pc && *pc != '"'; i++)
               param[nparam][i] = *pc++;
            if (*pc)
               pc++;
         } else if (*pc == '\'') {
            pc++;
            for (i = 0; *pc && *pc != '\''; i++)
               param[nparam][i] = *pc++;
            if (*pc)
               pc++;
         } else if (*pc == '`') {
            pc++;
            for (i = 0; *pc && *pc != '`'; i++)
               param[nparam][i] = *pc++;
            if (*pc)
               pc++;
         } else
            for (i = 0; *pc && *pc != ' '; i++)
               param[nparam][i] = *pc++;
         param[nparam][i] = 0;
         while (*pc == ' ' || *pc == '\r' || *pc == '\n')
            pc++;
         nparam++;
      } while (*pc);

      if (param[0][0] == 0) {
      }

      /* help ---------- */
      else if ((param[0][0] == 'h' && param[0][1] == 'e') || param[0][0] == '?')
         print_help();

      /* scan ---------- */
      else if (match(param[0], "scan")) {
         j = 0;

         do {
            delete drs;
            drs = new DRS();

            for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
               b = drs->GetBoard(i);
#ifdef HAVE_VME
               if (b->GetTransport() != 1)
                  printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", 
                     b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion());
#else
               printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", 
                  b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion());
#endif
            }
            
            if (drs_kbhit())
               break;

            if (param[1][0] == 'r') {
               printf("%c\r", bar[j]);
               fflush(stdout);
               j = (j+1) % 4;
               Sleep(1000);
            }

         } while (param[1][0] == 'r');

         while (drs_kbhit())
            getch();

         if (drs->GetNumberOfBoards()) {
            i_start = 0;
            i_end = 1;
            b = drs->GetBoard(0);
         } else {
            printf("No DRS Boards found\n");
            i_start = i_end = 0;
            b = NULL;
         }
      }

      /* address board ---------- */
      else if (match(param[0], "board")) {
         if (param[1][0] == 'a') {
            i_start = 0;
            i_end = drs->GetNumberOfBoards();
            b = drs->GetBoard(0);
         } else if (param[2][0] && atoi(param[2]) > 0 && atoi(param[2]) < drs->GetNumberOfBoards()) {
            i_start = atoi(param[1]);
            i_end = atoi(param[2]) + 1;
            b = drs->GetBoard(i_start);
         } else if (atoi(param[1]) >= 0 && atoi(param[1]) < drs->GetNumberOfBoards()) {
            i_start = atoi(param[1]);
            i_end = i_start + 1;
            b = drs->GetBoard(i_start);
         } else
            printf("Board #%d does not exist\n", atoi(param[1]));
      }

      /* info ---------- */
      else if (match(param[0], "info")) {
         for (idx=i_start ; idx<i_end ; idx++) {
            b = drs->GetBoard(idx);
            printf("==============================\n");
            printf("Mezz. Board index:    %d\n", idx);
#ifdef HAVE_VME
            if (b->GetTransport() == TR_VME) {
               printf("Slot:                 %d", (b->GetSlotNumber() >> 1)+2);
               if ((b->GetSlotNumber() & 1) == 0)
                  printf(" upper\n");
               else
                  printf(" lower\n");
            }
#endif
            printf("DRS type:             DRS%d\n", b->GetDRSType());
            printf("Board type:           %d\n", b->GetBoardType());
            printf("Serial number:        %04d\n", b->GetBoardSerialNumber());
            printf("Firmware revision:    %d\n", b->GetFirmwareVersion());
            printf("Temperature:          %1.1lf C\n", b->GetTemperature());
            if (b->GetDRSType() == 4) {
               printf("Input range:          %1.2lgV...%1.2lgV\n", 
                      b->GetInputRange()-0.5, b->GetInputRange()+0.5);
               printf("Calibrated range:     %1.2lgV...%1.2lgV\n", b->GetCalibratedInputRange()-0.5,
                  b->GetCalibratedInputRange()+0.5);
               printf("Calibrated frequency: %1.3lf GHz\n", b->GetCalibratedFrequency());

               if (b->GetTransport() == TR_VME) {
                  printf("Multi Buffer WP:      %d\n", b->GetMultiBufferWP());
                  printf("Multi Buffer RP:      %d\n", b->GetMultiBufferRP());
               }
            }
            
            printf("Status reg.:          %08X\n", b->GetStatusReg());
            if (b->GetStatusReg() & BIT_RUNNING)
               puts("  Domino wave running");
            if (b->GetDRSType() == 4) {
               if (b->GetBoardType() == 5) {
                  if (b->GetStatusReg() & BIT_PLL_LOCKED0)
                     puts("  PLL locked");
               } else if (b->GetBoardType() == 6) {
                  i = 0;
                  if (b->GetStatusReg() & BIT_PLL_LOCKED0) i++;
                  if (b->GetStatusReg() & BIT_PLL_LOCKED1) i++;
                  if (b->GetStatusReg() & BIT_PLL_LOCKED2) i++;
                  if (b->GetStatusReg() & BIT_PLL_LOCKED3) i++;
                  if (i == 4)
                     puts("  All PLLs locked");
                  else if (i == 0)
                     puts("  No PLL locked");
                  else
                     printf("  %d PLLs locked\n", i);
                  if (b->GetStatusReg() & BIT_LMK_LOCKED)
                     puts("  LMK PLL locked");
               }
            } else {
               if (b->GetStatusReg() & BIT_NEW_FREQ1)
                  puts("  New Freq1 ready");
               if (b->GetStatusReg() & BIT_NEW_FREQ2)
                  puts("  New Freq2 ready");
            }
            
            printf("Control reg.:         %08X\n", b->GetCtrlReg());
            if (b->GetCtrlReg() & BIT_MULTI_BUFFER)
               puts("  Multi-buffering enabled");
            if (b->GetDRSType() == 4) {
               if (b->GetConfigReg() & BIT_CONFIG_DMODE)
                  puts("  DMODE circular");
               else
                  puts("  DMODE single shot");
            } else {
               if (b->GetCtrlReg() & BIT_DMODE)
                  puts("  DMODE circular");
               else
                  puts("  DMODE single shot");
            }
            if (b->GetCtrlReg() & BIT_LED)
               puts("  LED");
            if (b->GetCtrlReg() & BIT_TCAL_EN)
               puts("  TCAL enabled");
            if (b->GetDRSType() == 4) {
               if (b->GetCtrlReg() & BIT_TRANSP_MODE)
                  puts("  TRANSP_MODE enabled");
            } else {
               if (b->GetCtrlReg() & BIT_FREQ_AUTO_ADJ)
                  puts("  FREQ_AUTO_ADJ enabled");
            }
            if (b->GetCtrlReg() & BIT_ENABLE_TRIGGER1)
               puts("  Hardware trigger enabled");
            if (b->GetDRSType() == 4) {
               if (b->GetCtrlReg() & BIT_READOUT_MODE)
                  puts("  Readout from stop");
               if (b->GetCtrlReg() & BIT_ENABLE_TRIGGER2)
                  puts("  Internal trigger enabled");
            } else {
               if (b->GetCtrlReg() & BIT_LONG_START_PULSE)
                  puts("  LONG_START_PULSE");
            }
            if (b->GetCtrlReg() & BIT_DELAYED_START)
               puts("  DELAYED_START");
            if (b->GetCtrlReg() & BIT_ACAL_EN)
               puts("  ACAL enabled");
            if (b->GetDRSType() < 4)
               if (b->GetCtrlReg() & BIT_TRIGGER_DELAYED)
                  puts("  DELAYED_TRIGGER selected");
            if (b->GetBoardType() != 5)
               printf("Trigger bus:          %08X\n", b->GetTriggerBus());
            if (b->GetDRSType() == 4) {
               if (b->GetRefclk() == 1) {
                  if (b->IsPLLLocked() && b->IsLMKLocked()) {
                     b->ReadFrequency(0, &freq);
                     printf("Frequency:            %1.3lf GHz\n", freq);
                  } else {
                     if (!b->IsPLLLocked())
                        printf("Frequency:            PLL not locked\n");
                     else
                        printf("Frequency:            LMK chip not locked\n");
                  }
               } else {
                  if (b->IsPLLLocked()) {
                     b->ReadFrequency(0, &freq);
                     printf("Frequency:            %1.3lf GHz\n", freq);
                  } else {
                     printf("Frequency:            PLL not locked\n");
                  }
               }
            } else {
               if (b->IsBusy()) {
                  b->ReadFrequency(0, &freq);
                  printf("Frequency0:           %1.4lf GHz\n", freq);
                  b->ReadFrequency(1, &freq);
                  printf("Frequency1:           %1.4lf GHz\n", freq);
               } else
                  puts("Domino wave stopped");
            }
         }
      }

      /* init ---------- */
      else if (match(param[0], "init")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->Init();
         }
      }

      /* set led ---------- */
      else if (match(param[0], "led")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (atoi(param[1]))
               b->SetLED(1);
            else
               b->SetLED(0);
         }
      }

      /* set multi buffer mode ---------- */
      else if (match(param[0], "multi")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (atoi(param[1]))
               b->SetMultiBuffer(1);
            else
               b->SetMultiBuffer(0);
         }
      }

      /* lock status ---------- */
      else if (match(param[0], "lock")) {
         int slot, found, restart;

         restart = atoi(param[1]);

         // select external reference clock
         for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
            b = drs->GetBoard(i);
            b->SetRefclk(1);
            b->SetFrequency(b->GetNominalFrequency(), true);
         }

         // loop until keyboard hit
         do {
            clear_screen();
            printf("                1 1 1 1 1 1 1 1 1 1 2 2\n");
            printf("2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n\n");

            // upper slots
            for (slot = 2 ; slot<22 ; slot++) {
               found = 0;
               for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
                  b = drs->GetBoard(i);
                  if ((b->GetSlotNumber() & 1) == 0 && (b->GetSlotNumber() >> 1)+2 == slot) {
                     found = 1;
                     if (b->IsLMKLocked())
                        printf("O ");
                     else
                        printf("- ");
                  }
               }
               if (!found)
                  printf("  ");
            }
            printf("\n");

            // lower slots
            for (slot = 2 ; slot<22 ; slot++) {
               found = 0;
               for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
                  b = drs->GetBoard(i);
                  if ((b->GetSlotNumber() & 1) == 1 && (b->GetSlotNumber() >> 1)+2 == slot) {
                     found = 1;
                     if (b->IsLMKLocked())
                        printf("O ");
                     else
                        printf("- ");
                  }
               }
               if (!found)
                  printf("  ");
            }
            printf("\n");

            if (restart) {
               for (i=0 ; i<drs->GetNumberOfBoards() ; i++) {
                  b = drs->GetBoard(i);
                  b->SetFrequency(b->GetNominalFrequency(), true);
               }
            }

            Sleep(300);

         } while (!drs_kbhit());
         puts("");
         while (drs_kbhit())
            getch();
      }

      /* start domino wave ---------- */
      else if (match(param[0], "start")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->StartDomino();
            b->ReadFrequency(0, &freq);
            for (j=0 ; j<10 ; j++)
               if (b->GetDRSType() != 4 || b->IsPLLLocked())
                  break;
            if (j == 10)
               printf("Domino wave started but PLL did not lock!\n");
            else
               printf("Domino wave started at %1.3lf GHz\n", freq);
         }
      }

      /* issue soft trigger ---------- */
      else if (match(param[0], "stop")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->SoftTrigger();
         }
      }

      /* set serial ---------- */
      else if (match(param[0], "serial")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Serial number: ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            if (!b->SetBoardSerialNumber(atoi(str)))
               printf("Board EEPROM is write protected\n");
            else
               printf("Serial number successfully changed\n");
         }
      }

      /* eeprom test ---------- */
      else if (match(param[0], "et")) {
         unsigned short buf[16384];
         unsigned short rbuf[16384];
         int n_error;

         do {
            for (i=0 ; i<16384 ; i++)
               buf[i] = rand();
            b->WriteEEPROM(1, buf, sizeof(buf));
            memset(rbuf, 0, sizeof(rbuf));
            b->Write(T_RAM, 0, rbuf, sizeof(rbuf));
            b->ReadEEPROM(1, rbuf, sizeof(rbuf));
            for (i=n_error=0 ; i<16384 ; i++)
               if (buf[i] != rbuf[i]) {
                  printf("%04X %04X - %04X\n", i, buf[i], rbuf[i]);
                  n_error++;
               }

            printf("32 kb written, %d errors\n", n_error);
         } while (!drs_kbhit());

         while (drs_kbhit())
            getch();
      }

      /* set frequency ---------- */
      else if (match(param[0], "freq")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Frequency: ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            b->SetDebug(1);

            if (param[2][0] && atoi(param[2]))
               b->RegulateFrequency(atof(str));
            else
               b->SetFrequency(atof(str), true);
         }
      }

      /* set calibration voltage ---------- */
      else if (match(param[0], "volt")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Voltage or \"off\": ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            if (str[0] == 'o') {
               b->EnableAcal(0, 0);
               puts("Calibration voltage turned off");
            } else {
               b->EnableAcal(1, atof(str));
               printf("Voltage set to %1.3lf Volt\n", atof(str));
            }
         }
      }

      /* set channel configuration ---------- */
      else if (match(param[0], "chn")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Number of channels (8,4,2,1): ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            if (b->SetChannelConfig(0, 8, atoi(str)))
               printf("DRS4 configured for %d channels\n", atoi(str));
         }
      }

      /* set trigger level ---------- */
      else if (match(param[0], "tlevel")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Voltage: ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            b->SetTriggerLevel(atof(str));
            printf("Trigger level set to %1.3lf Volt\n", atof(str));
         }
      }

      /* trigger on/off ---------- */
      else if (match(param[0], "trig")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->EnableTrigger(atoi(param[1]), 0);
            if (atoi(param[1]) == 1) {
               puts("Hardware fast trigger is on");
            } else if (atoi(param[1]) == 2) {
               puts("Hardware slow trigger is on");
            } else {
               puts("Hardware trigger is off");
            }
         }
      }

      /* timing calibration signal on/off ---------- */
      else if (match(param[0], "tcs")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->EnableTcal(atoi(param[1]), 0, 0);
            b->SelectClockSource(0);
            if (atoi(param[1]))
               puts("Timing calibration signal is on");
            else
               puts("Timing calibration signal is off");
         }
      }

      /* timing calibration signal on/off ---------- */
      else if (match(param[0], "refclk")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->SetRefclk(atoi(param[1]));
            // re-set frequency since LMK configuration needs to be changed
            b->SetFrequency(b->GetNominalFrequency(), true);
            if (atoi(param[1]))
               puts("Refclock set to external through P2");
            else
               puts("Refclock set to internal (FPGA)");
         }
      }

      /* domino mode 0/1 ---------- */
      else if (match(param[0], "dmode")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (atoi(param[1]) == 1) {
               b->SetDominoMode(1);
               puts("Domino mode switched to cyclic");
            } else {
               b->SetDominoMode(0);
               puts("Domino mode switched to single shot");
            }
         }
      }

      /* active mode 0/1 ---------- */
      else if (match(param[0], "active")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (atoi(param[1]) == 1) {
               b->SetDominoActive(1);
               puts("Domino wave active during readout");
            } else {
               b->SetDominoMode(0);
               puts("Domino wave stopped during readout");
            }
         }
      }

      /* delayed start on/off ---------- */
      else if (match(param[0], "del")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (b->GetDRSType() == 4)
               puts("Delayed start not possible for DRS4");
            else {
               if (atoi(param[1]) == 1) {
                  b->SetDelayedStart(1);
                  puts("Delayed start is on");
               } else {
                  b->SetDelayedStart(0);
                  puts("Delayed start is off");
               }
            }
         }
      }

      /* transparent mode on/off ---------- */
      else if (match(param[0], "trans")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (b->GetDRSType() != 4)
               puts("Transparen mode only possible for DRS4");
            else {
               if (atoi(param[1]) == 1) {
                  b->SetTranspMode(1);
                  puts("Transparent mode is on");
               } else {
                  b->SetTranspMode(0);
                  puts("Transparent mode is off");
               }
            }
         }
      }

      /* standby mode on/off ---------- */
      else if (match(param[0], "standby")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (b->GetDRSType() != 4)
               puts("Standby mode only possible for DRS4");
            else {
               if (atoi(param[1]) == 1) {
                  b->SetStandbyMode(1);
                  puts("Standby mode is on");
               } else {
                  b->SetStandbyMode(0);
                  puts("Standby mode is off");
               }
            }
         }
      }

      /* offset ---------- */
      else if (match(param[0], "offset")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->SetVoltageOffset(atof(param[1]), atof(param[2]));
         }
      }

      /* phase ---------- */
      else if (match(param[0], "phase")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            b->SetADCClkPhase(atoi(param[1]), atoi(param[2]) > 0);
         }
      }

      /* directory ---------- */
      else if (match(param[0], "dir")) {

#ifdef HAVE_VME
#ifdef CF_VIA_USB
         {
            if (param[2][0])
               i = atoi(param[2]);
            else
               i = 1;
            printf("Physical drive %d:\n", i);

            if (ace_init(NULL, i, &ace) != ACE_SUCCESS) {
               printf("Cannot access ACE on physical drive %d\n", i);
            } else {
#else
         for (i=i_start ; i<i_end ; i++) {

            /* do only once per VME board */
            if (i_end - i_start > 1 && (i % 2) == 1)
               continue;

            b = drs->GetBoard(i);

            printf("VME slot %2d:   ", (b->GetSlotNumber() >> 1) + 2);

            if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) {
               printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2);
            } else {
#endif
            ace_dir(&ace);
            }
         }
#else
         printf("No VME support compiled into drscl\n");
#endif // HAVE_VME
      }

      /* upload ---------- */
      else if (match(param[0], "upload")) {

#ifdef HAVE_VME
#ifdef CF_VIA_USB
         {
            if (param[2][0])
               i = atoi(param[2]);
            else
               i = 1;
            printf("Physical drive %d:\n", i);

            if (ace_init(NULL, i, &ace) != ACE_SUCCESS) {
               printf("Cannot access ACE on physical drive %d\n", i);
            } else {
#else

            /* use SVN file as default */
            if (param[1][0] == 0) {
#ifdef _MSC_VER
               if (b->GetDRSType() == 4)
                  strcpy(str, "c:\\meg\\online\\VPC\\drs4\\2vp30\\cflash\\drs4\\rev0\\rev0.ace");
               else if (b->GetDRSType() == 3)
                  strcpy(str, "c:\\meg\\online\\VPC\\drs3\\2vp30\\cflash\\drs3\\rev0\\rev0.ace");
               else
                  strcpy(str, "c:\\meg\\online\\VPC\\drs2\\2vp30\\cflash\\drs2\\rev0\\rev0.ace");
#else
               if (b->GetDRSType() == 4)
                  strcpy(str, "/home/meg/meg/online/VPC/drs4/2vp30/cflash/drs4/rev0/rev0.ace");
               else if (b->GetDRSType() == 3)
                  strcpy(str, "/home/meg/meg/online/VPC/drs3/2vp30/cflash/drs3/rev0/rev0.ace");
               else
                  strcpy(str, "/home/meg/meg/online/VPC/drs2/2vp30/cflash/drs2/rev0/rev0.ace");
#endif
               printf("Enter filename or hit return for \n%s\n", str);
               fgets(line, sizeof(line), stdin);
               if (line[0] == '\r' || line[0] == '\n')
                  strcpy(file_name, str);
               else
                  strcpy(file_name, line);
               strcpy(param[1], str);
            } else
               strcpy(file_name, param[1]);

         for (i=i_start ; i<i_end ; i++) {

            /* do only once per VME board */
            if (i_end - i_start > 1 && (i % 2) == 1)
               continue;

            b = drs->GetBoard(i);

            if (b->GetTransport() == TR_USB) {
               printf("Cannot upload to USB board.\n");
            } else {
               printf("VME slot %d:\n", (b->GetSlotNumber() >> 1)+2);
               if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) {
                  printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2);
               } else {
#endif
                  status = ace_upload(&ace, file_name);
               }
            }
         }
         printf("\nPlease issue a power cycle to activate new firmware\n");
#else
         printf("No VME support compiled into drscl\n");
#endif // HAVE_VME
      }

      /* download ---------- */
      else if (match(param[0], "download")) {

#ifdef HAVE_VME
         b = drs->GetBoard(i_start);

         if (b->GetTransport() == TR_USB) {
            printf("Cannot upload to USB board.\n");
         } else {
            printf("VME slot %d:\n", (b->GetSlotNumber() >> 1)+2);
            if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) {
               printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2);
            } else {
               strcpy(str, "rev0.ace");
               if (param[1][0] == 0) {
                  printf("Enter filename or hit return for \n%s\n", str);
                  fgets(line, sizeof(line), stdin);
                  if (line[0] == '\r' || line[0] == '\n')
                     strcpy(file_name, str);
                  else
                     strcpy(file_name, line);
                  strcpy(param[1], str);
               } else
                  strcpy(file_name, param[1]);

               if (strchr(file_name, '\r'))
                  *strchr(file_name, '\r') = 0;
               if (strchr(file_name, '\n'))
                  *strchr(file_name, '\n') = 0;

               status = ace_download(&ace, file_name);
               }
         }
#else
         printf("No VME support compiled into drscl\n");
#endif // HAVE_VME
      }

      /* calibration ---------- */
      else if (match(param[0], "calib")) {
         debug = strcmp(param[1], "debug") == 0 || strcmp(param[2], "debug") == 0 || strcmp(param[3], "debug") == 0;
         if (param[1][0]) {
            strlcpy(dir, param[1], sizeof(str));
         } else
            getcwd(dir, sizeof(dir));

         while (dir[strlen(dir)-1] == '\n' || dir[strlen(dir)-1] == '\r')
           dir[strlen(dir)-1] = 0;

         b = drs->GetBoard(i_start);

         printf("\n           Enter calibration frequency [GHz]: ");
         fgets(line, sizeof(line), stdin);
         freq = atof(line);

         if (b->GetDRSType() == 2) {
            printf("   Enter the expected trigger frequency [Hz]: ");
            fgets(line, sizeof(line), stdin);
            triggerfreq = atof(line);
         } else
            triggerfreq = 0;

         ext_refclk = 0;
         if (b->GetBoardType() == 6) {
            printf("Use [e]xternal or [i]nternal reference clock: ");
            fgets(line, sizeof(line), stdin);
            ext_refclk = line[0] == 'e';
         }

         if (b->GetDRSType() == 4) {
            printf("                             Enter range [V]: ");
            fgets(line, sizeof(line), stdin);
            range = atof(line);

            printf("        Enter mode [1]024 or [2]048 bin mode: ");
            fgets(line, sizeof(line), stdin);
            cascading = atoi(line);
         } else {
            range = 0;
            cascading = 0;
         }

         if (b->GetDRSType() == 4) {
            printf("\nPlease make sure that no input signal are present then hit any key\r");
            fflush(stdout);
            while (!drs_kbhit());
            printf("                                                                  \r");
            while (drs_kbhit())
               getchar();
         }

         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (b->GetTransport() == TR_VME)
               printf("Creating Calibration of Board in VME slot %2d %s, serial #%04d\n",  
                       (b->GetSlotNumber() >> 1)+2, ((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower", 
                        b->GetBoardSerialNumber());
            else
               printf("Creating Calibration of Board on USB, serial #%04d\n",  
                        b->GetBoardSerialNumber());
            if (b->GetDRSType() == 4) {
               ProgressBar p;
               if (b->GetTransport() == TR_VME) {
                  if (cascading == 2)
                     b->SetChannelConfig(7, 8, 4);  // 7 means read all 9 channels per chip
                  else
                     b->SetChannelConfig(7, 8, 8);
               } else {
                  if (cascading == 2)
                     b->SetChannelConfig(0, 8, 4);
                  else
                     b->SetChannelConfig(0, 8, 8);
               }

               b->SetRefclk(ext_refclk);
               b->SetFrequency(freq, true);
               b->SetInputRange(range);
               b->CalibrateVolt(&p);
            } else {
               b->SetDebug(debug);
               b->Init();
               b->SetFrequency(freq, true);
               b->SoftTrigger();

               if (b->GetDRSType() == 3)
                  b->GetResponseCalibration()->SetCalibrationParameters(1,11,0,20,0,0,0,0,0);
               else
                  b->GetResponseCalibration()->SetCalibrationParameters(1,36,110,20,19,40,15,triggerfreq,0);
               if (!strcmp(dir,"lab"))
                  b->SetCalibrationDirectory("C:/experiment/calibrations");
               else if (!strcmp(dir,"area"))
                  b->SetCalibrationDirectory("/home/meg/meg/online/calibrations");
               else
                  b->SetCalibrationDirectory(dir);
               for (j=0;j<2;j++) {
                  b->GetResponseCalibration()->ResetCalibration();
                  while (!b->GetResponseCalibration()->RecordCalibrationPoints(j)) {}
                  while (!b->GetResponseCalibration()->FitCalibrationPoints(j)) {}
                  while (!b->GetResponseCalibration()->OffsetCalibration(j)) {}
                  if (!b->GetResponseCalibration()->WriteCalibration(j))
                     break;
               }
            }
         }
      }
        
      /* timing calibration ---------- */
      else if (match(param[0], "tcalib")) {
         
         freq = 0;
         if (param[1][0])
            freq = atof(param[1]);

         if (freq == 0) {
            printf("Enter calibration frequency [GHz]: ");
            fgets(line, sizeof(line), stdin);
            freq = atof(line);
         }
         
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (b->GetDRSType() < 4)
               printf("Timing calibration not possivle for DRS2 or DRS3\n");
            else if (b->GetFirmwareVersion() < 13279)
               printf("Firmware revision 13279 or later required for timing calibration\n");
            else if (b->GetDRSType() == 4) {
               printf("Creating Timing Calibration of Board #%d\n", b->GetBoardSerialNumber());
               ProgressBar p;
               b->SetFrequency(freq, true);
               status = b->CalibrateTiming(&p);
               if (!status)
                  printf("Error performing timing calibration, please check waveforms\n");
               printf("\n");
            }
         }
      }

      /* tcout ---------- */
      else if (match(param[0], "tcout")) {
         float time[1024];
         int chip;
         int k;
         int idx = 0;
         int first_board = i_start;
         int last_board = i_end;

         file_name[0] = 0;
         strcpy(file_name, param[1]);
         if (file_name[0]) {
            f = fopen(file_name, "wt");
            if (f == NULL) {
               printf("Cannot open file \"%s\"\n", file_name);
            } else {
               first_board = 0;
               last_board = drs->GetNumberOfBoards();
            }
            idx += atoi(param[2]);
         } else
            f = NULL;

         if (f) {
            fprintf(f, "-- Replace %%%% with correct id\n");
         }
         for (i=first_board ; i<last_board ; i++) {
            b = drs->GetBoard(i);
            if (b->GetDRSType() >= 4) {
               for (chip = 0; chip < b->GetNumberOfChips(); chip++) {
                  b->GetTime(chip, 0, b->GetTriggerCell(0), time, true, false);
                  if (f) {
                     fprintf(f, "INSERT INTO MEGDRSTimeCalibration VALUES(%%%%,%d,%d", idx,
                            static_cast<int>(b->GetNominalFrequency() * 10 + 0.5) * 100);
                     for (j=0 ; j<1024 ; j++)
                        fprintf(f, ",%g", time[j] * 1e-9);
                     fprintf(f, ",%d,%d", b->GetBoardSerialNumber(), chip);
                     fprintf(f, ",%g);\n", 1 / (b->GetNominalFrequency() * 1e9) * 1024);
                     idx++;
                  } else {
                     printf("Board %d\n", b->GetBoardSerialNumber());
                     for (j=0 ; j<128 ; j++) {
                        printf("%4d: ", j*8);
                        for (k=0 ; k<7 ; k++)
                           printf("%6.1lf ", time[j*8+k]);
                        printf("%6.1lf\n", time[j*8+k]);
                     }
                     printf("n");
                  }
               }
            } else {
               // DRS2 or DRS3
               idx += 2;
            }
         }
         if (f) {
            fclose(f);
            printf("Data successfully written to \"%s\"\n", file_name);
         }
      }

      /* read */   
      else if (match(param[0], "read")) {
         float waveform[2048];
         short swaveform[2048];
         calib = 0;

         file_name[0] = 0;
         if (param[1][0]) {
            idx = atoi(param[1]);
            calib = atoi(param[2]);
            if (strlen(param[2]) > 2)
               strcpy(file_name, param[2]);
            else
               strcpy(file_name, param[3]);
         } else {
            printf("Enter channel number (0..19): ");
            fgets(line, sizeof(line), stdin);
            idx = atoi(line);
         }

         if (idx<0 || idx>19)
            printf("Channel number must be between 0 and 19\n");
         else {
            b = drs->GetBoard(i_start);
            if (!b->IsEventAvailable())
               printf("Error: Domino wave is running, please issue a \"stop\" first\n");
            else {
               if (calib == 1) {
                  if (b->GetDRSType() == 4) {
                     if (!b->IsVoltageCalibrationValid()) {
                        printf("Calibration not valid for board #%d\n", b->GetBoardSerialNumber());
                        calib = 0;
                     }

                  } else {
#ifdef _MSC_VER
                     b->SetCalibrationDirectory("C:/experiment/calibrations");
#else
                     b->SetCalibrationDirectory("/home/meg/meg/online/calibrations");
#endif
                     if (!b->GetResponseCalibration()->IsRead(0))
                        if (!b->GetResponseCalibration()->ReadCalibration(0))
                           calib = 0;
                     if (!b->GetResponseCalibration()->IsRead(1))
                        if (!b->GetResponseCalibration()->ReadCalibration(1))
                           calib = 0;
                  }
               }

               status = b->TransferWaves(idx, idx);
               if (file_name[0]) {
                  f = fopen(file_name, "wt");
                  if (f == NULL)
                     printf("Cannot open file \"%s\"\n", file_name);
               } else
                  f = NULL;

               if (calib) {
                  status = b->GetWave(idx/b->GetNumberOfChannels(), idx%b->GetNumberOfChannels(), waveform, 
                                      true, b->GetTriggerCell(idx/b->GetNumberOfChannels()), b->GetStopWSR(idx/b->GetNumberOfChannels()));
                  if (status == 0) {
                     if (f)
                        for (i=0 ; i<b->GetChannelDepth() ; i++)
                           fprintf(f, "%6.1lf\n", waveform[i]);
                     else {
                        for (i=0 ; i<b->GetChannelDepth()/8 ; i++) {
                           printf("%4d: ", i*8);
                           for (j=0 ; j<7 ; j++)
                              printf("%6.1lf ", waveform[i*8+j]);
                           printf("%6.1lf\n", waveform[i*8+j]);
                        }
                     }
                  }
               } else {
                  status = b->GetWave(idx/b->GetNumberOfChannels(), idx%b->GetNumberOfChannels(), swaveform, 0, 0);
                  if (status == 0) {
                     if (f)
                        for (i=0 ; i<b->GetChannelDepth() ; i++)
                           fprintf(f, "%4d\n", swaveform[i]);
                     else {
                        for (i=0 ; i<b->GetChannelDepth()/16 ; i++) {
                           for (j=0 ; j<15 ; j++)
                              printf("%4d ", swaveform[i*16+j] >> 4);
                           printf("%4d\n", swaveform[i*16+j] >> 4);
                        }
                     }
                  }
               }
            }
         }

         if (f) {
            fclose(f);
            printf("Data successfully written to \"%s\"\n", file_name);
         }
      }

      /* register test ---------- */
      else if (match(param[0], "reg")) {
         b->RegisterTest();
      }

      /* RAM test */
      else if (match(param[0], "ram")) {
         if (param[1][0] == 0)
            b->RAMTest(3);
         else
            b->RAMTest(atoi(param[1]));
      }
      
      /* Change input range */
      else if (match(param[0], "range")) {
         for (i=i_start ; i<i_end ; i++) {
            b = drs->GetBoard(i);
            if (param[1][0] == 0) {
               printf("Input range: ");
               fgets(str, sizeof(str), stdin);
            } else
               strlcpy(str, param[1], sizeof(str));

            b->SetInputRange(atof(str));
            printf("Range set to %1.2lg V ... %1.2lg V\n", atof(str)-0.5, atof(str)+0.5);
         }
      }

      /* Chip Test */
      else if (match(param[0], "ct")) {
         b->SetStandbyMode(0);
         Sleep(500);
         if (drs->GetNumberOfBoards() == 0)
            puts("No DRS board found");
         else {
            puts("Press 'q' to quit, any other key to repeat test.\n");
            do {
               b->ChipTest(param[1][0] > 0);
               b->SetStandbyMode(1);
               for (i=0 ; i<8 ; i++)
                  b->SetDAC(i, 0);
               i = getch();
               b->SetStandbyMode(0);
               Sleep(500);
            } while (i != 'q');
         }
      }
      
      /* calib0 for speed vs. temperature calibration */
      else if (match(param[0], "c0")) {
         
         double volt, freq;
         
         b->Init();
         b->SetFrequency(5, true);
         b->EnableAcal(0, 0);
         b->SetDominoMode(1);

         for (volt=2.5 ; volt > 0 ; volt -= 0.05) {
            printf("%4.1lf - %5.3lf ", b->GetTemperature(), volt);
            b->SetDAC(1, volt);
            b->SetDAC(2, volt);
            Sleep(100);
            b->ReadFrequency(0, &freq);

            printf("%5.3lf\n", freq);

            if (drs_kbhit())
               break;
         }

         while (drs_kbhit())
            getch();

         b->Init(); // reset voltage offset
      }

      /* calib1 */
      else if (match(param[0], "c1")) {
         
         short swaveform[1024];
         double volt;
         double av[1024];
         int k;
         
         b->Init();
         b->SetFrequency(5, true);
         b->SetDominoMode(1);
         b->SetDominoActive(1);
         b->SetReadoutMode(1);

         for (volt=-0.5 ; volt <= 0.5001 ; volt += 0.02) {
            printf("%4.1lf - %6.0lf ", b->GetTemperature(), 1000*volt);
            b->EnableAcal(1, volt);
            b->StartDomino();
            Sleep(100);
            
            memset(av, 0, sizeof(av));

            for (j=0 ; j<100 ; j++) {
               for (i=0 ; i<10 ; i++)
                  b->IsBusy();
               b->SoftTrigger();
               while (b->IsBusy());
               b->StartDomino();
               b->TransferWaves(b->GetNumberOfChannels()*b->GetNumberOfChips());
               i = b->GetTriggerCell(0);
               b->GetWave(0, 0, swaveform, false, i, 1);

               for (k=0 ; k<1024 ; k++)
                  av[k] += swaveform[k];

               if (drs_kbhit())
                  break;
            }

            for (k=0 ; k<1024 ; k++)
               av[k] /= j;

            for (k=0 ; k<5 ; k++)
               printf("%10.2lf ", 1000*(av[k]/65536-0.5));
            printf("\n");

            if (drs_kbhit())
               break;
         }
         // keep chip "warm"
         b->StartDomino();
      }

      /* test0 */
      else if (match(param[0], "t0")) {
         b->Init();
         b->SetDominoMode(1);
         b->SetDominoActive(1);
         b->SetReadoutMode(1);
         b->SetFrequency(0.8, true);
         b->EnableTrigger(1, 0);
         b->SetTriggerLevel(1);
         b->SetChannelConfig(0, 8, 4);

         do {
            b->StartDomino();
            while (b->IsBusy())
               if (drs_kbhit())
                  break;

            b->TransferWaves();

            if (b->GetBoardType() == 5) {
               printf("%04d(0x%03X) - %3d\n", b->GetTriggerCell(0), b->GetTriggerCell(0), 
                  b->GetStopWSR(0));
            } else {
               printf("%04d %04d %04d %04d - %3d %3d %3d\n", 
                  b->GetTriggerCell(0),
                  b->GetTriggerCell(1),
                  b->GetTriggerCell(2),
                  b->GetTriggerCell(3),
                  b->GetTriggerCell(1)-b->GetTriggerCell(0),
                  b->GetTriggerCell(2)-b->GetTriggerCell(0),
                  b->GetTriggerCell(3)-b->GetTriggerCell(0));
            }
            Sleep(300);
         } while (!drs_kbhit());

         while (drs_kbhit())
            getch();
      }

      /* test1 simple start/stop loop */
      else if (match(param[0], "t1")) {
         time_t t1, t2;
         
         b->SetDebug(1);
         b->Init();
         b->SetFrequency(5, true);
         b->SetDominoMode(1);
         b->SetReadoutMode(0);
         b->SetTranspMode(0);
         b->SetDominoActive(1);
         b->EnableAcal(1, 0.5);
         b->EnableTcal(1);
         time(&t1);
         do {
            time(&t2);
         } while (t1 == t2);
         i=0;
         t1 = t2;
         do {
            b->StartDomino();
            b->SoftTrigger();
            b->TransferWaves();
            i++;
            time(&t2);
            if (t2 > t1) {
               printf("%d events/sec\n", i);
               i = 0;
               t1 = t2;
            }
         } while (!drs_kbhit());

         while (drs_kbhit())
            getch();
      }

      /* test2 readout from stop position */
      else if (match(param[0], "t2")) {
         short sw[1024];
         double volt = 0.5;

         b->Init();
         b->SetNumberOfChannels(10);
         b->SetChannelConfig(0, 9, 12);
         b->SetFrequency(2, true);
         b->EnableTcal(1);
         b->SetReadoutMode(0);
         b->SetDominoActive(0);
         b->SetDominoMode(1);
         b->SetCalibTiming(0, 0);
         b->StartDomino();
         b->EnableAcal(1, 0.5);
         if (!b->GetResponseCalibration()->IsRead(0))
            if (!b->GetResponseCalibration()->ReadCalibration(0))
               printf("cannot read calibration\n");

         do {
            //volt += 0.25;
            if (volt > 1)
               volt = 0;
            b->SoftTrigger();
            while (b->IsBusy());
            b->StartDomino();
            b->EnableAcal(1, volt);
            b->TransferWaves();

            b->GetWave(0, 1, sw, 0, 0);
            printf("%d ", sw[100]);
            b->GetWave(0, 1, sw, 1, 0);
            printf("%1.4lf\n", sw[100]/4096.0);
         } while (!drs_kbhit());
         while (drs_kbhit()) getch();
      }

      /* DAC Loop */
      else if (match(param[0], "t3")) {
         double volt;
         do {
            for (volt=2.5 ; volt > 0 ; volt -= 0.05) {
               
               printf("%4.1lf - %5.3lf\n", b->GetTemperature(), volt);
               b->SetDAC(0, volt);
               b->SetDAC(1, 2.5-volt);
               Sleep(100);
               if (drs_kbhit())
                  break;
            }
         } while (!drs_kbhit());

         while (drs_kbhit())
            getch();
      }

      /* noise measurement */
      else if (match(param[0], "t4")) {
         int i, n;
         short sw[1024];
         double ofs[1024], sx, sxx, avg, stdev, enob;

         b->Init();
         b->SetFrequency(2, true);
         b->EnableTcal(0);
         b->SetDominoMode(1);
         b->StartDomino();
         b->EnableAcal(1, 0.5);
         Sleep(100);
         b->SoftTrigger();
         while (b->IsBusy());
         b->StartDomino();
         Sleep(100);
         memset(ofs, 0, sizeof(ofs));

         for (i=0 ; i<10 ; i++) {
            b->SoftTrigger();
            while (b->IsBusy());
            b->StartDomino();
            b->TransferWaves(1);
            b->GetWave(0, 0, sw, 0, 0);
            sx = sxx = 0;
            for (n=0 ; n<1024 ; n++) {
               ofs[n] += sw[n];
            }
         }

         for (n=0 ; n<1024 ; n++)
            ofs[n] /= i;

         for (i=0 ; i<10 ; i++) {
            b->SoftTrigger();
            while (b->IsBusy());
            b->StartDomino();
            b->TransferWaves(1);
            b->GetWave(0, 0, sw, 0, 0);

            sx = sxx = 0;
            for (n=10 ; n<1014 ; n++) {
               sx += (sw[n]-ofs[n])/4096.0;
               sxx += (sw[n]-ofs[n])/4096.0*(sw[n]-ofs[n])/4096.0;
            }

            if (i>5)
               Sleep(5000);

            avg = sx / n;
            stdev = sqrt((sxx-sx*sx/n)/(n-1));
            enob = log(1/stdev)/log(2.);
            printf("avg=%1.4lf sd=%1.4lf ENOB=%1.1lf\n", avg, stdev, enob);
         };
      }

      /* exit/quit ---------- */
      else if (match(param[0], "exit") || match(param[0], "quit"))
         break;

      else {
         if (strchr(param[0], '\r'))
            *strchr(param[0], '\r') = 0;
         if (strchr(param[0], '\n'))
            *strchr(param[0], '\n') = 0;
         printf("Unknon command \"%s\"\n", param[0]);
      }

   } while (1);

   delete drs;
}

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

int main(int argc, char *argv[])
{
   if (argc == 2 && argv[1][1] == 'l') {
      lusb();
      return 0;
   }
   
   printf("DRS command line tool, Revision %d\n", atoi(drscl_svn_revision+15));
   printf("Type 'help' for a list of available commands.\n\n");

   cmd_loop();
   return 1;
}
