-- StephanLinn - 29 Jun 2009

The 'Idiots Guide' to PVSS Control Language Extensions

First lets document Sasha's notes.

Installation steps:
1.       Install PVSS with API
2.       Install and configure visual studio
3.       In addition to PVSS environment variables, we need $API_ROOT = c:\etm\PVSS2\3.X\api
4.       Add  the IDE executable library to PATH???
5.       Copy vsvars.bat to c:\etm\PVSS2\3.X\api
 
Compilation:
 
In command promt
>cd c:\etm\PVSS2\3.X\api
>vsvars32
>checkAPIenv
>devenv
 
To Create a new CtrlExt:
 

A CLE is a compiled piece of code that can be executed by PVSS script. A example is given with helpful TODO comments in "$API_ROOT\TemplateCtrlExt\_TEMPLATE_ExternHdl.cxx:

static FunctionListRec fnList[] =
{
  // TODO add for every new function an entry
  { INTEGER_VAR, "add", "(int a, int b, int &sum)", false }
};

.......

// TODO implement your logic; here: get first and second argument
      // and convert them to IntegerVar (Variable::operator= does autmatic casting)
      IntegerVar a, b;
      a = *(param.args->getFirst()->evaluate(param.thread));
      b = *(param.args->getNext ()->evaluate(param.thread));
.....

     // calculate the sum
      integerVar.setValue(a.getValue() + b.getValue());
....

      // This shows how to provide data to an in/out parameter
      // get a pointer to the given reference variable
      Variable *sum = param.args->getNext()->getTarget(param.thread);


This is nice if you happen to be arithmetically challenged or only want to pass single integers in and out. If you are interested in passing anything more complex like strings, blobs or dynamic arrays, the documentation is scarce. That was until I found our very own Fernando Varela-Rodriguez Ph.D. thesis, which contained enough hints to get started.

Below is the HCAL DSS CLE for control of the 1-wire ADC. It merely encapsulates some routines that use the "TMEX" api from Dallas Semiconductor. It shows how to pass uchar arrays and blobs into out of PVSS and how to use dynamic arrays internally. Hopefully someone will do a better and more complete job. I don't have time now.

#include <HssExternHdl.hxx>

#include "BlobVar.hxx"
#include "CharVar.hxx"
#include "CtrlVar.hxx"
#include "TextVar.hxx"
#include "DynVar.hxx"
#include "atod.h"
#include <iostream>
#include <iomanip>
#include <string>
//============================================================================================================

static FunctionListRec fnList[] =
  {
   { INTEGER_VAR, "TestPVSS"            , "(int verbose", false },
   { INTEGER_VAR, "ReadAtoDResultsPVSS" , "(int portnum, unsigned char * SerialNum, blob &results)", false },
   { INTEGER_VAR, "FindDevicePVSS"      , "(int portnum, int devType, blob &FamilySN)", false },
   { INTEGER_VAR, "WriteAtoDPVSS"       , "(int portnum, unsigned char * SerialNum, unsigned char * ctrl )",false },
   { INTEGER_VAR, "DoAtoDConversionPVSS", "(int portnum, unsigned char * SerialNum)",false}, 
   { INTEGER_VAR, "ReleasePVSS"         , "(int portnum )",false}, 
   { INTEGER_VAR, "AcquirePVSS"         , "(char * portName)",false},
   { INTEGER_VAR, "SelectPVSS"          , "(int portnum)",false} 
  };

CTRL_EXTENSION(HssExternHdl, fnList)







//============================================================================================================

const Variable *HssExternHdl::execute(ExecuteParamRec &param)
{
  enum
  {
    // TODO add here all your function numbers in the sequence used in the FunctionListRec array
    F_TestPVSS=0,F_ReadAtoDResultsPVSS, F_FindDevicePVSS, F_WriteAtoDPVSS, F_DoAtoDConversionPVSS,F_ReleasePVSS,F_AcquirePVSS,F_SelectPVSS
  };

//============================================================================================================

  // prints to file: 0( none ) 1( debug )
  static int VERBOSE=0;
  unsigned char uadd[16],uctl[16];

  // TODO for the different return types you need corresponding static Variables
  static IntegerVar integerVar;
  static BlobVar blobVar;

  // pointers used in all
  CtrlExpr *expr;
  const Variable *numPtr;
  const Variable *devPtr;
  const Variable *intPtr;


  switch ( param.funcNum )
  {
    //============================================================================================================
   case F_TestPVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      if ( !param.args || (param.args->getNumberOfItems() != 1) ){
        integerVar.setValue(-1); return &integerVar;
      }
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

     VERBOSE = portNum.getValue();

     //if (VERBOSE > 0){
     //     std::freopen("AAAlogfile.txt","a",stderr); 
     //}
     //else {
     //     fclose(stderr);
     //}

     if (VERBOSE >0)std::cout << "\nTestPVSS: portnum "<<std::dec<<portNum.getValue()<<std::endl;

     integerVar.setValue( 0 ) ;return &integerVar;
     
    }

   //============================================================================================================
   case F_FindDevicePVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 3) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

      // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

   // get devType
     
     expr = param.args->getNext();
     devPtr = expr -> evaluate(param.thread);
     if ( ! devPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar devType;
     devType = *devPtr;


      // This shows how to provide data to an in/out parameter
      // get a pointer to the given reference variable
      Variable *sum = param.args->getNext()->getTarget(param.thread);

      if ( ! sum )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::NO_LVALUE,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }
     // get FamilySN into PVSSuchar?

   
     PVSSuchar FamilySN[16][8];

     int nFound = FindDevice(portNum.getValue(), &FamilySN[0], devType.getValue(), MAXDEVICES);

     if (VERBOSE > 0){
       std::cout << "FindDevicePVSS: portnum "<< std::dec<< portNum.getValue()<<" nFound "<<nFound <<" adapID "<<std::hex<<devType.getValue()<<std::endl;
       for ( int i = 0; i < nFound; i++){
         for ( int j=0; j < 8; j++ ){
         std::cout<< std::hex<<std::setw(2)<<std::setfill('0')<<(int)FamilySN[i][j];
         }
         std::cout<<std::endl;
       }
     }
     
      // directly assign the result to the target var
     //static BlobVar blobVar( temp, sizeof(temp), PVSS_TRUE );
     //blobVar = BlobVar( temp, sizeof(temp), PVSS_TRUE );
     blobVar = BlobVar( FamilySN[0], nFound*8 , PVSS_TRUE );
      *sum = blobVar;

     
      integerVar.setValue(nFound); return &integerVar;
    }


   //============================================================================================================
   case F_ReadAtoDResultsPVSS:
    {
      param.thread->clearLastError();

      // check number of arguments

      if ( !param.args || (param.args->getNumberOfItems() != 3) ){
        integerVar.setValue(-1); return &integerVar;
      }

      // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;
     
          // get chipID blob

     TextVar chipPtr;
      chipPtr = *(param.args->getNext()->evaluate(param.thread));
     if ( ! chipPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
    
     const char * add;
     add = new char[32];
     add = chipPtr.getValue(); // gets the string
     sscanf( add, "%2x %2x %2x %2x %2x %2x %2x %2x ", 
        &uadd[0],&uadd[1],&uadd[2],&uadd[3],&uadd[4],&uadd[5],&uadd[6],&uadd[7] );
     delete[] add;
     add = NULL;
     
     int adc[4];
     int status = ReadAtoDResults(portNum.getValue(), TRY_OVERDRIVE, uadd, &adc[0]);

     if (VERBOSE > 0){
        std::cout << "ReadAtoDPVSS : portnum "<<std::dec<<portNum.getValue()<<" status "<<status <<" chip ";
        for (int i=0;i<8;i++)std::cout<< std::hex<<std::setw(2)<<std::setfill('0')<<(int)uadd[i];
        std::cout<< std::dec<< " adc "<<adc[0]<<" "<<adc[1]<<" "<<adc[2]<<" "<<adc[3]<< std::endl;
     }

     
     
     // output dyn_int unsigned char * dum;
     
     expr = param.args->getNext();
     intPtr = expr -> getTarget(param.thread);
     if ( ! intPtr ){
        integerVar.setValue(-1); return &integerVar;
      }
    
     ((DynVar *) intPtr)->clear();
     for(int i=0;i<4;i++){
        //((DynVar *) intPtr)->append(new IntegerVar(adc[i]));
         ((DynVar *)intPtr)->append( IntegerVar(adc[i]) );
     }
  
     integerVar.setValue(0); return &integerVar;
    }

   
   //============================================================================================================
   case F_WriteAtoDPVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 3) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

   // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

      // get chipID blob

     TextVar chipPtr;
      chipPtr = *(param.args->getNext()->evaluate(param.thread));
     if ( ! chipPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
    
     const char * add;
     add = new char[32];
     add = chipPtr.getValue(); // gets the string
     sscanf( add, "%2x %2x %2x %2x %2x %2x %2x %2x ", 
        &uadd[0],&uadd[1],&uadd[2],&uadd[3],&uadd[4],&uadd[5],&uadd[6],&uadd[7] );
     delete[] add;
     add = NULL;

     
     // get ctrl blob

     TextVar ctrlPtr;
      ctrlPtr = *(param.args->getNext()->evaluate(param.thread));
     if ( ! ctrlPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
     
     const char * ctl;
     ctl = new char[32];
     ctl = ctrlPtr.getValue(); // gets the string
     sscanf( ctl, "%2x %2x %2x %2x %2x %2x %2x %2x ", 
        &uctl[0],&uctl[1],&uctl[2],&uctl[3],&uctl[4],&uctl[5],&uctl[6],&uctl[7] );
     delete[] ctl;
     ctl = NULL;
     
     int status = WriteAtoD(portNum.getValue(),TRY_OVERDRIVE, uadd, uctl, START_ADD, END_ADD);
     if (VERBOSE > 0){
        std::cout << "\nWriteAtoDPVSS: portnum "<<std::dec<<portNum.getValue()<<" status "<< status<<" chip ";
        for (int i=0;i<8;i++)std::cout<< std::hex<<std::setw(2)<<std::setfill('0')<<(int)uadd[i];
          std::cout<<" ctrl ";
        for (int i=0;i<8;i++)std::cout<< std::hex<<std::setw(2)<<std::setfill('0')<<(int)uctl[i];
        std::cout<< std::endl;
     }

     uctl[0] = 0x40;
     int vccAdd = 0x1C;

     status = WriteAtoD(portNum.getValue(),TRY_OVERDRIVE, uadd, uctl, vccAdd, vccAdd);

      // directly assign the result to the target var
     integerVar.setValue(status); return &integerVar;
    }
   //============================================================================================================
   case F_DoAtoDConversionPVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 2) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

      // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

     // get chipID blob

     TextVar chipPtr;
      chipPtr = *(param.args->getNext()->evaluate(param.thread));
     if ( ! chipPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
    
     const char * add;
     add = new char[32];
     add = chipPtr.getValue(); // gets the string
          sscanf( add, "%2x %2x %2x %2x %2x %2x %2x %2x ", 
        &uadd[0],&uadd[1],&uadd[2],&uadd[3],&uadd[4],&uadd[5],&uadd[6],&uadd[7] );
     delete[] add;
     add = NULL;

     int status = DoAtoDConversion(portNum.getValue(),TRY_OVERDRIVE, uadd);
     if (VERBOSE > 0){
        std::cout << "DoAtoDPVSS   : portnum "<<std::dec<<portNum.getValue()<<" status "<<status <<" chip ";
        for (int i=0;i<8;i++)std::cout<< std::hex<<std::setw(2)<<std::setfill('0')<<(int)uadd[i];
        std::cout<< std::endl;
     }

     
      // directly assign the result to the target var
       integerVar.setValue(status); return &integerVar;
    }


   //============================================================================================================
   case F_ReleasePVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 1) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

     // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

     int status = Release(portNum.getValue());
     if (VERBOSE > 0)std::cout << "ReleasePVSS: portnum "<<std::dec<< portNum.getValue() <<" status "<< status<< std::endl;
     
      // directly assign the result to the target var
       integerVar.setValue(status); return &integerVar;
    }

   //============================================================================================================
   case F_AcquirePVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 1) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

      // TODO implement your logic; here: get first and second argument
      // and convert them to IntegerVar (Variable::operator= does autmatic casting)
    
     TextVar portNamePtr;
      portNamePtr = *(param.args->getFirst()->evaluate(param.thread));


     char * portName = (char*)portNamePtr.getString();
     int portNum = Acquire((char*)portNamePtr.getString());
     
     if (VERBOSE > 0)std::cout << "\nAcquirePVSS: portnum "<<std::dec<< portNum <<" portName "<< portName<< std::endl;
     
      // directly assign the result to the target var
       integerVar.setValue(portNum); return &integerVar;
    }

   //============================================================================================================
   case F_SelectPVSS:
    {
      param.thread->clearLastError();

      // check number of arguments
      // TODO
      if ( !param.args || (param.args->getNumberOfItems() != 1) )
      {
        ErrClass err(ErrClass::PRIO_WARNING,
                     ErrClass::ERR_CONTROL, ErrClass::ARG_MISSING,
                     param.clientData->getLocation(), param.funcName);

        ErrHdl::error(err);
        param.thread->appendLastError(&err);

        integerVar.setValue(-1); return &integerVar;
      }

     // get portnum
     
     expr = param.args->getFirst();
     numPtr = expr -> evaluate(param.thread);
     if ( ! numPtr ){ 
      integerVar.setValue(-1); return &integerVar;
      }
      IntegerVar portNum;
     portNum = *numPtr;

     int status = Select(portNum.getValue(),TRY_OVERDRIVE);
     if (VERBOSE > 0)std::cout << "SelectPVSS: portnum "<<std::dec<< portNum.getValue() <<" status "<< status<< std::endl;
     
      // directly assign the result to the target var
       integerVar.setValue(status); return &integerVar;
    }

    //============================================================================================================
    default:
      integerVar.setValue(-1);
      return &integerVar;
  }
}


Edit | Attach | Watch | Print version | History: r2 < r1 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r2 - 2009-06-29 - StephanLinn
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMS/HCAL/DCS All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2023 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback